diff mbox series

[bpf] bpf: relax zero fixed offset constraint on KF_TRUSTED_ARGS/KF_RCU

Message ID 20240709210939.1544011-1-mattbobrowski@google.com (mailing list archive)
State Accepted
Commit 605c96997d89c01c11bbddb4db820ede570581c7
Delegated to: BPF
Headers show
Series [bpf] bpf: relax zero fixed offset constraint on KF_TRUSTED_ARGS/KF_RCU | expand

Checks

Context Check Description
bpf/vmtest-bpf-PR success PR summary
bpf/vmtest-bpf-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-VM_Test-0 success Logs for Lint
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present fail Series targets non-next tree, but doesn't contain any Fixes tags
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 45 this patch: 45
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 10 maintainers not CCed: shuah@kernel.org yonghong.song@linux.dev linux-kselftest@vger.kernel.org mykolal@fb.com john.fastabend@gmail.com haoluo@google.com andreimatei1@gmail.com song@kernel.org laoar.shao@gmail.com martin.lau@linux.dev
netdev/build_clang fail Errors and warnings before: 36 this patch: 36
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 55 this patch: 55
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 62 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-VM_Test-13 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-VM_Test-15 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-VM_Test-17 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc

Commit Message

Matt Bobrowski July 9, 2024, 9:09 p.m. UTC
Currently, BPF kfuncs which accept trusted pointer arguments
i.e. those flagged as KF_TRUSTED_ARGS, KF_RCU, or KF_RELEASE, all
require an original/unmodified trusted pointer argument to be supplied
to them. By original/unmodified, it means that the backing register
holding the trusted pointer argument that is to be supplied to the BPF
kfunc must have its fixed offset set to zero, or else the BPF verifier
will outright reject the BPF program load. However, this zero fixed
offset constraint that is currently enforced by the BPF verifier onto
BPF kfuncs specifically flagged to accept KF_TRUSTED_ARGS or KF_RCU
trusted pointer arguments is rather unnecessary, and can limit their
usability in practice. Specifically, it completely eliminates the
possibility of constructing a derived trusted pointer from an original
trusted pointer. To put it simply, a derived pointer is a pointer
which points to one of the nested member fields of the object being
pointed to by the original trusted pointer.

This patch relaxes the zero fixed offset constraint that is enforced
upon BPF kfuncs which specifically accept KF_TRUSTED_ARGS, or KF_RCU
arguments. Although, the zero fixed offset constraint technically also
applies to BPF kfuncs accepting KF_RELEASE arguments, relaxing this
constraint for such BPF kfuncs has subtle and unwanted
side-effects. This was discovered by experimenting a little further
with an initial version of this patch series [0]. The primary issue
with relaxing the zero fixed offset constraint on BPF kfuncs accepting
KF_RELEASE arguments is that it'd would open up the opportunity for
BPF programs to supply both trusted pointers and derived trusted
pointers to them. For KF_RELEASE BPF kfuncs specifically, this could
be problematic as resources associated with the backing pointer could
be released by the backing BPF kfunc and cause instabilities for the
rest of the kernel.

With this new fixed offset semantic in-place for BPF kfuncs accepting
KF_TRUSTED_ARGS and KF_RCU arguments, we now have more flexibility
when it comes to the BPF kfuncs that we're able to introduce moving
forward.

Early discussions covering the possibility of relaxing the zero fixed
offset constraint can be found using the link below. This will provide
more context on where all this has stemmed from [1].

Notably, pre-existing tests have been updated such that they provide
coverage for the updated zero fixed offset
functionality. Specifically, the nested offset test was converted from
a negative to positive test as it was already designed to assert zero
fixed offset semantics of a KF_TRUSTED_ARGS BPF kfunc.

[0] https://lore.kernel.org/bpf/ZnA9ndnXKtHOuYMe@google.com/
[1] https://lore.kernel.org/bpf/ZhkbrM55MKQ0KeIV@google.com/

Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
---
 kernel/bpf/verifier.c                                    | 9 +++------
 tools/testing/selftests/bpf/progs/nested_trust_failure.c | 8 --------
 tools/testing/selftests/bpf/progs/nested_trust_success.c | 8 ++++++++
 tools/testing/selftests/bpf/verifier/calls.c             | 2 +-
 4 files changed, 12 insertions(+), 15 deletions(-)

Comments

Kumar Kartikeya Dwivedi July 9, 2024, 9:23 p.m. UTC | #1
On Tue, 9 Jul 2024 at 23:09, Matt Bobrowski <mattbobrowski@google.com> wrote:
>
> Currently, BPF kfuncs which accept trusted pointer arguments
> i.e. those flagged as KF_TRUSTED_ARGS, KF_RCU, or KF_RELEASE, all
> require an original/unmodified trusted pointer argument to be supplied
> to them. By original/unmodified, it means that the backing register
> holding the trusted pointer argument that is to be supplied to the BPF
> kfunc must have its fixed offset set to zero, or else the BPF verifier
> will outright reject the BPF program load. However, this zero fixed
> offset constraint that is currently enforced by the BPF verifier onto
> BPF kfuncs specifically flagged to accept KF_TRUSTED_ARGS or KF_RCU
> trusted pointer arguments is rather unnecessary, and can limit their
> usability in practice. Specifically, it completely eliminates the
> possibility of constructing a derived trusted pointer from an original
> trusted pointer. To put it simply, a derived pointer is a pointer
> which points to one of the nested member fields of the object being
> pointed to by the original trusted pointer.
>
> This patch relaxes the zero fixed offset constraint that is enforced
> upon BPF kfuncs which specifically accept KF_TRUSTED_ARGS, or KF_RCU
> arguments. Although, the zero fixed offset constraint technically also
> applies to BPF kfuncs accepting KF_RELEASE arguments, relaxing this
> constraint for such BPF kfuncs has subtle and unwanted
> side-effects. This was discovered by experimenting a little further
> with an initial version of this patch series [0]. The primary issue
> with relaxing the zero fixed offset constraint on BPF kfuncs accepting
> KF_RELEASE arguments is that it'd would open up the opportunity for
> BPF programs to supply both trusted pointers and derived trusted
> pointers to them. For KF_RELEASE BPF kfuncs specifically, this could
> be problematic as resources associated with the backing pointer could
> be released by the backing BPF kfunc and cause instabilities for the
> rest of the kernel.
>
> With this new fixed offset semantic in-place for BPF kfuncs accepting
> KF_TRUSTED_ARGS and KF_RCU arguments, we now have more flexibility
> when it comes to the BPF kfuncs that we're able to introduce moving
> forward.
>
> Early discussions covering the possibility of relaxing the zero fixed
> offset constraint can be found using the link below. This will provide
> more context on where all this has stemmed from [1].
>
> Notably, pre-existing tests have been updated such that they provide
> coverage for the updated zero fixed offset
> functionality. Specifically, the nested offset test was converted from
> a negative to positive test as it was already designed to assert zero
> fixed offset semantics of a KF_TRUSTED_ARGS BPF kfunc.
>
> [0] https://lore.kernel.org/bpf/ZnA9ndnXKtHOuYMe@google.com/
> [1] https://lore.kernel.org/bpf/ZhkbrM55MKQ0KeIV@google.com/
>
> Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
> ---

Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>

Though I'm not sure this is bpf material since it isn't a fix, it
might be better to base it against bpf-next.
patchwork-bot+netdevbpf@kernel.org July 10, 2024, 2:20 a.m. UTC | #2
Hello:

This patch was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Tue,  9 Jul 2024 21:09:39 +0000 you wrote:
> Currently, BPF kfuncs which accept trusted pointer arguments
> i.e. those flagged as KF_TRUSTED_ARGS, KF_RCU, or KF_RELEASE, all
> require an original/unmodified trusted pointer argument to be supplied
> to them. By original/unmodified, it means that the backing register
> holding the trusted pointer argument that is to be supplied to the BPF
> kfunc must have its fixed offset set to zero, or else the BPF verifier
> will outright reject the BPF program load. However, this zero fixed
> offset constraint that is currently enforced by the BPF verifier onto
> BPF kfuncs specifically flagged to accept KF_TRUSTED_ARGS or KF_RCU
> trusted pointer arguments is rather unnecessary, and can limit their
> usability in practice. Specifically, it completely eliminates the
> possibility of constructing a derived trusted pointer from an original
> trusted pointer. To put it simply, a derived pointer is a pointer
> which points to one of the nested member fields of the object being
> pointed to by the original trusted pointer.
> 
> [...]

Here is the summary with links:
  - [bpf] bpf: relax zero fixed offset constraint on KF_TRUSTED_ARGS/KF_RCU
    https://git.kernel.org/bpf/bpf-next/c/605c96997d89

You are awesome, thank you!
Matt Bobrowski July 10, 2024, 7:06 a.m. UTC | #3
On Tue, Jul 09, 2024 at 11:23:34PM +0200, Kumar Kartikeya Dwivedi wrote:
> On Tue, 9 Jul 2024 at 23:09, Matt Bobrowski <mattbobrowski@google.com> wrote:
> >
> > Currently, BPF kfuncs which accept trusted pointer arguments
> > i.e. those flagged as KF_TRUSTED_ARGS, KF_RCU, or KF_RELEASE, all
> > require an original/unmodified trusted pointer argument to be supplied
> > to them. By original/unmodified, it means that the backing register
> > holding the trusted pointer argument that is to be supplied to the BPF
> > kfunc must have its fixed offset set to zero, or else the BPF verifier
> > will outright reject the BPF program load. However, this zero fixed
> > offset constraint that is currently enforced by the BPF verifier onto
> > BPF kfuncs specifically flagged to accept KF_TRUSTED_ARGS or KF_RCU
> > trusted pointer arguments is rather unnecessary, and can limit their
> > usability in practice. Specifically, it completely eliminates the
> > possibility of constructing a derived trusted pointer from an original
> > trusted pointer. To put it simply, a derived pointer is a pointer
> > which points to one of the nested member fields of the object being
> > pointed to by the original trusted pointer.
> >
> > This patch relaxes the zero fixed offset constraint that is enforced
> > upon BPF kfuncs which specifically accept KF_TRUSTED_ARGS, or KF_RCU
> > arguments. Although, the zero fixed offset constraint technically also
> > applies to BPF kfuncs accepting KF_RELEASE arguments, relaxing this
> > constraint for such BPF kfuncs has subtle and unwanted
> > side-effects. This was discovered by experimenting a little further
> > with an initial version of this patch series [0]. The primary issue
> > with relaxing the zero fixed offset constraint on BPF kfuncs accepting
> > KF_RELEASE arguments is that it'd would open up the opportunity for
> > BPF programs to supply both trusted pointers and derived trusted
> > pointers to them. For KF_RELEASE BPF kfuncs specifically, this could
> > be problematic as resources associated with the backing pointer could
> > be released by the backing BPF kfunc and cause instabilities for the
> > rest of the kernel.
> >
> > With this new fixed offset semantic in-place for BPF kfuncs accepting
> > KF_TRUSTED_ARGS and KF_RCU arguments, we now have more flexibility
> > when it comes to the BPF kfuncs that we're able to introduce moving
> > forward.
> >
> > Early discussions covering the possibility of relaxing the zero fixed
> > offset constraint can be found using the link below. This will provide
> > more context on where all this has stemmed from [1].
> >
> > Notably, pre-existing tests have been updated such that they provide
> > coverage for the updated zero fixed offset
> > functionality. Specifically, the nested offset test was converted from
> > a negative to positive test as it was already designed to assert zero
> > fixed offset semantics of a KF_TRUSTED_ARGS BPF kfunc.
> >
> > [0] https://lore.kernel.org/bpf/ZnA9ndnXKtHOuYMe@google.com/
> > [1] https://lore.kernel.org/bpf/ZhkbrM55MKQ0KeIV@google.com/
> >
> > Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
> > ---
> 
> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> 
> Though I'm not sure this is bpf material since it isn't a fix, it
> might be better to base it against bpf-next.

Yes, sorry, this was based off bpf-next. I just happened to screw up
the subject prefix.

Thanks for the review! 

/M
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3d6306c363b7..c0263fb5ca4b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11335,7 +11335,9 @@  static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
 	    btf_type_ids_nocast_alias(&env->log, reg_btf, reg_ref_id, meta->btf, ref_id))
 		strict_type_match = true;
 
-	WARN_ON_ONCE(is_kfunc_trusted_args(meta) && reg->off);
+	WARN_ON_ONCE(is_kfunc_release(meta) &&
+		     (reg->off || !tnum_is_const(reg->var_off) ||
+		      reg->var_off.value));
 
 	reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id, &reg_ref_id);
 	reg_ref_tname = btf_name_by_offset(reg_btf, reg_ref_t->name_off);
@@ -11917,12 +11919,8 @@  static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
 					return -EINVAL;
 				}
 			}
-
 			fallthrough;
 		case KF_ARG_PTR_TO_CTX:
-			/* Trusted arguments have the same offset checks as release arguments */
-			arg_type |= OBJ_RELEASE;
-			break;
 		case KF_ARG_PTR_TO_DYNPTR:
 		case KF_ARG_PTR_TO_ITER:
 		case KF_ARG_PTR_TO_LIST_HEAD:
@@ -11935,7 +11933,6 @@  static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
 		case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
 		case KF_ARG_PTR_TO_CONST_STR:
 		case KF_ARG_PTR_TO_WORKQUEUE:
-			/* Trusted by default */
 			break;
 		default:
 			WARN_ON_ONCE(1);
diff --git a/tools/testing/selftests/bpf/progs/nested_trust_failure.c b/tools/testing/selftests/bpf/progs/nested_trust_failure.c
index ea39497f11ed..3568ec450100 100644
--- a/tools/testing/selftests/bpf/progs/nested_trust_failure.c
+++ b/tools/testing/selftests/bpf/progs/nested_trust_failure.c
@@ -31,14 +31,6 @@  int BPF_PROG(test_invalid_nested_user_cpus, struct task_struct *task, u64 clone_
 	return 0;
 }
 
-SEC("tp_btf/task_newtask")
-__failure __msg("R1 must have zero offset when passed to release func or trusted arg to kfunc")
-int BPF_PROG(test_invalid_nested_offset, struct task_struct *task, u64 clone_flags)
-{
-	bpf_cpumask_first_zero(&task->cpus_mask);
-	return 0;
-}
-
 /* Although R2 is of type sk_buff but sock_common is expected, we will hit untrusted ptr first. */
 SEC("tp_btf/tcp_probe")
 __failure __msg("R2 type=untrusted_ptr_ expected=ptr_, trusted_ptr_, rcu_ptr_")
diff --git a/tools/testing/selftests/bpf/progs/nested_trust_success.c b/tools/testing/selftests/bpf/progs/nested_trust_success.c
index 833840bffd3b..2b66953ca82e 100644
--- a/tools/testing/selftests/bpf/progs/nested_trust_success.c
+++ b/tools/testing/selftests/bpf/progs/nested_trust_success.c
@@ -32,3 +32,11 @@  int BPF_PROG(test_skb_field, struct sock *sk, struct sk_buff *skb)
 	bpf_sk_storage_get(&sk_storage_map, skb->sk, 0, 0);
 	return 0;
 }
+
+SEC("tp_btf/task_newtask")
+__success
+int BPF_PROG(test_nested_offset, struct task_struct *task, u64 clone_flags)
+{
+	bpf_cpumask_first_zero(&task->cpus_mask);
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index ab25a81fd3a1..d76ef2018859 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -76,7 +76,7 @@ 
 	},
 	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 	.result = REJECT,
-	.errstr = "R1 must have zero offset when passed to release func or trusted arg to kfunc",
+	.errstr = "arg#0 expected pointer to ctx, but got PTR",
 	.fixup_kfunc_btf_id = {
 		{ "bpf_kfunc_call_test_pass_ctx", 2 },
 	},