diff mbox series

[bpf-next,1/2] bpf: Relax KF_ACQUIRE kfuncs strict type matching constraint on non-zero offset pointers

Message ID AM6PR03MB584837A72DB98E45AE595A9799812@AM6PR03MB5848.eurprd03.prod.outlook.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series [bpf-next,1/2] bpf: Relax KF_ACQUIRE kfuncs strict type matching constraint on non-zero offset pointers | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 42 this patch: 42
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 13 of 13 maintainers
netdev/build_clang success Errors and warnings before: 43 this patch: 43
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 success Errors and warnings before: 53 this patch: 53
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 8 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-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-17 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-18 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-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-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 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-next-VM_Test-31 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-next-VM_Test-38 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-next-VM_Test-23 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-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-39 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-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc

Commit Message

Juntong Deng Aug. 16, 2024, 1:23 p.m. UTC
Currently the non-zero offset pointer constraint for KF_TRUSTED_ARGS
kfuncs has been relaxed in commit 605c96997d89 ("bpf: relax zero fixed
offset constraint on KF_TRUSTED_ARGS/KF_RCU"), which means that non-zero
offset does not affect whether a pointer is valid.

But currently we still cannot pass non-zero offset pointers to
KF_ACQUIRE kfuncs. This is because KF_ACQUIRE kfuncs requires strict
type matching, but non-zero offset does not change the type of pointer,
which causes the ebpf program to be rejected by the verifier.

This can cause some problems, one example is that bpf_skb_peek_tail
kfunc [0] cannot be implemented by just passing in non-zero offset
pointers.

This patch makes KF_ACQUIRE kfuncs not require strict type matching
on non-zero offset pointers.

[0]: https://lore.kernel.org/bpf/AM6PR03MB5848CA39CB4B7A4397D380B099B12@AM6PR03MB5848.eurprd03.prod.outlook.com/

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 kernel/bpf/verifier.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Alexei Starovoitov Aug. 21, 2024, 6:02 p.m. UTC | #1
On Fri, Aug 16, 2024 at 6:24 AM Juntong Deng <juntong.deng@outlook.com> wrote:
>
> Currently the non-zero offset pointer constraint for KF_TRUSTED_ARGS
> kfuncs has been relaxed in commit 605c96997d89 ("bpf: relax zero fixed
> offset constraint on KF_TRUSTED_ARGS/KF_RCU"), which means that non-zero
> offset does not affect whether a pointer is valid.
>
> But currently we still cannot pass non-zero offset pointers to
> KF_ACQUIRE kfuncs. This is because KF_ACQUIRE kfuncs requires strict
> type matching, but non-zero offset does not change the type of pointer,
> which causes the ebpf program to be rejected by the verifier.
>
> This can cause some problems, one example is that bpf_skb_peek_tail
> kfunc [0] cannot be implemented by just passing in non-zero offset
> pointers.
>
> This patch makes KF_ACQUIRE kfuncs not require strict type matching
> on non-zero offset pointers.
>
> [0]: https://lore.kernel.org/bpf/AM6PR03MB5848CA39CB4B7A4397D380B099B12@AM6PR03MB5848.eurprd03.prod.outlook.com/
>
> Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
> ---
>  kernel/bpf/verifier.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index ebec74c28ae3..3a14002d24a0 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11484,7 +11484,7 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
>          * btf_struct_ids_match() to walk the struct at the 0th offset, and
>          * resolve types.
>          */
> -       if (is_kfunc_acquire(meta) ||
> +       if ((is_kfunc_acquire(meta) && !reg->off) ||

Agree that relaxing is fine and calling acquire kfunc like:
  bpf_kfunc_nested_acquire_test(&sk->sk_write_queue);

should be allowed,
but above check is strange, since
if offsetof(&sk_write_queue) == 0
it will disallow calling a kfunc.
I mean if the field is the first in the outer struct this
condition will force strict type match which will fail, right?

So should we remove the above is_kfunc_acquire() check instead?

pw-bot: cr
Juntong Deng Aug. 28, 2024, 8:12 p.m. UTC | #2
On 8/21/24 19:02, Alexei Starovoitov wrote:
> On Fri, Aug 16, 2024 at 6:24 AM Juntong Deng <juntong.deng@outlook.com> wrote:
>>
>> Currently the non-zero offset pointer constraint for KF_TRUSTED_ARGS
>> kfuncs has been relaxed in commit 605c96997d89 ("bpf: relax zero fixed
>> offset constraint on KF_TRUSTED_ARGS/KF_RCU"), which means that non-zero
>> offset does not affect whether a pointer is valid.
>>
>> But currently we still cannot pass non-zero offset pointers to
>> KF_ACQUIRE kfuncs. This is because KF_ACQUIRE kfuncs requires strict
>> type matching, but non-zero offset does not change the type of pointer,
>> which causes the ebpf program to be rejected by the verifier.
>>
>> This can cause some problems, one example is that bpf_skb_peek_tail
>> kfunc [0] cannot be implemented by just passing in non-zero offset
>> pointers.
>>
>> This patch makes KF_ACQUIRE kfuncs not require strict type matching
>> on non-zero offset pointers.
>>
>> [0]: https://lore.kernel.org/bpf/AM6PR03MB5848CA39CB4B7A4397D380B099B12@AM6PR03MB5848.eurprd03.prod.outlook.com/
>>
>> Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
>> ---
>>   kernel/bpf/verifier.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index ebec74c28ae3..3a14002d24a0 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -11484,7 +11484,7 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
>>           * btf_struct_ids_match() to walk the struct at the 0th offset, and
>>           * resolve types.
>>           */
>> -       if (is_kfunc_acquire(meta) ||
>> +       if ((is_kfunc_acquire(meta) && !reg->off) ||
> 
> Agree that relaxing is fine and calling acquire kfunc like:
>    bpf_kfunc_nested_acquire_test(&sk->sk_write_queue);
> 
> should be allowed,
> but above check is strange, since
> if offsetof(&sk_write_queue) == 0
> it will disallow calling a kfunc.
> I mean if the field is the first in the outer struct this
> condition will force strict type match which will fail, right?
> 
> So should we remove the above is_kfunc_acquire() check instead?
> 
> pw-bot: cr

I agree that if strict type matching is not required for both zero
offset and non-zero pointers, then we can remove the strict type
matching for KF_ACQUIRE kfuncs.

I sent the version 2 patch set:
https://lore.kernel.org/bpf/AM6PR03MB5848FD2BD89BF0B6B5AA3B4C99952@AM6PR03MB5848.eurprd03.prod.outlook.com/T/#t
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ebec74c28ae3..3a14002d24a0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11484,7 +11484,7 @@  static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
 	 * btf_struct_ids_match() to walk the struct at the 0th offset, and
 	 * resolve types.
 	 */
-	if (is_kfunc_acquire(meta) ||
+	if ((is_kfunc_acquire(meta) && !reg->off) ||
 	    (is_kfunc_release(meta) && reg->ref_obj_id) ||
 	    btf_type_ids_nocast_alias(&env->log, reg_btf, reg_ref_id, meta->btf, ref_id))
 		strict_type_match = true;