From: "Jose E. Marchesi" <jemarch@gnu.org>
To: Justin Suess <utilityemal77@gmail.com>
Cc: "Christian Brauner" <brauner@kernel.org>,
"Alexander Viro" <viro@zeniv.linux.org.uk>,
"Jan Kara" <jack@suse.cz>, NeilBrown <neil@brown.name>,
"Mickaël Salaün" <mic@digikod.net>,
"Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Song Liu" <song@kernel.org>,
linux-fsdevel@vger.kernel.org, bpf@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org, "Günther Noack" <gnoack@google.com>,
"Paul Moore" <paul@paul-moore.com>,
"James Morris" <jmorris@namei.org>,
"Serge E . Hallyn" <serge@hallyn.com>,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Eduard Zingerman" <eddyz87@gmail.com>,
"Yonghong Song" <yonghong.song@linux.dev>,
"John Fastabend" <john.fastabend@gmail.com>,
"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
"Jiri Olsa" <jolsa@kernel.org>,
"Jeff Layton" <jlayton@kernel.org>,
"Amir Goldstein" <amir73il@gmail.com>,
"Mateusz Guzik" <mjguzik@gmail.com>,
"Shuah Khan" <shuah@kernel.org>, "Tingmao Wang" <m@maowtm.org>,
jose.marchesi@oracle.com
Subject: Re: [PATCH bpf-next v1 06/11] selftests/bpf: exercise the path ancestor iterator
Date: Wed, 14 Oct 2026 08:41:12 +0200 [thread overview]
Message-ID: <875wz43htj.fsf@gnu.org> (raw)
In-Reply-To: <as6GG4NMzLrnpKXK@zenbox>
> On Tue, Oct 13, 2026 at 12: 47: 55PM -0400, Justin Suess wrote: >
> Walk the ancestry of a mkdir's parent directory from a sleepable LSM
>> program and check that the iteration reaches the root: the
> temporary > directory, its parent and
> ZjQcmQRYFpfptBannerStart
> This Message Is From an External Sender
> This message came from outside your organization.
> Report Suspicious
>
> ZjQcmQRYFpfptBannerEnd
>
> On Tue, Oct 13, 2026 at 12:47:55PM -0400, Justin Suess wrote:
>> Walk the ancestry of a mkdir's parent directory from a sleepable LSM
>> program and check that the iteration reaches the root: the temporary
>> directory, its parent and / are visited, no position comes back
>> flagged, and the flags read back after the loop show it ended at the
>> root rather than on a failed allocation.
>>
>> Hold the first position across the rest of the walk and resolve its
>> pathname only once the loop is done and the iterator destroyed: the
>> acquired reference, not the walk's, is then all that keeps the
>> position alive.
>>
>> Signed-off-by: Justin Suess <utilityemal77@gmail.com>
>> ---
>> .../selftests/bpf/prog_tests/path_ancestors.c | 57 ++++++++++++++
>> .../selftests/bpf/progs/path_ancestors.c | 74 +++++++++++++++++++
>> 2 files changed, 131 insertions(+)
>> create mode 100644 tools/testing/selftests/bpf/prog_tests/path_ancestors.c
>> create mode 100644 tools/testing/selftests/bpf/progs/path_ancestors.c
>>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/path_ancestors.c b/tools/testing/selftests/bpf/prog_tests/path_ancestors.c
>> new file mode 100644
>> index 000000000000..d1bd26bce10b
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/prog_tests/path_ancestors.c
>> @@ -0,0 +1,57 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c) 2026 Justin Suess */
>> +
>> +#include <sys/stat.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +#include <test_progs.h>
>> +#include "path_ancestors.skel.h"
>> +
>> +void test_path_ancestors(void)
>> +{
>> + char base[] = "/tmp/path_ancestors_XXXXXX";
>> + struct path_ancestors *skel = NULL;
>> + char suba[280], subb[280];
>> +
>> + if (!ASSERT_OK_PTR(mkdtemp(base), "mkdtemp"))
>> + return;
>> + snprintf(suba, sizeof(suba), "%s/a", base);
>> + snprintf(subb, sizeof(subb), "%s/a/b", base);
>> + if (!ASSERT_OK(mkdir(suba, 0755), "mkdir_a"))
>> + goto out_rm;
>> +
>> + skel = path_ancestors__open_and_load();
>> + if (!ASSERT_OK_PTR(skel, "open_and_load"))
>> + goto out_rm;
>> + skel->bss->monitored_pid = getpid();
>> + if (!ASSERT_OK(path_ancestors__attach(skel), "attach"))
>> + goto out;
>> +
>> + /* mkdir b: the hook sees dir == suba, whose ancestry is walked. */
>> + if (!ASSERT_OK(mkdir(subb, 0755), "mkdir_b"))
>> + goto out;
>> +
>> + /* suba, base, /tmp, / at least. */
>> + ASSERT_GE(skel->bss->ref_count, 4, "ref_count");
>> + ASSERT_EQ(skel->bss->ref_flags, 0, "ref_flags");
>> + /*
>> + * The referenced loop ended at the root, not on an allocation
>> + * failure.
>> + */
>> + ASSERT_EQ(skel->bss->end_flags, 0, "end_flags");
>> +
>> + /* The acquired second position, used after its step was taken. */
>> + ASSERT_STREQ(skel->bss->second_path, base, "second_path");
>> + ASSERT_EQ(skel->bss->second_len, strlen(base) + 1, "second_len");
>> +
>> + /* The first position, used only after the walk itself was gone. */
>> + ASSERT_STREQ(skel->bss->first_path, suba, "first_path");
>> + ASSERT_EQ(skel->bss->first_len, strlen(suba) + 1, "first_len");
>> +
>> +out:
>> + path_ancestors__destroy(skel);
>> +out_rm:
>> + rmdir(subb);
>> + rmdir(suba);
>> + rmdir(base);
>> +}
>> diff --git a/tools/testing/selftests/bpf/progs/path_ancestors.c b/tools/testing/selftests/bpf/progs/path_ancestors.c
>> new file mode 100644
>> index 000000000000..6287f5099a18
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/path_ancestors.c
>> @@ -0,0 +1,74 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c) 2026 Justin Suess */
>> +
>> +#include "vmlinux.h"
>> +#include <errno.h>
>> +#include <bpf/bpf_helpers.h>
>> +#include <bpf/bpf_tracing.h>
>> +#include "bpf_kfuncs.h"
>> +
>> +char _license[] SEC("license") = "GPL";
>> +
>> +__u32 monitored_pid;
>> +
>> +int ref_count; /* positions seen by the pure referenced walk */
>> +int ref_flags; /* pos flags seen by the referenced walk */
>> +int end_flags; /* flags after a referenced loop ended: 0 unless NOMEM */
>> +int second_len; /* d_path length of the walk's second position */
>> +int first_len; /* d_path length of the first position, after the walk */
>> +char second_path[256];
>> +char first_path[256];
>> +
>> +static bool monitored(void)
>> +{
>> + return (bpf_get_current_pid_tgid() >> 32) == monitored_pid;
>> +}
>> +
>> +SEC("lsm.s/path_mkdir")
>> +int BPF_PROG(walk_modes, const struct path *dir, struct dentry *dentry,
>> + umode_t mode)
>> +{
>> + struct bpf_iter_path_ancestors it;
>> + struct path *pos, *first = NULL;
>> +
>> + /*
>> + * Keep first's init opaque: gcc-bpf otherwise folds it into a
>> + * preceding loop's exit value, which the verifier cannot track.
>> + */
>> + barrier_var(first);
>> +
> cc'ing Eduard Zingerman + Jose Marchesi
>
> This barrier_var line was necessary for this selftest to pass
> under GCC BPF.
>
> Othwise it will be rejected by the verifier:
>
> 84: (85) call bpf_iter_path_ancestors_rcu_next#63514
> 85: R0=rcu_ptr_path(id=30) ... depth=9
> 86: (bf) r6 = r0 ; R6=rcu_ptr_path(id=30)
> 88: (55) if r0 != 0x0 goto pc-64
> ...
> 101: (85) call bpf_rcu_read_unlock#64876
> ^-- R6 downgraded rcu_ptr_ -> untrusted_ptr_
> ...
> 146: (15) if r6 == 0x0 goto pc+10 ; R6=untrusted_ptr_path(id=30)
> 147: (bf) r1 = r6
> 151: (85) call bpf_path_d_path#64649
> R1 must be referenced or trusted
>
> I think it's trying to optimize out the "struct path* first" and make it
> use the r6 register. It tries reusing the R6 register between the two
> loops, and doing so causes the program to fail to verify because it doesn't
> understand that the path was reinitialized with r6=0 from the previous
> exit.
>
> So I had to add the memory barrier to force struct path to be
> instantiated outside the register.
>
> There's nothing wrong from a *correctness* perspective with the code
> generated by GCC-BPF. But I'm not sure if this is a GCC-BPF bug or a
> bug in the SCEV widening series (merge 15b578b1715d). It depends on
> the contract BPF bytecode is supposed to meet.
>
> But clang works without the barrier, it's only GCC-BPF that produces
> this issue requiring the barrier.
>
> I can give more details if needed.
Please open a bugzilla at https://gcc.gnu.org/bugzilla so we can keep
track of this. It would help to have a preprocessed reproducer based on
the selftest that could be used as a testcase in the GCC testsuite.
Thanks!
>
> Justin
>> [...]
next prev parent reply other threads:[~2026-10-14 6:41 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 16:47 [PATCH bpf-next v1 00/11] fs: unified VFS ancestor walk for Landlock and BPF Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 01/11] namei: introduce __path_walk_parent() Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 02/11] namei: add vfs_walk_ancestors() Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 03/11] landlock: convert ancestor walk to vfs_walk_ancestors() Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 04/11] namei: expose the stepwise ancestor walk to fs/ Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 05/11] bpf: add a path ancestor iterator Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 06/11] selftests/bpf: exercise the " Justin Suess
2026-10-13 19:50 ` Justin Suess
2026-10-14 6:41 ` Jose E. Marchesi [this message]
2026-10-13 16:47 ` [PATCH bpf-next v1 07/11] fs: add mnt_undo_legitimize() Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 08/11] namei: add an rcu-walk mode to the ancestor walk Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 09/11] bpf: support "__uninit" iterator arguments in generic kfuncs Justin Suess
2026-10-13 16:47 ` [PATCH bpf-next v1 10/11] bpf: add a lockless path ancestor iterator Justin Suess
2026-10-13 16:48 ` [PATCH bpf-next v1 11/11] selftests/bpf: exercise the " Justin Suess
2026-10-13 17:50 ` bot+bpf-ci
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=875wz43htj.fsf@gnu.org \
--to=jemarch@gnu.org \
--cc=amir73il@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=gnoack@google.com \
--cc=jack@suse.cz \
--cc=jlayton@kernel.org \
--cc=jmorris@namei.org \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=jose.marchesi@oracle.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=mic@digikod.net \
--cc=mjguzik@gmail.com \
--cc=neil@brown.name \
--cc=paul@paul-moore.com \
--cc=serge@hallyn.com \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=utilityemal77@gmail.com \
--cc=viro@zeniv.linux.org.uk \
--cc=yonghong.song@linux.dev \
/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
all inboxes | Powered by JetHome®