FAILED: patch "[PATCH] ovl: check that the parents of volatile/dirty are dirs" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x e34d2ef818e4c7676d8d8e1bf43e6a1ed39efb2a
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026110453-dock-echo-0d7a@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e34d2ef818e4c7676d8d8e1bf43e6a1ed39efb2a Mon Sep 17 00:00:00 2001
From: Chris Mason <[email protected]>
Date: Wed, 7 Oct 2026 10:15:11 +0000
Subject: [PATCH] ovl: check that the parents of volatile/dirty are dirs
An unprivileged user crashes the kernel by mounting overlayfs with the volatile option.
A dentry that serves as the parent of a lookup must be a directory. ovl_create_volatile_dirty() walks work/incompat/volatile/dirty by name, and ovl_lookup_or_create() returns an existing entry whatever its type. A file or a symlink that another task creates during the mount becomes the parent of the next lookup, which calls a NULL ->lookup.
An unprivileged user mounted overlayfs with "volatile" in a user namespace while a second process created a symlink named work/incompat, and the mount task oopsed on a NULL ->lookup call.
Fix this by returning -ENOTDIR from ovl_lookup_or_create() when the caller asked for a directory and the existing entry is a non-dir.
fs/overlayfs/super.c +9 -4
@@ -621,16 +621,21 @@ cleanup_temp:static struct dentry *ovl_lookup_or_create (struct ovl_fs *ofs,struct dentry *parent, -const char *name,umode_t mode) +const char *name,bool is_dir) {struct dentry *child; child =ovl_start_creating_upper (ofs, parent, &QSTR (name));if (!IS_ERR (child)) { -if (!child->d_inode) +if (!child->d_inode) { child =ovl_create_real (ofs, parent, child, &QSTR (name), -OVL_CATTR (mode)); +OVL_CATTR (is_dir ?S_IFDIR : +S_IFREG )); + }else if (is_dir && !d_can_lookup (child)) { +end_creating (child); + child =ERR_PTR (-ENOTDIR ); + }end_creating_keep (child); }dput (parent);
@@ -652,7 +657,7 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs)const char *const *name = volatile_path;for (ctr =ARRAY_SIZE (volatile_path); ctr; ctr--, name++) { - d =ovl_lookup_or_create (ofs, d, *name, ctr >1 ?S_IFDIR :S_IFREG ); + d =ovl_lookup_or_create (ofs, d, *name, ctr >1 );if (IS_ERR (d))return PTR_ERR (d); }
Sasha Levin
maintainerPATCH 1/1 ovl: check that the parents of volatile/dirty are dirs
From: Chris Mason <[email protected]>
[ Upstream commit e34d2ef818e4c7676d8d8e1bf43e6a1ed39efb2a ]
An unprivileged user crashes the kernel by mounting overlayfs with the volatile option.
A dentry that serves as the parent of a lookup must be a directory. ovl_create_volatile_dirty() walks work/incompat/volatile/dirty by name, and ovl_lookup_or_create() returns an existing entry whatever its type. A file or a symlink that another task creates during the mount becomes the parent of the next lookup, which calls a NULL ->lookup.
An unprivileged user mounted overlayfs with "volatile" in a user namespace while a second process created a symlink named work/incompat, and the mount task oopsed on a NULL ->lookup call.
Fix this by returning -ENOTDIR from ovl_lookup_or_create() when the caller asked for a directory and the existing entry is a non-dir.
--- fs/overlayfs/super.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
fs/overlayfs/super.c +12 -5
@@ -1321,16 +1321,23 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs)static struct dentry *ovl_lookup_or_create (struct ovl_fs *ofs,struct dentry *parent, -const char *name,umode_t mode) +const char *name,bool is_dir) {size_t len =strlen (name);struct dentry *child;inode_lock_nested (parent->d_inode,I_MUTEX_PARENT ); child =lookup_one_len (name, parent, len); -if (!IS_ERR (child) && !child->d_inode) - child =ovl_create_real (ofs, parent->d_inode, child, -OVL_CATTR (mode)); +if (!IS_ERR (child)) { +if (!child->d_inode) { + child =ovl_create_real (ofs, parent->d_inode, child, +OVL_CATTR (is_dir ?S_IFDIR : +S_IFREG )); + }else if (is_dir && !d_can_lookup (child)) { +dput (child); + child =ERR_PTR (-ENOTDIR ); + } + }inode_unlock (parent->d_inode);dput (parent);
@@ -1351,7 +1358,7 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs)const char *const *name = volatile_path;for (ctr =ARRAY_SIZE (volatile_path); ctr; ctr--, name++) { - d =ovl_lookup_or_create (ofs, d, *name, ctr >1 ?S_IFDIR :S_IFREG ); + d =ovl_lookup_or_create (ofs, d, *name, ctr >1 );if (IS_ERR (d))return PTR_ERR (d); }
Signature · 1 line
2.53.0