* FAILED: patch "[PATCH] ovl: hold a reference on the parent in readdir" failed to apply to 5.10-stable tree
@ 2026-11-04 14:34 gregkh
2026-11-05 13:45 ` [PATCH 5.10.y] ovl: hold a reference on the parent in readdir Sasha Levin
0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2026-11-04 14:34 UTC (permalink / raw)
To: mason, amir73il, josef; +Cc: stable
The patch below does not apply to the 5.10-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 <stable@vger.kernel.org>.
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.10.y
git checkout FETCH_HEAD
git cherry-pick -x 16d319e12328acafeafd3eecdf09c46d7fb43452
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026110449-diligent-sip-8b14@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 16d319e12328acafeafd3eecdf09c46d7fb43452 Mon Sep 17 00:00:00 2001
From: Chris Mason <mason@kernel.org>
Date: Wed, 7 Oct 2026 10:53:10 +0000
Subject: [PATCH] ovl: hold a reference on the parent in readdir
Listing a directory on an overlay uses a freed dentry and crashes the
kernel when a lookup moves the directory at the same time.
Code that can sleep may only use d_parent without a reference while
something stops a move of the dentry. ovl_iterate_real(),
ovl_need_adjust_d_ino() and ovl_cache_update() use the d_parent of the
listed directory and hold only the lock of that directory. When a
lookup finds the directory under another parent after a change to a
layer, d_splice_alias() moves it without that lock and drops its
reference on the old parent.
With a delay in ovl_iterate_real(), getdents64 on an overlay directory
raced a rename in the lower layer and a lookup that moved its dentry,
and after an rmdir of the old parent KASAN reported a use-after-free in
security_inode_getattr().
Fix this by using dget_parent() in the three functions.
Fixes: b5efccbe0a12 ("ovl: constant d_ino across copy up")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[amir: fix comments in ovl_need_adjust_d_ino()]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index b875332107d3..45239ef63e8c 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -588,8 +588,8 @@ static int ovl_cache_update(const struct path *path, struct ovl_cache_entry *p,
goto get;
}
if (p->len == 2) {
- /* we shall not be moved */
- this = dget(dir->d_parent);
+ /* d_splice_alias() can move even a locked dir */
+ this = dget_parent(dir);
goto get;
}
}
@@ -818,6 +818,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
struct dentry *dir = file->f_path.dentry;
struct ovl_fs *ofs = OVL_FS(dir->d_sb);
const struct ovl_layer *lower_layer = ovl_layer_lower(dir);
+ struct dentry *parent;
struct ovl_readdir_translate rdt = {
.ctx.actor = ovl_fill_real,
.ctx.count = ctx->count,
@@ -829,18 +830,26 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
if (rdt.xinobits && lower_layer)
rdt.fsid = lower_layer->fsid;
- if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) {
+ /*
+ * The lock on dir does not stop d_splice_alias() from moving it to
+ * another parent, which drops the reference dir holds on this one.
+ */
+ parent = dget_parent(dir);
+ if (OVL_TYPE_MERGE(ovl_path_type(parent))) {
struct kstat stat;
struct path statpath = file->f_path;
- statpath.dentry = dir->d_parent;
+ statpath.dentry = parent;
err = vfs_getattr(&statpath, &stat, STATX_INO, 0);
- if (err)
+ if (err) {
+ dput(parent);
return err;
+ }
WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev);
rdt.parent_ino = stat.ino;
}
+ dput(parent);
if (ovl_is_impure_dir(file)) {
rdt.cache = ovl_cache_get_impure(&file->f_path);
@@ -896,8 +905,10 @@ static bool ovl_need_adjust_d_ino(struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+ struct dentry *parent;
+ enum ovl_path_type type;
- /* If parent is merge, then need to adjust d_ino for '..' */
+ /* With xino, need to map real d_ino to the unified overlay ino space */
if (ovl_xino_bits(ofs))
return true;
@@ -906,8 +917,14 @@ static bool ovl_need_adjust_d_ino(struct file *file)
return false;
/* If dir is impure then need to adjust d_ino for copied up entries */
- if (ovl_is_impure_dir(file) ||
- OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent)))
+ if (ovl_is_impure_dir(file))
+ return true;
+
+ /* If parent is merge, then need to adjust d_ino for '..' */
+ parent = dget_parent(dentry);
+ type = ovl_path_type(parent);
+ dput(parent);
+ if (OVL_TYPE_MERGE(type))
return true;
/* Pure: no need to adjust d_ino */
^ permalink raw reply related [flat|nested] 2+ messages in thread* [PATCH 5.10.y] ovl: hold a reference on the parent in readdir
2026-11-04 14:34 FAILED: patch "[PATCH] ovl: hold a reference on the parent in readdir" failed to apply to 5.10-stable tree gregkh
@ 2026-11-05 13:45 ` Sasha Levin
0 siblings, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-11-05 13:45 UTC (permalink / raw)
To: stable; +Cc: Chris Mason, Josef Bacik, Amir Goldstein, Sasha Levin
From: Chris Mason <mason@kernel.org>
[ Upstream commit 16d319e12328acafeafd3eecdf09c46d7fb43452 ]
Listing a directory on an overlay uses a freed dentry and crashes the
kernel when a lookup moves the directory at the same time.
Code that can sleep may only use d_parent without a reference while
something stops a move of the dentry. ovl_iterate_real(),
ovl_need_adjust_d_ino() and ovl_cache_update() use the d_parent of the
listed directory and hold only the lock of that directory. When a
lookup finds the directory under another parent after a change to a
layer, d_splice_alias() moves it without that lock and drops its
reference on the old parent.
With a delay in ovl_iterate_real(), getdents64 on an overlay directory
raced a rename in the lower layer and a lookup that moved its dentry,
and after an rmdir of the old parent KASAN reported a use-after-free in
security_inode_getattr().
Fix this by using dget_parent() in the three functions.
Fixes: b5efccbe0a12 ("ovl: constant d_ino across copy up")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[amir: fix comments in ovl_need_adjust_d_ino()]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
[ sashal: adapted ovl_need_adjust_d_ino() changes to the inline logic in ovl_iterate() ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/overlayfs/readdir.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 09a5542723787..23ff11914907c 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -474,8 +474,8 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p)
goto get;
}
if (p->len == 2 && p->name[1] == '.') {
- /* we shall not be moved */
- this = dget(dir->d_parent);
+ /* d_splice_alias() can move even a locked dir */
+ this = dget_parent(dir);
goto get;
}
}
@@ -691,6 +691,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
struct ovl_dir_file *od = file->private_data;
struct dentry *dir = file->f_path.dentry;
const struct ovl_layer *lower_layer = ovl_layer_lower(dir);
+ struct dentry *parent;
struct ovl_readdir_translate rdt = {
.ctx.actor = ovl_fill_real,
.orig_ctx = ctx,
@@ -701,18 +702,26 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
if (rdt.xinobits && lower_layer)
rdt.fsid = lower_layer->fsid;
- if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) {
+ /*
+ * The lock on dir does not stop d_splice_alias() from moving it to
+ * another parent, which drops the reference dir holds on this one.
+ */
+ parent = dget_parent(dir);
+ if (OVL_TYPE_MERGE(ovl_path_type(parent))) {
struct kstat stat;
struct path statpath = file->f_path;
- statpath.dentry = dir->d_parent;
+ statpath.dentry = parent;
err = vfs_getattr(&statpath, &stat, STATX_INO, 0);
- if (err)
+ if (err) {
+ dput(parent);
return err;
+ }
WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev);
rdt.parent_ino = stat.ino;
}
+ dput(parent);
if (ovl_is_impure_dir(file)) {
rdt.cache = ovl_cache_get_impure(&file->f_path);
@@ -740,6 +749,8 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
ovl_dir_reset(file);
if (od->is_real) {
+ struct dentry *parent = dget_parent(dentry);
+
/*
* If parent is merge, then need to adjust d_ino for '..', if
* dir is impure then need to adjust d_ino for copied up
@@ -748,11 +759,12 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
if (ovl_xino_bits(dentry->d_sb) ||
(ovl_same_fs(dentry->d_sb) &&
(ovl_is_impure_dir(file) ||
- OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) {
+ OVL_TYPE_MERGE(ovl_path_type(parent))))) {
err = ovl_iterate_real(file, ctx);
} else {
err = iterate_dir(od->realfile, ctx);
}
+ dput(parent);
goto out;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-05 13:45 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04 14:34 FAILED: patch "[PATCH] ovl: hold a reference on the parent in readdir" failed to apply to 5.10-stable tree gregkh
2026-11-05 13:45 ` [PATCH 5.10.y] ovl: hold a reference on the parent in readdir Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.