Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'bpf-make-trusted-args-nullable'

Vadim Fedorenko says:

====================
bpf: make trusted args nullable

Current verifier checks for the arg to be nullable after checking for
certain pointer types. It prevents programs to pass NULL to kfunc args
even if they are marked as nullable. This patchset adjusts verifier and
changes bpf crypto kfuncs to allow null for IV parameter which is
optional for some ciphers. Benchmark shows ~4% improvements when there
is no need to initialise 0-sized dynptr.

v3:
- add special selftest for nullable parameters
v2:
- adjust kdoc accordingly
====================

Link: https://lore.kernel.org/r/20240613211817.1551967-1-vadfed@meta.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+85 -34
+13 -13
kernel/bpf/crypto.c
··· 275 275 if (__bpf_dynptr_is_rdonly(dst)) 276 276 return -EINVAL; 277 277 278 - siv_len = __bpf_dynptr_size(siv); 278 + siv_len = siv ? __bpf_dynptr_size(siv) : 0; 279 279 src_len = __bpf_dynptr_size(src); 280 280 dst_len = __bpf_dynptr_size(dst); 281 281 if (!src_len || !dst_len) ··· 303 303 304 304 /** 305 305 * bpf_crypto_decrypt() - Decrypt buffer using configured context and IV provided. 306 - * @ctx: The crypto context being used. The ctx must be a trusted pointer. 307 - * @src: bpf_dynptr to the encrypted data. Must be a trusted pointer. 308 - * @dst: bpf_dynptr to the buffer where to store the result. Must be a trusted pointer. 309 - * @siv: bpf_dynptr to IV data and state data to be used by decryptor. 306 + * @ctx: The crypto context being used. The ctx must be a trusted pointer. 307 + * @src: bpf_dynptr to the encrypted data. Must be a trusted pointer. 308 + * @dst: bpf_dynptr to the buffer where to store the result. Must be a trusted pointer. 309 + * @siv__nullable: bpf_dynptr to IV data and state data to be used by decryptor. May be NULL. 310 310 * 311 311 * Decrypts provided buffer using IV data and the crypto context. Crypto context must be configured. 312 312 */ 313 313 __bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx, 314 314 const struct bpf_dynptr *src, 315 315 const struct bpf_dynptr *dst, 316 - const struct bpf_dynptr *siv) 316 + const struct bpf_dynptr *siv__nullable) 317 317 { 318 318 const struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src; 319 319 const struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst; 320 - const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv; 320 + const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv__nullable; 321 321 322 322 return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, true); 323 323 } 324 324 325 325 /** 326 326 * bpf_crypto_encrypt() - Encrypt buffer using configured context and IV provided. 327 - * @ctx: The crypto context being used. The ctx must be a trusted pointer. 328 - * @src: bpf_dynptr to the plain data. Must be a trusted pointer. 329 - * @dst: bpf_dynptr to buffer where to store the result. Must be a trusted pointer. 330 - * @siv: bpf_dynptr to IV data and state data to be used by decryptor. 327 + * @ctx: The crypto context being used. The ctx must be a trusted pointer. 328 + * @src: bpf_dynptr to the plain data. Must be a trusted pointer. 329 + * @dst: bpf_dynptr to the buffer where to store the result. Must be a trusted pointer. 330 + * @siv__nullable: bpf_dynptr to IV data and state data to be used by decryptor. May be NULL. 331 331 * 332 332 * Encrypts provided buffer using IV data and the crypto context. Crypto context must be configured. 333 333 */ 334 334 __bpf_kfunc int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx, 335 335 const struct bpf_dynptr *src, 336 336 const struct bpf_dynptr *dst, 337 - const struct bpf_dynptr *siv) 337 + const struct bpf_dynptr *siv__nullable) 338 338 { 339 339 const struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src; 340 340 const struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst; 341 - const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv; 341 + const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv__nullable; 342 342 343 343 return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, false); 344 344 }
+3 -3
kernel/bpf/verifier.c
··· 11187 11187 if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno)) 11188 11188 return KF_ARG_PTR_TO_CTX; 11189 11189 11190 + if (is_kfunc_arg_nullable(meta->btf, &args[argno]) && register_is_null(reg)) 11191 + return KF_ARG_PTR_TO_NULL; 11192 + 11190 11193 if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno])) 11191 11194 return KF_ARG_PTR_TO_ALLOC_BTF_ID; 11192 11195 ··· 11234 11231 11235 11232 if (is_kfunc_arg_callback(env, meta->btf, &args[argno])) 11236 11233 return KF_ARG_PTR_TO_CALLBACK; 11237 - 11238 - if (is_kfunc_arg_nullable(meta->btf, &args[argno]) && register_is_null(reg)) 11239 - return KF_ARG_PTR_TO_NULL; 11240 11234 11241 11235 if (argno + 1 < nargs && 11242 11236 (is_kfunc_arg_mem_size(meta->btf, &args[argno + 1], &regs[regno + 1]) ||
+6
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
··· 154 154 { 155 155 } 156 156 157 + __bpf_kfunc void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr, 158 + struct bpf_dynptr *ptr__nullable) 159 + { 160 + } 161 + 157 162 struct bpf_testmod_btf_type_tag_1 { 158 163 int a; 159 164 }; ··· 368 363 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL) 369 364 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY) 370 365 BTF_ID_FLAGS(func, bpf_kfunc_common_test) 366 + BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test) 371 367 BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids) 372 368 373 369 static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = {
+1
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h
··· 134 134 int bpf_kfunc_call_kernel_getsockname(struct addr_args *args) __ksym; 135 135 int bpf_kfunc_call_kernel_getpeername(struct addr_args *args) __ksym; 136 136 137 + void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr, struct bpf_dynptr *ptr__nullable) __ksym; 137 138 #endif /* _BPF_TESTMOD_KFUNC_H */
+11
tools/testing/selftests/bpf/prog_tests/kfunc_param_nullable.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Copyright (c) 2024 Meta Platforms, Inc */ 4 + 5 + #include <test_progs.h> 6 + #include "test_kfunc_param_nullable.skel.h" 7 + 8 + void test_kfunc_param_nullable(void) 9 + { 10 + RUN_TESTS(test_kfunc_param_nullable); 11 + }
+4 -6
tools/testing/selftests/bpf/progs/crypto_bench.c
··· 57 57 { 58 58 struct __crypto_ctx_value *v; 59 59 struct bpf_crypto_ctx *ctx; 60 - struct bpf_dynptr psrc, pdst, iv; 60 + struct bpf_dynptr psrc, pdst; 61 61 62 62 v = crypto_ctx_value_lookup(); 63 63 if (!v) { ··· 73 73 74 74 bpf_dynptr_from_skb(skb, 0, &psrc); 75 75 bpf_dynptr_from_mem(dst, len, 0, &pdst); 76 - bpf_dynptr_from_mem(dst, 0, 0, &iv); 77 76 78 - status = bpf_crypto_encrypt(ctx, &psrc, &pdst, &iv); 77 + status = bpf_crypto_encrypt(ctx, &psrc, &pdst, NULL); 79 78 __sync_add_and_fetch(&hits, 1); 80 79 81 80 return 0; ··· 83 84 SEC("tc") 84 85 int crypto_decrypt(struct __sk_buff *skb) 85 86 { 86 - struct bpf_dynptr psrc, pdst, iv; 87 + struct bpf_dynptr psrc, pdst; 87 88 struct __crypto_ctx_value *v; 88 89 struct bpf_crypto_ctx *ctx; 89 90 ··· 97 98 98 99 bpf_dynptr_from_skb(skb, 0, &psrc); 99 100 bpf_dynptr_from_mem(dst, len, 0, &pdst); 100 - bpf_dynptr_from_mem(dst, 0, 0, &iv); 101 101 102 - status = bpf_crypto_decrypt(ctx, &psrc, &pdst, &iv); 102 + status = bpf_crypto_decrypt(ctx, &psrc, &pdst, NULL); 103 103 __sync_add_and_fetch(&hits, 1); 104 104 105 105 return 0;
+4 -12
tools/testing/selftests/bpf/progs/crypto_sanity.c
··· 89 89 { 90 90 struct __crypto_ctx_value *v; 91 91 struct bpf_crypto_ctx *ctx; 92 - struct bpf_dynptr psrc, pdst, iv; 92 + struct bpf_dynptr psrc, pdst; 93 93 int err; 94 94 95 95 err = skb_dynptr_validate(skb, &psrc); ··· 114 114 * production code, a percpu map should be used to store the result. 115 115 */ 116 116 bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst); 117 - /* iv dynptr has to be initialized with 0 size, but proper memory region 118 - * has to be provided anyway 119 - */ 120 - bpf_dynptr_from_mem(dst, 0, 0, &iv); 121 117 122 - status = bpf_crypto_decrypt(ctx, &psrc, &pdst, &iv); 118 + status = bpf_crypto_decrypt(ctx, &psrc, &pdst, NULL); 123 119 124 120 return TC_ACT_SHOT; 125 121 } ··· 125 129 { 126 130 struct __crypto_ctx_value *v; 127 131 struct bpf_crypto_ctx *ctx; 128 - struct bpf_dynptr psrc, pdst, iv; 132 + struct bpf_dynptr psrc, pdst; 129 133 int err; 130 134 131 135 status = 0; ··· 152 156 * production code, a percpu map should be used to store the result. 153 157 */ 154 158 bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst); 155 - /* iv dynptr has to be initialized with 0 size, but proper memory region 156 - * has to be provided anyway 157 - */ 158 - bpf_dynptr_from_mem(dst, 0, 0, &iv); 159 159 160 - status = bpf_crypto_encrypt(ctx, &psrc, &pdst, &iv); 160 + status = bpf_crypto_encrypt(ctx, &psrc, &pdst, NULL); 161 161 162 162 return TC_ACT_SHOT; 163 163 }
+43
tools/testing/selftests/bpf/progs/test_kfunc_param_nullable.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc */ 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_helpers.h> 5 + #include "bpf_misc.h" 6 + #include "bpf_kfuncs.h" 7 + #include "../bpf_testmod/bpf_testmod_kfunc.h" 8 + 9 + SEC("tc") 10 + int kfunc_dynptr_nullable_test1(struct __sk_buff *skb) 11 + { 12 + struct bpf_dynptr data; 13 + 14 + bpf_dynptr_from_skb(skb, 0, &data); 15 + bpf_kfunc_dynptr_test(&data, NULL); 16 + 17 + return 0; 18 + } 19 + 20 + SEC("tc") 21 + int kfunc_dynptr_nullable_test2(struct __sk_buff *skb) 22 + { 23 + struct bpf_dynptr data; 24 + 25 + bpf_dynptr_from_skb(skb, 0, &data); 26 + bpf_kfunc_dynptr_test(&data, &data); 27 + 28 + return 0; 29 + } 30 + 31 + SEC("tc") 32 + __failure __msg("expected pointer to stack or dynptr_ptr") 33 + int kfunc_dynptr_nullable_test3(struct __sk_buff *skb) 34 + { 35 + struct bpf_dynptr data; 36 + 37 + bpf_dynptr_from_skb(skb, 0, &data); 38 + bpf_kfunc_dynptr_test(NULL, &data); 39 + 40 + return 0; 41 + } 42 + 43 + char _license[] SEC("license") = "GPL";