From: Sasha Levin <sashal@kernel.org>
To: amir73il@gmail.com, edvard@tuta.io
Cc: stable@vger.kernel.org
Subject: FAILED: patch "[PATCH] ovl: inherit FMODE_NONOTIFY when reading directory layers" failed to apply to 7.3-stable tree
Date: Mon, 9 Nov 2026 20:01:59 -0500 [thread overview]
Message-ID: <20261109200159-failed-7.3-9ff338af0e00@kernel.org> (raw)
The patch below does not apply to the 7.3-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-7.3.y
git checkout FETCH_HEAD
git cherry-pick -x 9ff338af0e002fe217cfa16b1289b76f6b21fc72
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261109200159-failed-7.3-9ff338af0e00@kernel.org' --subject-prefix 'PATCH 7.3.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From 9ff338af0e002fe217cfa16b1289b76f6b21fc72 Mon Sep 17 00:00:00 2001
From: Amir Goldstein <amir73il@gmail.com>
Date: Fri, 30 Oct 2026 18:07:02 +0100
Subject: [PATCH] ovl: inherit FMODE_NONOTIFY when reading directory layers
Listing a merged or impure overlay directory opens the real layer
directories from ovl_dir_read(), when the readdir cache is filled.
Those opens use plain ovl_path_open(), so when the directory fd is
one that fanotify created for a permission event, they can still raise
FS_OPEN_PERM. A listener that also marks the backing filesystem and
calls getdents() on the event fd before answering then deadlocks the
same way as with the directory open fixed by the previous commit.
Store the overlay user file in struct ovl_readdir_data and pass it to
ovl_path_open_realfile() from ovl_dir_read(), for both the merged and
the impure cache. Internal readers such as ovl_check_empty_dir() and
the mount-time workdir cleanup still pass no user file.
A note about severity and real world impact: The FAN_OPEN_PERM event is
traditionally used by anti-malware protection agents and security/audit
agents. The scope that is often used in those use cases is FAN_MARK_MOUNT
and agents typically monitor multiple mounts in a mount namespace.
FAN_OPEN_PERM from directory open requires user opt-in with FAN_ONDIR.
It is often not the case that anti-malware agents monitor open of
directories. Security/audit engines are more likely to opt-into
FAN_OPEN_PERM on directories, but are less likely to list the content
of a directory within the scope of FAN_OPEN_PERM event, so the real
world impact of this bug is likely not significant.
Reported-by: Edvard Conrad <edvard@tuta.io>
Closes: https://lore.kernel.org/all/P5Qu3co--N-9@tuta.io/
Cc: stable@vger.kernel.org
Tested-by: Edvard Conrad <edvard@tuta.io>
Link: https://lore.kernel.org/ltp/P5WKBbq--F-9@tuta.io/
Co-developed-by: Edvard Conrad <edvard@tuta.io>
Signed-off-by: Edvard Conrad <edvard@tuta.io>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/readdir.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 5d21a328fad46..4cd4af097e5c1 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -43,6 +43,7 @@ struct ovl_dir_cache {
struct ovl_readdir_data {
struct dir_context ctx;
+ const struct file *user_file;
struct dentry *dentry;
bool is_lowest;
struct rb_root *root;
@@ -377,7 +378,8 @@ static inline int ovl_dir_read(const struct path *realpath,
struct file *realfile;
int err;
- realfile = ovl_path_open(realpath, O_RDONLY | O_LARGEFILE);
+ realfile = ovl_path_open_realfile(rdd->user_file, realpath,
+ O_RDONLY | O_LARGEFILE);
if (IS_ERR(realfile))
return PTR_ERR(realfile);
@@ -421,13 +423,14 @@ static void ovl_dir_reset(struct file *file)
}
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
- struct rb_root *root)
+ struct rb_root *root, const struct file *user_file)
{
int err;
struct path realpath;
struct ovl_readdir_data rdd = {
.ctx.actor = ovl_fill_merge,
.ctx.count = INT_MAX,
+ .user_file = user_file,
.dentry = dentry,
.list = list,
.root = root,
@@ -498,9 +501,10 @@ static struct ovl_dir_cache *ovl_dir_cache_check(struct inode *inode,
return cache;
}
-static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
+static struct ovl_dir_cache *ovl_dir_cache_get(struct file *file)
{
int res;
+ struct dentry *dentry = file->f_path.dentry;
struct ovl_dir_cache *cache;
struct inode *inode = d_inode(dentry);
@@ -521,7 +525,7 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
INIT_LIST_HEAD(&cache->entries);
cache->root = RB_ROOT;
- res = ovl_dir_read_merged(dentry, &cache->entries, &cache->root);
+ res = ovl_dir_read_merged(dentry, &cache->entries, &cache->root, file);
if (res) {
ovl_cache_free(&cache->entries);
kfree(cache);
@@ -665,8 +669,8 @@ static bool ovl_fill_plain(struct dir_context *ctx, const char *name,
return true;
}
-static int ovl_dir_read_impure(const struct path *path, struct list_head *list,
- struct rb_root *root)
+static int ovl_dir_read_impure(const struct path *path, struct list_head *list,
+ struct rb_root *root, const struct file *user_file)
{
int err;
struct path realpath;
@@ -674,6 +678,7 @@ static int ovl_dir_read_impure(const struct path *path, struct list_head *list,
struct ovl_readdir_data rdd = {
.ctx.actor = ovl_fill_plain,
.ctx.count = INT_MAX,
+ .user_file = user_file,
.list = list,
.root = root,
};
@@ -710,9 +715,10 @@ static int ovl_dir_read_impure(const struct path *path, struct list_head *list,
return 0;
}
-static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path)
+static struct ovl_dir_cache *ovl_cache_get_impure(struct file *file)
{
int res;
+ const struct path *path = &file->f_path;
struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry);
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
@@ -731,7 +737,7 @@ static struct ovl_dir_cache *ovl_cache_get_impure(const struct path *path)
return ERR_PTR(-ENOMEM);
cache->is_refcounted = false;
- res = ovl_dir_read_impure(path, &cache->entries, &cache->root);
+ res = ovl_dir_read_impure(path, &cache->entries, &cache->root, file);
if (res) {
ovl_cache_free(&cache->entries);
kfree(cache);
@@ -852,7 +858,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
dput(parent);
if (ovl_is_impure_dir(file)) {
- rdt.cache = ovl_cache_get_impure(&file->f_path);
+ rdt.cache = ovl_cache_get_impure(file);
if (IS_ERR(rdt.cache))
return PTR_ERR(rdt.cache);
}
@@ -866,14 +872,13 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
static int ovl_iterate_merged(struct file *file, struct dir_context *ctx)
{
struct ovl_dir_file *od = file->private_data;
- struct dentry *dentry = file->f_path.dentry;
struct ovl_cache_entry *p;
int err;
if (!od->cache) {
struct ovl_dir_cache *cache;
- cache = ovl_cache_get(dentry);
+ cache = ovl_dir_cache_get(file);
if (IS_ERR(cache))
return PTR_ERR(cache);
@@ -1120,7 +1125,7 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
struct rb_root root = RB_ROOT;
with_ovl_creds(dentry->d_sb)
- err = ovl_dir_read_merged(dentry, list, &root);
+ err = ovl_dir_read_merged(dentry, list, &root, NULL);
if (err)
return err;
--
2.53.0
reply other threads:[~2026-11-10 1:02 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261109200159-failed-7.3-9ff338af0e00@kernel.org \
--to=sashal@kernel.org \
--cc=amir73il@gmail.com \
--cc=edvard@tuta.io \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox