From: Justin Suess <utilityemal77@gmail.com>
To: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>
Cc: Song Liu <song@kernel.org>, Chris Mason <mason@kernel.org>,
Xu Yunxiang <xyx2021@mail.ustc.edu.cn>,
Amery Hung <ameryhung@gmail.com>,
Christian Brauner <brauner@kernel.org>,
bpf@vger.kernel.org, Justin Suess <utilityemal77@gmail.com>
Subject: [PATCH bpf-next v3 5/5] selftests/bpf: Test __derives_ret return invalidation on argument release
Date: Fri, 23 Oct 2026 17:20:41 -0400 [thread overview]
Message-ID: <20261023212041.884996-6-utilityemal77@gmail.com> (raw)
In-Reply-To: <20261023212041.884996-1-utilityemal77@gmail.com>
A pointer a kfunc derives from a __derives_ret argument must not
outlive the reference that keeps the argument alive. Cover the inode
bpf_real_data_inode() returns for a file acquired from
bpf_get_task_exe_file(): a reject test dereferences it after
bpf_put_file(), an accept test before.
Annotate the argument of bpf_kfunc_call_test3() in bpf_testmod, which
returns its argument, and cover a socket acquired through a helper the
same way around bpf_sk_release().
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
.../testing/selftests/bpf/bpf_experimental.h | 9 ++++
.../selftests/bpf/prog_tests/verifier.c | 2 +
.../bpf/progs/verifier_derives_ret.c | 50 +++++++++++++++++++
.../selftests/bpf/progs/verifier_vfs_accept.c | 20 ++++++++
.../selftests/bpf/progs/verifier_vfs_reject.c | 22 ++++++++
.../selftests/bpf/test_kmods/bpf_testmod.c | 4 +-
.../bpf/test_kmods/bpf_testmod_kfunc.h | 2 +-
7 files changed, 106 insertions(+), 3 deletions(-)
create mode 100644 tools/testing/selftests/bpf/progs/verifier_derives_ret.c
diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
index 2893bf06ff25..e9dfd5d2e1ec 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -64,6 +64,15 @@ extern struct file *bpf_get_task_exe_file(struct task_struct *task) __ksym;
*/
extern void bpf_put_file(struct file *file) __ksym;
+/* Description
+ * Resolve the supplied file to the inode hosting its data. The supplied
+ * file must be trusted/referenced; the inode is valid only as long as
+ * the file is.
+ * Returns
+ * The inode hosting the file's data, or NULL.
+ */
+extern struct inode *bpf_real_data_inode(struct file *file) __ksym;
+
/* Description
* Resolve a pathname for the supplied path and store it in the supplied
* buffer. The supplied path must be trusted/referenced.
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index 04740ba37e91..ff6e6515ea48 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -45,6 +45,7 @@
#include "verifier_ctx_sk_msg.skel.h"
#include "verifier_d_path.skel.h"
#include "verifier_default_trusted_ptr.skel.h"
+#include "verifier_derives_ret.skel.h"
#include "verifier_direct_packet_access.skel.h"
#include "verifier_direct_stack_access_wraparound.skel.h"
#include "verifier_div0.skel.h"
@@ -237,6 +238,7 @@ void test_verifier_ctx(void) { RUN_TESTS(verifier_ctx); }
void test_verifier_ctx_sk_msg(void) { RUN(verifier_ctx_sk_msg); }
void test_verifier_d_path(void) { RUN(verifier_d_path); }
void test_verifier_default_trusted_ptr(void) { RUN_TESTS(verifier_default_trusted_ptr); }
+void test_verifier_derives_ret(void) { RUN_TESTS(verifier_derives_ret); }
void test_verifier_direct_packet_access(void) { RUN(verifier_direct_packet_access); }
void test_verifier_direct_stack_access_wraparound(void) { RUN(verifier_direct_stack_access_wraparound); }
void test_verifier_div0(void) { RUN(verifier_div0); }
diff --git a/tools/testing/selftests/bpf/progs/verifier_derives_ret.c b/tools/testing/selftests/bpf/progs/verifier_derives_ret.c
new file mode 100644
index 000000000000..041d2a656233
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_derives_ret.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Justin Suess */
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+#include "bpf_misc.h"
+#include "../test_kmods/bpf_testmod_kfunc.h"
+
+/* bpf_kfunc_call_test3() returns its __derives_ret argument. */
+
+SEC("tc")
+__success
+int derived_sock_used_before_release(struct __sk_buff *skb)
+{
+ struct bpf_sock_tuple tuple = {};
+ struct sock *derived;
+ struct bpf_sock *sk;
+ int state;
+
+ sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple.ipv4), BPF_F_CURRENT_NETNS, 0);
+ if (!sk)
+ return 0;
+
+ derived = bpf_kfunc_call_test3((struct sock *)sk);
+ state = derived->__sk_common.skc_state;
+ bpf_sk_release(sk);
+ return state;
+}
+
+SEC("tc")
+__failure __msg("invalid mem access 'scalar'")
+int derived_sock_outlives_release(struct __sk_buff *skb)
+{
+ struct bpf_sock_tuple tuple = {};
+ struct sock *derived;
+ struct bpf_sock *sk;
+
+ sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple.ipv4), BPF_F_CURRENT_NETNS, 0);
+ if (!sk)
+ return 0;
+
+ derived = bpf_kfunc_call_test3((struct sock *)sk);
+ bpf_sk_release(sk);
+
+ /* derived was pinned by sk's reference and died with it. */
+ return derived->__sk_common.skc_state;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c b/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c
index 34919abcff04..3f9e1f8fba58 100644
--- a/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c
+++ b/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c
@@ -124,4 +124,24 @@ int BPF_PROG(trusted_field_used_in_rcu_cs, struct linux_binprm *bprm)
return 0;
}
+SEC("lsm.s/file_open")
+__success
+int BPF_PROG(derived_inode_used_before_put)
+{
+ struct task_struct *task = bpf_get_current_task_btf();
+ struct file *file = bpf_get_task_exe_file(task);
+ struct inode *inode;
+ umode_t mode = 0;
+
+ if (!file)
+ return 0;
+
+ inode = bpf_real_data_inode(file);
+ if (inode)
+ mode = inode->i_mode;
+ bpf_put_file(file);
+ __sink(mode);
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
index 067b4f979902..df2fe54deeff 100644
--- a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
+++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
@@ -224,4 +224,26 @@ int BPF_PROG(trusted_field_escapes_rcu_cs, struct linux_binprm *bprm)
subprog_trusted_inode(inode);
return 0;
}
+
+SEC("lsm.s/file_open")
+__failure __msg("invalid mem access 'scalar'")
+int BPF_PROG(derived_inode_outlives_parent_reference)
+{
+ struct task_struct *task = bpf_get_current_task_btf();
+ struct file *file = bpf_get_task_exe_file(task);
+ struct inode *inode;
+
+ if (!file)
+ return 0;
+
+ inode = bpf_real_data_inode(file);
+ if (!inode) {
+ bpf_put_file(file);
+ return 0;
+ }
+ bpf_put_file(file);
+
+ /* inode was derived from file's reference and died with it. */
+ return inode->i_mode;
+}
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
index 6380f52f4dd2..5308daa2259d 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
@@ -1073,9 +1073,9 @@ __bpf_kfunc int bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b)
return a + b;
}
-__bpf_kfunc struct sock *bpf_kfunc_call_test3(struct sock *sk)
+__bpf_kfunc struct sock *bpf_kfunc_call_test3(struct sock *sk__derives_ret)
{
- return sk;
+ return sk__derives_ret;
}
__bpf_kfunc long noinline bpf_kfunc_call_test4(signed char a, short b, int c, long d)
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
index 3b810f1e438f..ccef296a9961 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
@@ -230,7 +230,7 @@ int bpf_testmod_ops3_call_test_nullable(void) __ksym;
__u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b,
__u32 c, __u64 d) __ksym;
int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym;
-struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym;
+struct sock *bpf_kfunc_call_test3(struct sock *sk__derives_ret) __ksym;
long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym;
int bpf_kfunc_call_test5(__u8 a, __u16 b, __u32 c) __ksym;
#ifdef __SIZEOF_INT128__
--
2.55.0
prev parent reply other threads:[~2026-10-23 21:21 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 21:20 [PATCH bpf-next v3 0/5] bpf: bound trusted fields and derived returns to their parent's lifetime Justin Suess
2026-10-23 21:20 ` [PATCH bpf-next v3 1/5] bpf: Don't apply the trusted field lists to an RCU-protected parent Justin Suess
2026-10-23 21:58 ` sashiko-bot
2026-10-23 21:20 ` [PATCH bpf-next v3 2/5] selftests/bpf: Test f_inode of an RCU-protected file Justin Suess
2026-10-23 21:20 ` [PATCH bpf-next v3 3/5] bpf: Add a __derives_ret kfunc argument annotation Justin Suess
2026-10-23 21:52 ` sashiko-bot
2026-10-23 21:20 ` [PATCH bpf-next v3 4/5] bpf: Bind the inode bpf_real_data_inode() returns to the file Justin Suess
2026-10-23 21:20 ` Justin Suess [this message]
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=20261023212041.884996-6-utilityemal77@gmail.com \
--to=utilityemal77@gmail.com \
--cc=ameryhung@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=mason@kernel.org \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
--cc=xyx2021@mail.ustc.edu.cn \
/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 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.