* [PATCH] ovl: Fix uninit-value in ovl_fill_real
@ 2026-01-27 7:54 Qing Wang
2026-01-27 10:42 ` Miklos Szeredi
0 siblings, 1 reply; 9+ messages in thread
From: Qing Wang @ 2026-01-27 7:54 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein
Cc: linux-unionfs, linux-kernel, Qing Wang,
syzbot+d130f98b2c265fae5297
Syzbot reported a KMSAN uninit-value issue in ovl_fill_real.
This iusse's call chain is:
__do_sys_getdents64()
-> iterate_dir()
...
-> ext4_readdir()
-> fscrypt_fname_alloc_buffer() // alloc
-> fscrypt_fname_disk_to_usr // write without tail '\0'
-> dir_emit()
-> ovl_fill_real() // read by strcmp()
The string is used to store the decrypted directory entry name for an
encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr()
write it wthout null-terminate. However, ovl_fill_real() uses strcmp() to
compare the name against "..", which assumes a null-terminated string and
may trigger a KMSAN uninit-value warning when the buffer tail contains
uninit data.
Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297
Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs")
Signed-off-by: Qing Wang <wangqing7171@gmail.com>
---
fs/overlayfs/readdir.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 160960bb0ad0..2581cb33fb87 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
struct dir_context *orig_ctx = rdt->orig_ctx;
bool res;
- if (rdt->parent_ino && strcmp(name, "..") == 0) {
+ if (rdt->parent_ino && strncmp(name, "..", 2) == 0) {
ino = rdt->parent_ino;
} else if (rdt->cache) {
struct ovl_cache_entry *p;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH] ovl: Fix uninit-value in ovl_fill_real
2026-01-27 7:54 [PATCH] ovl: Fix uninit-value in ovl_fill_real Qing Wang
@ 2026-01-27 10:42 ` Miklos Szeredi
2026-01-27 10:52 ` [PATCH v2] " Qing Wang
0 siblings, 1 reply; 9+ messages in thread
From: Miklos Szeredi @ 2026-01-27 10:42 UTC (permalink / raw)
To: Qing Wang
Cc: Amir Goldstein, linux-unionfs, linux-kernel,
syzbot+d130f98b2c265fae5297
On Tue, 27 Jan 2026 at 08:54, Qing Wang <wangqing7171@gmail.com> wrote:
>
> Syzbot reported a KMSAN uninit-value issue in ovl_fill_real.
>
> This iusse's call chain is:
> __do_sys_getdents64()
> -> iterate_dir()
> ...
> -> ext4_readdir()
> -> fscrypt_fname_alloc_buffer() // alloc
> -> fscrypt_fname_disk_to_usr // write without tail '\0'
> -> dir_emit()
> -> ovl_fill_real() // read by strcmp()
>
> The string is used to store the decrypted directory entry name for an
> encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr()
> write it wthout null-terminate. However, ovl_fill_real() uses strcmp() to
> compare the name against "..", which assumes a null-terminated string and
> may trigger a KMSAN uninit-value warning when the buffer tail contains
> uninit data.
>
> Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297
> Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs")
> Signed-off-by: Qing Wang <wangqing7171@gmail.com>
> ---
> fs/overlayfs/readdir.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index 160960bb0ad0..2581cb33fb87 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
> struct dir_context *orig_ctx = rdt->orig_ctx;
> bool res;
>
> - if (rdt->parent_ino && strcmp(name, "..") == 0) {
> + if (rdt->parent_ino && strncmp(name, "..", 2) == 0) {
Need to compare namelen as well.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v2] ovl: Fix uninit-value in ovl_fill_real
2026-01-27 10:42 ` Miklos Szeredi
@ 2026-01-27 10:52 ` Qing Wang
2026-01-27 11:09 ` Amir Goldstein
2026-01-27 11:19 ` Miklos Szeredi
0 siblings, 2 replies; 9+ messages in thread
From: Qing Wang @ 2026-01-27 10:52 UTC (permalink / raw)
To: miklos
Cc: amir73il, linux-kernel, linux-unionfs,
syzbot+d130f98b2c265fae5297, wangqing7171
Syzbot reported a KMSAN uninit-value issue in ovl_fill_real.
This iusse's call chain is:
__do_sys_getdents64()
-> iterate_dir()
...
-> ext4_readdir()
-> fscrypt_fname_alloc_buffer() // alloc
-> fscrypt_fname_disk_to_usr // write without tail '\0'
-> dir_emit()
-> ovl_fill_real() // read by strcmp()
The string is used to store the decrypted directory entry name for an
encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr()
write it wthout null-terminate. However, ovl_fill_real() uses strcmp() to
compare the name against "..", which assumes a null-terminated string and
may trigger a KMSAN uninit-value warning when the buffer tail contains
uninit data.
Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297
Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs")
Signed-off-by: Qing Wang <wangqing7171@gmail.com>
---
fs/overlayfs/readdir.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 160960bb0ad0..9ea3cd11dd93 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
struct dir_context *orig_ctx = rdt->orig_ctx;
bool res;
- if (rdt->parent_ino && strcmp(name, "..") == 0) {
+ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", namelen)) {
ino = rdt->parent_ino;
} else if (rdt->cache) {
struct ovl_cache_entry *p;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2] ovl: Fix uninit-value in ovl_fill_real
2026-01-27 10:52 ` [PATCH v2] " Qing Wang
@ 2026-01-27 11:09 ` Amir Goldstein
2026-01-28 0:43 ` Eric Biggers
2026-01-27 11:19 ` Miklos Szeredi
1 sibling, 1 reply; 9+ messages in thread
From: Amir Goldstein @ 2026-01-27 11:09 UTC (permalink / raw)
To: Qing Wang, Eric Biggers
Cc: miklos, linux-kernel, linux-unionfs, syzbot+d130f98b2c265fae5297,
Christian Brauner
On Tue, Jan 27, 2026 at 11:52 AM Qing Wang <wangqing7171@gmail.com> wrote:
>
> Syzbot reported a KMSAN uninit-value issue in ovl_fill_real.
>
> This iusse's call chain is:
> __do_sys_getdents64()
> -> iterate_dir()
> ...
> -> ext4_readdir()
> -> fscrypt_fname_alloc_buffer() // alloc
> -> fscrypt_fname_disk_to_usr // write without tail '\0'
> -> dir_emit()
> -> ovl_fill_real() // read by strcmp()
>
> The string is used to store the decrypted directory entry name for an
> encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr()
> write it wthout null-terminate. However, ovl_fill_real() uses strcmp() to
typo: without
> compare the name against "..", which assumes a null-terminated string and
> may trigger a KMSAN uninit-value warning when the buffer tail contains
> uninit data.
>
> Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297
> Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs")
> Signed-off-by: Qing Wang <wangqing7171@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> fs/overlayfs/readdir.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index 160960bb0ad0..9ea3cd11dd93 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
> struct dir_context *orig_ctx = rdt->orig_ctx;
> bool res;
>
> - if (rdt->parent_ino && strcmp(name, "..") == 0) {
> + if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", namelen)) {
> ino = rdt->parent_ino;
> } else if (rdt->cache) {
> struct ovl_cache_entry *p;
> --
> 2.34.1
>
Eric,
Considering that fscrypt_fname_alloc_buffer() anyway allocates the byte for NUL
termination and that decrypted names are zero padded (right?).
How about reinforcing this fix with:
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index a9a4432d12ba1..97e00af49bb9f 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -276,6 +276,7 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
if (fscrypt_is_dot_dotdot(&qname)) {
oname->name[0] = '.';
oname->name[iname->len - 1] = '.';
+ oname->name[iname->len] = 0;
oname->len = iname->len;
return 0;
}
Thanks,
Amir.
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2] ovl: Fix uninit-value in ovl_fill_real
2026-01-27 11:09 ` Amir Goldstein
@ 2026-01-28 0:43 ` Eric Biggers
0 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2026-01-28 0:43 UTC (permalink / raw)
To: Amir Goldstein
Cc: Qing Wang, miklos, linux-kernel, linux-unionfs,
syzbot+d130f98b2c265fae5297, Christian Brauner
On Tue, Jan 27, 2026 at 12:09:47PM +0100, Amir Goldstein wrote:
> Eric,
>
> Considering that fscrypt_fname_alloc_buffer() anyway allocates the byte for NUL
> termination and that decrypted names are zero padded (right?).
Only when the length of the original filename isn't already a multiple
of the padding amount, as configured by FSCRYPT_POLICY_FLAGS_PAD_*.
> How about reinforcing this fix with:
>
> diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
> index a9a4432d12ba1..97e00af49bb9f 100644
> --- a/fs/crypto/fname.c
> +++ b/fs/crypto/fname.c
> @@ -276,6 +276,7 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
> if (fscrypt_is_dot_dotdot(&qname)) {
> oname->name[0] = '.';
> oname->name[iname->len - 1] = '.';
> + oname->name[iname->len] = 0;
> oname->len = iname->len;
> return 0;
Do you propose to do the same for all callers of dir_emit() in all
filesystems? It seems not NUL-terminating the name is normal. Just
usually the name is in the pagecache rather than slab memory, which
makes KMSAN not usually notice the out-of-bounds read in overlayfs.
- Eric
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2] ovl: Fix uninit-value in ovl_fill_real
2026-01-27 10:52 ` [PATCH v2] " Qing Wang
2026-01-27 11:09 ` Amir Goldstein
@ 2026-01-27 11:19 ` Miklos Szeredi
2026-01-28 2:42 ` Qing Wang
1 sibling, 1 reply; 9+ messages in thread
From: Miklos Szeredi @ 2026-01-27 11:19 UTC (permalink / raw)
To: Qing Wang
Cc: amir73il, linux-kernel, linux-unionfs,
syzbot+d130f98b2c265fae5297
On Tue, 27 Jan 2026 at 11:52, Qing Wang <wangqing7171@gmail.com> wrote:
>
> Syzbot reported a KMSAN uninit-value issue in ovl_fill_real.
>
> This iusse's call chain is:
> __do_sys_getdents64()
> -> iterate_dir()
> ...
> -> ext4_readdir()
> -> fscrypt_fname_alloc_buffer() // alloc
> -> fscrypt_fname_disk_to_usr // write without tail '\0'
> -> dir_emit()
> -> ovl_fill_real() // read by strcmp()
>
> The string is used to store the decrypted directory entry name for an
> encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr()
> write it wthout null-terminate. However, ovl_fill_real() uses strcmp() to
> compare the name against "..", which assumes a null-terminated string and
> may trigger a KMSAN uninit-value warning when the buffer tail contains
> uninit data.
>
> Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297
> Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs")
> Signed-off-by: Qing Wang <wangqing7171@gmail.com>
> ---
> fs/overlayfs/readdir.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index 160960bb0ad0..9ea3cd11dd93 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
> struct dir_context *orig_ctx = rdt->orig_ctx;
> bool res;
>
> - if (rdt->parent_ino && strcmp(name, "..") == 0) {
> + if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", namelen)) {
Yeah, and also the str... functions only make sense on null terminated
strings, so that needs to be memcmp.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2] ovl: Fix uninit-value in ovl_fill_real
2026-01-27 11:19 ` Miklos Szeredi
@ 2026-01-28 2:42 ` Qing Wang
2026-01-28 10:19 ` Amir Goldstein
0 siblings, 1 reply; 9+ messages in thread
From: Qing Wang @ 2026-01-28 2:42 UTC (permalink / raw)
To: miklos
Cc: amir73il, linux-kernel, linux-unionfs,
syzbot+d130f98b2c265fae5297, wangqing7171
On Tue, 27 Jan 2026 at 19:19, Miklos Szeredi <miklos@szeredi.hu> wrote:
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index 160960bb0ad0..9ea3cd11dd93 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
> struct dir_context *orig_ctx = rdt->orig_ctx;
> bool res;
>
> - if (rdt->parent_ino && strcmp(name, "..") == 0) {
> + if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", namelen)) {
>
> Yeah, and also the str... functions only make sense on null terminated
> strings, so that needs to be memcmp.
Thanks for your idea, but I think strncmp is same as memncmp in this case.
strncmp dons't use null terminated.
```
int strncmp(const char *cs, const char *ct, size_t count)
{
unsigned char c1, c2;
while (count) {
c1 = *cs++;
c2 = *ct++;
if (c1 != c2)
return c1 < c2 ? -1 : 1;
if (!c1)
break;
count--;
}
return 0;
}
```
What do you think?
--
Best Regards,
Qing
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2] ovl: Fix uninit-value in ovl_fill_real
2026-01-28 2:42 ` Qing Wang
@ 2026-01-28 10:19 ` Amir Goldstein
2026-01-28 10:36 ` Miklos Szeredi
0 siblings, 1 reply; 9+ messages in thread
From: Amir Goldstein @ 2026-01-28 10:19 UTC (permalink / raw)
To: Qing Wang
Cc: miklos, linux-kernel, linux-unionfs, syzbot+d130f98b2c265fae5297
On Wed, Jan 28, 2026 at 3:42 AM Qing Wang <wangqing7171@gmail.com> wrote:
>
> On Tue, 27 Jan 2026 at 19:19, Miklos Szeredi <miklos@szeredi.hu> wrote:
> > diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> > index 160960bb0ad0..9ea3cd11dd93 100644
> > --- a/fs/overlayfs/readdir.c
> > +++ b/fs/overlayfs/readdir.c
> > @@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
> > struct dir_context *orig_ctx = rdt->orig_ctx;
> > bool res;
> >
> > - if (rdt->parent_ino && strcmp(name, "..") == 0) {
> > + if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", namelen)) {
> >
> > Yeah, and also the str... functions only make sense on null terminated
> > strings, so that needs to be memcmp.
>
> Thanks for your idea, but I think strncmp is same as memncmp in this case.
> strncmp dons't use null terminated.
>
> ```
> int strncmp(const char *cs, const char *ct, size_t count)
> {
> unsigned char c1, c2;
>
> while (count) {
> c1 = *cs++;
> c2 = *ct++;
> if (c1 != c2)
> return c1 < c2 ? -1 : 1;
> if (!c1)
> break;
> count--;
> }
> return 0;
> }
> ```
>
> What do you think?
I think this discussion is not worth spending our time.
After namelen == 2, it really does not matter if we use strncmp or memcmp
IMO. I will post a followup patch to add name_is_dotdot() helper and use
those helpers in overlayfs readdir code instead of all the many open coded
variants that it has now, which may be safe, but still ugly.
In the meanwhile I'd rather apply v2 as is so it could be picked by stable.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-01-28 10:37 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-27 7:54 [PATCH] ovl: Fix uninit-value in ovl_fill_real Qing Wang
2026-01-27 10:42 ` Miklos Szeredi
2026-01-27 10:52 ` [PATCH v2] " Qing Wang
2026-01-27 11:09 ` Amir Goldstein
2026-01-28 0:43 ` Eric Biggers
2026-01-27 11:19 ` Miklos Szeredi
2026-01-28 2:42 ` Qing Wang
2026-01-28 10:19 ` Amir Goldstein
2026-01-28 10:36 ` Miklos Szeredi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox