Re: [PATCH] ovl: fix NULL pointer dereference in ovl_i_path_real()
Amir Goldstein <[email protected]>
| Newsgroups | org.kernel.vger.linux-unionfs,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAOQ4uxjKzqH6g41_Gtx_WWE8y69cUrzg8VVsVhg-4PgkOLxLoA@mail.gmail.com> |
On Fri, Aug 7, 2026 at 9:05 AM Varadarajan Narayanan <[email protected]> wrote: > > KASAN reported a NULL pointer dereference in ovl_permission() when it > called mnt_idmap(realpath.mnt): > > BUG: KASAN: null-ptr-deref in ovl_permission+0x150/0x190 > Read of size 8 at addr 0000000000000018 > > ovl_i_path_real() can return a path with a valid dentry but a NULL mnt. > This happens when the inode has an upper dentry, but ovl_upper_mnt() > returns NULL, for example on an overlay without an upper layer. The caller > then dereferences realpath.mnt and crashes. An overlayfs without an upper layer should not have an inode with an upper dentry. > > Also avoid dereferencing lowerpath when it is NULL. > > Fix this by checking lowerpath before using it, and by clearing > path->dentry when no upper mount is available. This makes ovl_i_path_real() > return NULL and lets callers use their existing error handling path. > > Call trace: > ... > __kasan_check_read+0x1c/0x24 > ovl_permission+0x150/0x190 > inode_permission+0x7c/0x204 > may_open+0x84/0x14c > path_openat+0xdf0/0xf60 > do_filp_open+0xbc/0x148 > do_sys_openat2+0x268/0x2bc > do_sys_open+0xd4/0x108 > > Signed-off-by: Varadarajan Narayanan <[email protected]> > --- > fs/overlayfs/util.c | 10 ++++++++-- > 1 file changed, 8 insertions(+), 2 deletions(-) > > diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c > index b41f4788e4f0..ec423e16cbbd 100644 > --- a/fs/overlayfs/util.c > +++ b/fs/overlayfs/util.c > @@ -380,10 +380,16 @@ struct inode *ovl_i_path_real(struct inode *inode, struct path *path) > > path->dentry = ovl_i_dentry_upper(inode); > if (!path->dentry) { > - path->dentry = lowerpath->dentry; > - path->mnt = lowerpath->layer->mnt; > + if (lowerpath) { > + path->dentry = lowerpath->dentry; > + path->mnt = lowerpath->layer->mnt; > + } else { > + path->mnt = NULL; > + } > } else { > path->mnt = ovl_upper_mnt(OVL_FS(inode->i_sb)); > + if (unlikely(!path->mnt)) > + path->dentry = NULL; > } > > return path->dentry ? d_inode_rcu(path->dentry) : NULL; > This patch is wrong because it defends against conditions that should not be possible. If this is reproducible, then there might be a bug somewhere else that needs fixing, use after free or what not. Thanks, Amir.