* [PATCH 00/13] fs: let d_real() fail
@ 2026-11-15 14:01 Christian Brauner
2026-11-15 14:01 ` [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real() Christian Brauner
2026-11-15 18:28 ` [PATCH 00/13] fs: let d_real() fail Alexei Starovoitov
0 siblings, 2 replies; 4+ messages in thread
From: Christian Brauner @ 2026-11-15 14:01 UTC (permalink / raw)
To: Amir Goldstein, linux-fsdevel
Cc: Chris Down, Miklos Szeredi, linux-unionfs, linux-kernel, bpf,
linux-trace-kernel, linux-integrity, linux-security-module,
linux-mm, Christian Brauner (Amutable), stable, Sashiko
overlayfs looks up the data of a metacopy file in a data-only layer
lazily and validates its verity digest when it's first needed. Both can
fail but d_real() has no way to report it. So ovl_d_real() warns and
hands back the overlayfs dentry and every caller silently works with an
inode that doesn't host the data:
- uprobes get created just fine and fail later with a bogus -EIO. Every
new uprobe warns again for each of them. With panic_on_warn that's a
panic.
- IMA skips detecting changes to the backing file and hands out a cached
verdict.
- IPE evaluates its policy against an inode that has none of the
dm-verity or fs-verity properties of the real file.
And that's not limited to files nobody opened yet. A metadata-only
copy-up of an open file makes overlayfs validate the digest again.
As Amir pointed out the correct fix is to teach the callers to deal with
an error. So d_real() may now fail for D_REAL_DATA and all callers
handle it: uprobes fail when they're created, IMA treats it like failing
to hash the file, IPE denies and the bpf kfunc returns NULL. Then
d_real_inode() goes away so nobody can ignore the error again. The first
patch only drops the WARN.
This came out of the same work as the freeze protection fixes for
backing files (cf. [1]). I ran into it with the pseudo filesystem
series (cf. [2]) where file_check_backing() looks at the file hosting
the data of O_PATH files registered for fuse passthrough. With this
series it can just return the error. But this stands on its own.
[1]: https://lore.kernel.org/r/20261114-work-fs-frozen_writes-v1-0-f5ae61c898b1@kernel.org
[2]: https://lore.kernel.org/r/20261114-work-loop-pseudo-v2-0-98639a2286fb@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
Christian Brauner (13):
ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real()
fs: add d_real_data_inode() and d_real_metadata_inode()
tracing/uprobes: handle errors from resolving the real inode
bpf: handle errors from resolving the real inode in uprobe_multi
selftests/bpf: handle d_real_data_inode() errors in bpf_testmod
ima: handle errors from resolving the real inode
ima,evm: use d_real_metadata_inode()
ipe: handle errors from resolving the real inode
bpf: return NULL from bpf_real_data_inode() on errors
ovl: return the error from the lazy lowerdata lookup in ovl_d_real()
fs: remove d_real_inode()
selftests/ftrace: add uprobe tests on overlayfs
selftests/bpf: add uprobe_multi test on overlayfs without data
Documentation/filesystems/porting.rst | 10 ++
Documentation/filesystems/vfs.rst | 6 +
fs/bpf_fs_kfuncs.c | 13 +-
fs/overlayfs/super.c | 19 ++-
include/linux/dcache.h | 47 ++++++-
kernel/trace/bpf_trace.c | 9 +-
kernel/trace/trace_probe.h | 1 +
kernel/trace/trace_uprobe.c | 57 +++++++--
security/integrity/evm/evm_crypto.c | 2 +-
security/integrity/ima/ima_api.c | 17 ++-
security/integrity/ima/ima_main.c | 11 +-
security/ipe/eval.c | 15 ++-
security/ipe/eval.h | 1 +
.../selftests/bpf/prog_tests/uprobe_multi_test.c | 141 +++++++++++++++++++++
.../testing/selftests/bpf/test_kmods/bpf_testmod.c | 11 +-
.../test.d/dynevent/add_remove_uprobe_overlayfs.tc | 92 ++++++++++++++
16 files changed, 408 insertions(+), 44 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261115-work-ovl-d_real-219930df9ec3
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real()
2026-11-15 14:01 [PATCH 00/13] fs: let d_real() fail Christian Brauner
@ 2026-11-15 14:01 ` Christian Brauner
2026-11-15 14:54 ` Amir Goldstein
2026-11-15 18:28 ` [PATCH 00/13] fs: let d_real() fail Alexei Starovoitov
1 sibling, 1 reply; 4+ messages in thread
From: Christian Brauner @ 2026-11-15 14:01 UTC (permalink / raw)
To: Amir Goldstein, linux-fsdevel
Cc: Chris Down, Miklos Szeredi, linux-unionfs, linux-kernel, bpf,
linux-trace-kernel, linux-integrity, linux-security-module,
linux-mm, Christian Brauner (Amutable), stable, Sashiko
ovl_d_real() looks up the data of a metacopy file in a data-only layer
itself if nothing has done that yet. If that lookup fails it WARN()s and
returns the overlayfs dentry.
Commit 42dd69ae1af4 ("ovl: implement lazy lookup of lowerdata in
data-only layers") assumed that the file would be read before
trace_uprobe places a uprobe on it so the data would be there already.
But nothing actually guarantees that. trace_uprobe takes the path from
kern_path() and calls d_real_inode() on it when the event is created and
again when it is enabled. So a uprobe on a metacopy file whose redirect
points at nothing warns twice:
ovl_d_real(/f, 0): real dentry not found
WARNING: fs/overlayfs/super.c:79 at ovl_d_real+0xc9/0x210, CPU#2: sh/279
Call Trace:
<TASK>
__trace_uprobe_create+0x1869/0x25b0
trace_probe_create+0xcc/0xe0
dyn_event_create+0x46/0x70
create_or_delete_trace_uprobe+0x3c/0x70
trace_parse_run_command+0x1a6/0x320
vfs_write+0x1cd/0xfa0
ksys_write+0x116/0x250
do_syscall_64+0x10e/0x5e0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
bpf's uprobe_multi does the same.
A failed lookup isn't a bug though. The data can be missing, its verity
digest can be wrong or a signal can interrupt the wait for the inode
lock. ovl_open() simply fails in that case and
ovl_maybe_lookup_lowerdata() already warns ratelimited about failed
lookups. So return the overlayfs dentry without warning. That's what the
WARN() path returned anyway.
Fixes: 42dd69ae1af4 ("ovl: implement lazy lookup of lowerdata in data-only layers")
Fixes: 184996e92e86 ("ovl: Validate verity xattr when resolving lowerdata")
Cc: stable@vger.kernel.org # v6.5+
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/sashiko-outbox-214581@kernel.org
Reported-by: Chris Down <chris@chrisdown.name>
Closes: https://lore.kernel.org/all/20261114120557.4bc1eb6e57218cdc@chrisdown.name
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
fs/overlayfs/super.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 08695a99f4f93..1985b553a47b7 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -58,15 +58,13 @@ static struct dentry *ovl_d_real(struct dentry *dentry, enum d_real_type type)
/*
* Best effort lazy lookup of lowerdata for D_REAL_DATA case to return
- * the real lowerdata dentry. The only current caller of d_real() with
- * D_REAL_DATA is d_real_inode() from trace_uprobe and this caller is
- * likely going to be followed reading from the file, before placing
- * uprobes on offset within the file, so lowerdata should be available
- * when setting the uprobe.
+ * the real lowerdata dentry. Callers may ask for files that were never
+ * opened, e.g. for uprobes or O_PATH files, so the lookup can fail
+ * here. Return the overlayfs dentry then.
*/
err = ovl_verify_lowerdata(dentry);
if (err)
- goto bug;
+ return dentry;
lower = ovl_dentry_lowerdata(dentry);
if (!lower)
goto bug;
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real()
2026-11-15 14:01 ` [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real() Christian Brauner
@ 2026-11-15 14:54 ` Amir Goldstein
0 siblings, 0 replies; 4+ messages in thread
From: Amir Goldstein @ 2026-11-15 14:54 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Chris Down, Miklos Szeredi, linux-unionfs,
linux-kernel, bpf, linux-trace-kernel, linux-integrity,
linux-security-module, linux-mm, stable, Sashiko
On Sun, Nov 15, 2026 at 3:02 PM Christian Brauner <brauner@kernel.org> wrote:
>
> ovl_d_real() looks up the data of a metacopy file in a data-only layer
> itself if nothing has done that yet. If that lookup fails it WARN()s and
> returns the overlayfs dentry.
>
> Commit 42dd69ae1af4 ("ovl: implement lazy lookup of lowerdata in
> data-only layers") assumed that the file would be read before
> trace_uprobe places a uprobe on it so the data would be there already.
>
> But nothing actually guarantees that. trace_uprobe takes the path from
> kern_path() and calls d_real_inode() on it when the event is created and
> again when it is enabled. So a uprobe on a metacopy file whose redirect
> points at nothing warns twice:
>
> ovl_d_real(/f, 0): real dentry not found
> WARNING: fs/overlayfs/super.c:79 at ovl_d_real+0xc9/0x210, CPU#2: sh/279
> Call Trace:
> <TASK>
> __trace_uprobe_create+0x1869/0x25b0
> trace_probe_create+0xcc/0xe0
> dyn_event_create+0x46/0x70
> create_or_delete_trace_uprobe+0x3c/0x70
> trace_parse_run_command+0x1a6/0x320
> vfs_write+0x1cd/0xfa0
> ksys_write+0x116/0x250
> do_syscall_64+0x10e/0x5e0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> </TASK>
>
> bpf's uprobe_multi does the same.
>
> A failed lookup isn't a bug though. The data can be missing, its verity
> digest can be wrong or a signal can interrupt the wait for the inode
> lock. ovl_open() simply fails in that case and
> ovl_maybe_lookup_lowerdata() already warns ratelimited about failed
> lookups. So return the overlayfs dentry without warning. That's what the
> WARN() path returned anyway.
>
> Fixes: 42dd69ae1af4 ("ovl: implement lazy lookup of lowerdata in data-only layers")
> Fixes: 184996e92e86 ("ovl: Validate verity xattr when resolving lowerdata")
Nit: 42dd69ae1af4 came first and opened the possibility of goto bug
and then 184996e92e86 came later and depends on 42dd69ae1af4.
I don't really see the benefit from stable POV to name the later as Fixes
> Cc: stable@vger.kernel.org # v6.5+
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/sashiko-outbox-214581@kernel.org
> Reported-by: Chris Down <chris@chrisdown.name>
> Closes: https://lore.kernel.org/all/20261114120557.4bc1eb6e57218cdc@chrisdown.name
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> fs/overlayfs/super.c | 10 ++++------
> 1 file changed, 4 insertions(+), 6 deletions(-)
>
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 08695a99f4f93..1985b553a47b7 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -58,15 +58,13 @@ static struct dentry *ovl_d_real(struct dentry *dentry, enum d_real_type type)
>
> /*
> * Best effort lazy lookup of lowerdata for D_REAL_DATA case to return
> - * the real lowerdata dentry. The only current caller of d_real() with
> - * D_REAL_DATA is d_real_inode() from trace_uprobe and this caller is
> - * likely going to be followed reading from the file, before placing
> - * uprobes on offset within the file, so lowerdata should be available
> - * when setting the uprobe.
> + * the real lowerdata dentry. Callers may ask for files that were never
> + * opened, e.g. for uprobes or O_PATH files, so the lookup can fail
> + * here. Return the overlayfs dentry then.
> */
> err = ovl_verify_lowerdata(dentry);
> if (err)
> - goto bug;
> + return dentry;
> lower = ovl_dentry_lowerdata(dentry);
> if (!lower)
> goto bug;
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 00/13] fs: let d_real() fail
2026-11-15 14:01 [PATCH 00/13] fs: let d_real() fail Christian Brauner
2026-11-15 14:01 ` [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real() Christian Brauner
@ 2026-11-15 18:28 ` Alexei Starovoitov
1 sibling, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2026-11-15 18:28 UTC (permalink / raw)
To: Christian Brauner, Amir Goldstein, linux-fsdevel
Cc: Chris Down, Miklos Szeredi, linux-unionfs, linux-kernel, bpf,
linux-trace-kernel, linux-integrity, linux-security-module,
linux-mm, stable, Sashiko
On Sun, Nov 15, 2026 at 06:01 AM Christian Brauner <brauner@kernel.org> wrote:
> As Amir pointed out the correct fix is to teach the callers to deal with
> an error. So d_real() may now fail for D_REAL_DATA and all callers
> handle it: uprobes fail when they're created, IMA treats it like failing
> to hash the file, IPE denies and the bpf kfunc returns NULL. Then
> d_real_inode() goes away so nobody can ignore the error again. The first
> patch only drops the WARN.
For bpf bits:
Acked-by: Alexei Starovoitov <ast@kernel.org>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-15 18:28 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-15 14:01 [PATCH 00/13] fs: let d_real() fail Christian Brauner
2026-11-15 14:01 ` [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real() Christian Brauner
2026-11-15 14:54 ` Amir Goldstein
2026-11-15 18:28 ` [PATCH 00/13] fs: let d_real() fail Alexei Starovoitov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox