[PATCH] overlayfs: mask d_type high bits before whiteout check

Chunsheng Luo posted 1 patch 1 month ago
fs/overlayfs/readdir.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
[PATCH] overlayfs: mask d_type high bits before whiteout check
Posted by Chunsheng Luo 1 month ago
Commit c31f91c6af96 ("fuse: don't allow signals to interrupt getdents
copying") introduced the use of high bits in d_type as flags. However,
overlayfs was not adapted to handle this change.

In ovl_cache_entry_new(), the code checks if d_type == DT_CHR to
determine if an entry might be a whiteout. When fuse is used as the
lower layer and sets high bits in d_type, this comparison fails,
causing whiteout files to not be recognized properly and resulting in
incorrect overlayfs behavior.

Fix this by masking out the high bits with S_DT_MASK before checking.

Fixes: c31f91c6af96 ("fuse: don't allow signals to interrupt getdents copying")
Link: https://github.com/containerd/stargz-snapshotter/issues/2214
Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
---
 fs/overlayfs/readdir.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 160960bb0ad0..a2ac47458bf9 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -246,6 +246,9 @@ static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
 {
 	struct ovl_cache_entry *p;
 
+	/* Mask out high bits that may be used (e.g., fuse) */
+	d_type &= S_DT_MASK;
+
 	p = ovl_cache_entry_find(rdd->root, c_name, c_len);
 	if (p) {
 		list_move_tail(&p->l_node, &rdd->middle);
@@ -316,6 +319,9 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
 	char *cf_name = NULL;
 	int c_len = 0, ret;
 
+	/* Mask out high bits that may be used (e.g., fuse) */
+	d_type &= S_DT_MASK;
+
 	if (ofs->casefold)
 		c_len = ovl_casefold(rdd, name, namelen, &cf_name);
 
@@ -632,6 +638,9 @@ static bool ovl_fill_plain(struct dir_context *ctx, const char *name,
 	struct ovl_readdir_data *rdd =
 		container_of(ctx, struct ovl_readdir_data, ctx);
 
+	/* Mask out high bits that may be used (e.g., fuse) */
+	d_type &= S_DT_MASK;
+
 	rdd->count++;
 	p = ovl_cache_entry_new(rdd, name, namelen, NULL, 0, ino, d_type);
 	if (p == NULL) {
@@ -755,6 +764,9 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
 	struct dir_context *orig_ctx = rdt->orig_ctx;
 	bool res;
 
+	/* Mask out high bits that may be used (e.g., fuse) */
+	d_type &= S_DT_MASK;
+
 	if (rdt->parent_ino && strcmp(name, "..") == 0) {
 		ino = rdt->parent_ino;
 	} else if (rdt->cache) {
@@ -1144,6 +1156,9 @@ static bool ovl_check_d_type(struct dir_context *ctx, const char *name,
 	struct ovl_readdir_data *rdd =
 		container_of(ctx, struct ovl_readdir_data, ctx);
 
+	/* Mask out high bits that may be used (e.g., fuse) */
+	d_type &= S_DT_MASK;
+
 	/* Even if d_type is not supported, DT_DIR is returned for . and .. */
 	if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
 		return true;
-- 
2.43.0
Re: [PATCH] overlayfs: mask d_type high bits before whiteout check
Posted by Amir Goldstein 1 month ago
On Wed, Jan 7, 2026 at 4:46 AM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>
> Commit c31f91c6af96 ("fuse: don't allow signals to interrupt getdents
> copying") introduced the use of high bits in d_type as flags. However,
> overlayfs was not adapted to handle this change.
>
> In ovl_cache_entry_new(), the code checks if d_type == DT_CHR to
> determine if an entry might be a whiteout. When fuse is used as the
> lower layer and sets high bits in d_type, this comparison fails,
> causing whiteout files to not be recognized properly and resulting in
> incorrect overlayfs behavior.
>
> Fix this by masking out the high bits with S_DT_MASK before checking.
>
> Fixes: c31f91c6af96 ("fuse: don't allow signals to interrupt getdents copying")
> Link: https://github.com/containerd/stargz-snapshotter/issues/2214
> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>

Hi Chunsheng,

Thanks for the report and the suggested fix.

This time overlayfs was surprised by unexpected d_type flags and next
time it could be another user.

I prefer to fix this in a more profound way -
Instead of making overlafys aware of d_type flags, require the users that
use the d_type flags to opt-in for them.

Please test/review the attached patch.

Thanks,
Amir.


> ---
>  fs/overlayfs/readdir.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
>
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index 160960bb0ad0..a2ac47458bf9 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -246,6 +246,9 @@ static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
>  {
>         struct ovl_cache_entry *p;
>
> +       /* Mask out high bits that may be used (e.g., fuse) */
> +       d_type &= S_DT_MASK;
> +
>         p = ovl_cache_entry_find(rdd->root, c_name, c_len);
>         if (p) {
>                 list_move_tail(&p->l_node, &rdd->middle);
> @@ -316,6 +319,9 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
>         char *cf_name = NULL;
>         int c_len = 0, ret;
>
> +       /* Mask out high bits that may be used (e.g., fuse) */
> +       d_type &= S_DT_MASK;
> +
>         if (ofs->casefold)
>                 c_len = ovl_casefold(rdd, name, namelen, &cf_name);
>
> @@ -632,6 +638,9 @@ static bool ovl_fill_plain(struct dir_context *ctx, const char *name,
>         struct ovl_readdir_data *rdd =
>                 container_of(ctx, struct ovl_readdir_data, ctx);
>
> +       /* Mask out high bits that may be used (e.g., fuse) */
> +       d_type &= S_DT_MASK;
> +
>         rdd->count++;
>         p = ovl_cache_entry_new(rdd, name, namelen, NULL, 0, ino, d_type);
>         if (p == NULL) {
> @@ -755,6 +764,9 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
>         struct dir_context *orig_ctx = rdt->orig_ctx;
>         bool res;
>
> +       /* Mask out high bits that may be used (e.g., fuse) */
> +       d_type &= S_DT_MASK;
> +
>         if (rdt->parent_ino && strcmp(name, "..") == 0) {
>                 ino = rdt->parent_ino;
>         } else if (rdt->cache) {
> @@ -1144,6 +1156,9 @@ static bool ovl_check_d_type(struct dir_context *ctx, const char *name,
>         struct ovl_readdir_data *rdd =
>                 container_of(ctx, struct ovl_readdir_data, ctx);
>
> +       /* Mask out high bits that may be used (e.g., fuse) */
> +       d_type &= S_DT_MASK;
> +
>         /* Even if d_type is not supported, DT_DIR is returned for . and .. */
>         if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
>                 return true;
> --
> 2.43.0
>
Re: [PATCH] overlayfs: mask d_type high bits before whiteout check
Posted by Chunsheng Luo 1 month ago

On 1/8/26 4:43 AM, Amir Goldstein wrote:
> On Wed, Jan 7, 2026 at 4:46 AM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>>
>> Commit c31f91c6af96 ("fuse: don't allow signals to interrupt getdents
>> copying") introduced the use of high bits in d_type as flags. However,
>> overlayfs was not adapted to handle this change.
>>
>> In ovl_cache_entry_new(), the code checks if d_type == DT_CHR to
>> determine if an entry might be a whiteout. When fuse is used as the
>> lower layer and sets high bits in d_type, this comparison fails,
>> causing whiteout files to not be recognized properly and resulting in
>> incorrect overlayfs behavior.
>>
>> Fix this by masking out the high bits with S_DT_MASK before checking.
>>
>> Fixes: c31f91c6af96 ("fuse: don't allow signals to interrupt getdents copying")
>> Link: https://github.com/containerd/stargz-snapshotter/issues/2214
>> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
> 
> Hi Chunsheng,
> 
> Thanks for the report and the suggested fix.
> 
> This time overlayfs was surprised by unexpected d_type flags and next
> time it could be another user.
> 
> I prefer to fix this in a more profound way -
> Instead of making overlafys aware of d_type flags, require the users that
> use the d_type flags to opt-in for them.
> 
> Please test/review the attached patch.
> 
> Thanks,
> Amir.
> 

Thank you for the profound solution!

The attached patch has been tested and verified to effectively address 
the d_type high bits usage issue by enforcing the opt-in mechanism.

The variable `dt_flag_mask` might be clearer if renamed to 
`dt_flags_mask` (plural "flags").

Reviewed-by: Chunsheng Luo <luochunsheng@ustc.edu>
Tested-by: Chunsheng Luo <luochunsheng@ustc.edu>

> 
>> ---
>>   fs/overlayfs/readdir.c | 15 +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>
>> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
>> index 160960bb0ad0..a2ac47458bf9 100644
>> --- a/fs/overlayfs/readdir.c
>> +++ b/fs/overlayfs/readdir.c
>> @@ -246,6 +246,9 @@ static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
>>   {
>>          struct ovl_cache_entry *p;
>>
>> +       /* Mask out high bits that may be used (e.g., fuse) */
>> +       d_type &= S_DT_MASK;
>> +
>>          p = ovl_cache_entry_find(rdd->root, c_name, c_len);
>>          if (p) {
>>                  list_move_tail(&p->l_node, &rdd->middle);
>> @@ -316,6 +319,9 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
>>          char *cf_name = NULL;
>>          int c_len = 0, ret;
>>
>> +       /* Mask out high bits that may be used (e.g., fuse) */
>> +       d_type &= S_DT_MASK;
>> +
>>          if (ofs->casefold)
>>                  c_len = ovl_casefold(rdd, name, namelen, &cf_name);
>>
>> @@ -632,6 +638,9 @@ static bool ovl_fill_plain(struct dir_context *ctx, const char *name,
>>          struct ovl_readdir_data *rdd =
>>                  container_of(ctx, struct ovl_readdir_data, ctx);
>>
>> +       /* Mask out high bits that may be used (e.g., fuse) */
>> +       d_type &= S_DT_MASK;
>> +
>>          rdd->count++;
>>          p = ovl_cache_entry_new(rdd, name, namelen, NULL, 0, ino, d_type);
>>          if (p == NULL) {
>> @@ -755,6 +764,9 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
>>          struct dir_context *orig_ctx = rdt->orig_ctx;
>>          bool res;
>>
>> +       /* Mask out high bits that may be used (e.g., fuse) */
>> +       d_type &= S_DT_MASK;
>> +
>>          if (rdt->parent_ino && strcmp(name, "..") == 0) {
>>                  ino = rdt->parent_ino;
>>          } else if (rdt->cache) {
>> @@ -1144,6 +1156,9 @@ static bool ovl_check_d_type(struct dir_context *ctx, const char *name,
>>          struct ovl_readdir_data *rdd =
>>                  container_of(ctx, struct ovl_readdir_data, ctx);
>>
>> +       /* Mask out high bits that may be used (e.g., fuse) */
>> +       d_type &= S_DT_MASK;
>> +
>>          /* Even if d_type is not supported, DT_DIR is returned for . and .. */
>>          if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
>>                  return true;
>> --
>> 2.43.0
>>

Re: [PATCH] overlayfs: mask d_type high bits before whiteout check
Posted by Amir Goldstein 1 month ago
On Thu, Jan 8, 2026 at 4:48 AM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>
>
>
> On 1/8/26 4:43 AM, Amir Goldstein wrote:
> > On Wed, Jan 7, 2026 at 4:46 AM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
> >>
> >> Commit c31f91c6af96 ("fuse: don't allow signals to interrupt getdents
> >> copying") introduced the use of high bits in d_type as flags. However,
> >> overlayfs was not adapted to handle this change.
> >>
> >> In ovl_cache_entry_new(), the code checks if d_type == DT_CHR to
> >> determine if an entry might be a whiteout. When fuse is used as the
> >> lower layer and sets high bits in d_type, this comparison fails,
> >> causing whiteout files to not be recognized properly and resulting in
> >> incorrect overlayfs behavior.
> >>
> >> Fix this by masking out the high bits with S_DT_MASK before checking.
> >>
> >> Fixes: c31f91c6af96 ("fuse: don't allow signals to interrupt getdents copying")
> >> Link: https://github.com/containerd/stargz-snapshotter/issues/2214
> >> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
> >
> > Hi Chunsheng,
> >
> > Thanks for the report and the suggested fix.
> >
> > This time overlayfs was surprised by unexpected d_type flags and next
> > time it could be another user.
> >
> > I prefer to fix this in a more profound way -
> > Instead of making overlafys aware of d_type flags, require the users that
> > use the d_type flags to opt-in for them.
> >
> > Please test/review the attached patch.
> >
> > Thanks,
> > Amir.
> >
>
> Thank you for the profound solution!
>
> The attached patch has been tested and verified to effectively address
> the d_type high bits usage issue by enforcing the opt-in mechanism.
>
> The variable `dt_flag_mask` might be clearer if renamed to
> `dt_flags_mask` (plural "flags").

Agreed.

>
> Reviewed-by: Chunsheng Luo <luochunsheng@ustc.edu>
> Tested-by: Chunsheng Luo <luochunsheng@ustc.edu>
>

Thanks for review and testing!
Amir.