* [PATCH 6.6 0/2] ovl: backports of fixes that failed to apply
@ 2026-11-04 18:45 Amir Goldstein
2026-11-04 18:45 ` [PATCH 6.6 1/2] ovl: take a snapshot of the name for copy up Amir Goldstein
2026-11-04 18:45 ` [PATCH 6.6 2/2] ovl: use the pinned upper dir in ovl_fix_origin() Amir Goldstein
0 siblings, 2 replies; 3+ messages in thread
From: Amir Goldstein @ 2026-11-04 18:45 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Miklos Szeredi, stable, linux-unionfs
Greg,
These are backports of two overlayfs fixes from ovl-fixes-7.3 that
failed to apply to the 6.6 and 6.1 stable trees:
65bf000962a3 ("ovl: take a snapshot of the name for copy up")
4f61ff2ebfb3 ("ovl: use the pinned upper dir in ovl_fix_origin()")
The same backports are expected to apply cleanly to 6.6 and 6.1, so
please apply this series to both trees. The upstream commits are
already queued for 6.18 and 6.12.
The patches do not depend on each other and can be applied in any order.
Thanks,
Amir.
Chris Mason (2):
ovl: take a snapshot of the name for copy up
ovl: use the pinned upper dir in ovl_fix_origin()
fs/overlayfs/copy_up.c | 16 ++++++++++++++--
fs/overlayfs/namei.c | 6 ++++--
fs/overlayfs/overlayfs.h | 6 ++++++
3 files changed, 24 insertions(+), 4 deletions(-)
--
backport
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 6.6 1/2] ovl: take a snapshot of the name for copy up
2026-11-04 18:45 [PATCH 6.6 0/2] ovl: backports of fixes that failed to apply Amir Goldstein
@ 2026-11-04 18:45 ` Amir Goldstein
2026-11-04 18:45 ` [PATCH 6.6 2/2] ovl: use the pinned upper dir in ovl_fix_origin() Amir Goldstein
1 sibling, 0 replies; 3+ messages in thread
From: Amir Goldstein @ 2026-11-04 18:45 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Miklos Szeredi, stable, linux-unionfs, Chris Mason, Josef Bacik
From: Chris Mason <mason@kernel.org>
commit 65bf000962a33ec9d2488e4e1797b6cf630abcbb upstream.
The copy up of a directory reads a freed dentry name when a lookup
moves the directory at the same time.
A pointer to the name of a dentry is only valid while something stops
a move of the dentry. ovl_do_copy_up() keeps a plain copy of
c->dentry->d_name in c->destname, and ovl_copy_up_start() only keeps
ovl_rename() away. When a lookup finds the same directory under another
name after a change to the lower layer, d_splice_alias() moves the
dentry and frees its external name.
With a delay in ovl_do_copy_up(), a chmod of a lower-only directory with
a 60 byte name raced with a rename of that directory in the lower layer
and a stat of the new name, and KASAN reported a use-after-free in
lookup_noperm_common().
Fix this by using take_dentry_name_snapshot() for c->destname.
Fixes: 829c28be9bb9 ("ovl: use d_splice_alias() in place of d_add() in lookup")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
[backport: destname is set in ovl_copy_up_one(), take the snapshot in
the non-index branch of ovl_do_copy_up() instead]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/copy_up.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -869,6 +869,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
{
int err;
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+ struct name_snapshot name;
bool to_index = false;
/*
@@ -897,13 +898,23 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
/* Disconnected dentry must be copied up to index dir */
return -EIO;
} else {
+ /*
+ * ovl_copy_up_start() keeps ovl_rename() away from c->dentry,
+ * because ovl_rename() calls ovl_copy_up() on source and target
+ * dentry. It does not stop d_splice_alias() from moving a
+ * directory that a lookup found under another name after a
+ * change to the lower layer. That move frees an external name,
+ * so take a snapshot.
+ */
+ take_dentry_name_snapshot(&name, c->dentry);
+ c->destname = name.name;
/*
* Mark parent "impure" because it may now contain non-pure
* upper
*/
err = ovl_set_impure(c->parent, c->destdir);
if (err)
- return err;
+ goto out;
}
/* Should we copyup with O_TMPFILE or with workdir? */
@@ -935,6 +946,8 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
out:
if (to_index)
kfree(c->destname.name);
+ else
+ release_dentry_name_snapshot(&name);
return err;
}
@@ -1070,7 +1083,6 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
if (parent) {
ovl_path_upper(parent, &parentpath);
ctx.destdir = parentpath.dentry;
- ctx.destname = dentry->d_name;
err = vfs_getattr(&parentpath, &ctx.pstat,
STATX_ATIME | STATX_MTIME,
--
backport
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 6.6 2/2] ovl: use the pinned upper dir in ovl_fix_origin()
2026-11-04 18:45 [PATCH 6.6 0/2] ovl: backports of fixes that failed to apply Amir Goldstein
2026-11-04 18:45 ` [PATCH 6.6 1/2] ovl: take a snapshot of the name for copy up Amir Goldstein
@ 2026-11-04 18:45 ` Amir Goldstein
1 sibling, 0 replies; 3+ messages in thread
From: Amir Goldstein @ 2026-11-04 18:45 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Miklos Szeredi, stable, linux-unionfs, Chris Mason, Josef Bacik
From: Chris Mason <mason@kernel.org>
commit 4f61ff2ebfb3d2967b83b6a4d456242244d5a61f upstream.
Renames made directly on the upper filesystem during a lookup crash the
kernel.
A dentry that is passed to vfs_setxattr() must be pinned.
ovl_fix_origin() passes upper->d_parent to ovl_set_impure() without a
reference, and the lookup holds no lock of the upper directory. A
rename on the upper filesystem changes d_parent, and only the child
pins the new parent, so a second rename and an rmdir free it.
With delays in ovl_fix_origin() and ovl_set_impure(), renaming the upper
directory twice and removing the intermediate parent during the lookup
of a merge directory without an origin xattr gave a KASAN
use-after-free in vfs_setxattr().
Fix this by passing the upper dentry that the overlay parent holds.
Fixes: 9678e6303057 ("ovl: fix inconsistent d_ino for legacy merge dir")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[amir: add helper ovl_set_impure_dir()]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
[ backport: context: ovl_fix_origin() calls ovl_set_origin() ]
fs/overlayfs/namei.c | 6 ++++--
fs/overlayfs/overlayfs.h | 6 ++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -883,8 +883,10 @@ static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry,
return err;
err = ovl_set_origin(ofs, lower, upper);
- if (!err)
- err = ovl_set_impure(dentry->d_parent, upper->d_parent);
+ if (!err) {
+ /* upper->d_parent is not stable, use the overlay parent */
+ err = ovl_set_impure_dir(dentry->d_parent);
+ }
ovl_drop_write(dentry);
return err;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -492,6 +492,12 @@ int ovl_check_setxattr(struct ovl_fs *ofs, struct dentry *upperdentry,
enum ovl_xattr ox, const void *value, size_t size,
int xerr);
int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry);
+
+static inline int ovl_set_impure_dir(struct dentry *dentry)
+{
+ return ovl_set_impure(dentry, ovl_dentry_upper(dentry));
+}
+
bool ovl_inuse_trylock(struct dentry *dentry);
void ovl_inuse_unlock(struct dentry *dentry);
bool ovl_is_inuse(struct dentry *dentry);
--
backport
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-04 18:46 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04 18:45 [PATCH 6.6 0/2] ovl: backports of fixes that failed to apply Amir Goldstein
2026-11-04 18:45 ` [PATCH 6.6 1/2] ovl: take a snapshot of the name for copy up Amir Goldstein
2026-11-04 18:45 ` [PATCH 6.6 2/2] ovl: use the pinned upper dir in ovl_fix_origin() Amir Goldstein
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox