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

bpf: Refactor ARG_PTR_TO_DYNPTR checks into process_dynptr_func

ARG_PTR_TO_DYNPTR is akin to ARG_PTR_TO_TIMER, ARG_PTR_TO_KPTR, where
the underlying register type is subjected to more special checks to
determine the type of object represented by the pointer and its state
consistency.

Move dynptr checks to their own 'process_dynptr_func' function so that
is consistent and in-line with existing code. This also makes it easier
to reuse this code for kfunc handling.

Then, reuse this consolidated function in kfunc dynptr handling too.
Note that for kfuncs, the arg_type constraint of DYNPTR_TYPE_LOCAL has
been lifted.

Acked-by: David Vernet <void@manifault.com>
Acked-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20221207204141.308952-2-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kumar Kartikeya Dwivedi and committed by
Alexei Starovoitov
6b75bd3d 6798152b

+75 -86
+3 -5
include/linux/bpf_verifier.h
··· 615 615 enum bpf_arg_type arg_type); 616 616 int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg, 617 617 u32 regno, u32 mem_size); 618 - bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, 619 - struct bpf_reg_state *reg); 620 - bool is_dynptr_type_expected(struct bpf_verifier_env *env, 621 - struct bpf_reg_state *reg, 622 - enum bpf_arg_type arg_type); 618 + struct bpf_call_arg_meta; 619 + int process_dynptr_func(struct bpf_verifier_env *env, int regno, 620 + enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta); 623 621 624 622 /* this lives here instead of in bpf.h because it needs to dereference tgt_prog */ 625 623 static inline u64 bpf_trampoline_compute_key(const struct bpf_prog *tgt_prog,
+70 -64
kernel/bpf/verifier.c
··· 810 810 return true; 811 811 } 812 812 813 - bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, 814 - struct bpf_reg_state *reg) 813 + static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg) 815 814 { 816 815 struct bpf_func_state *state = func(env, reg); 817 816 int spi = get_spi(reg->off); ··· 829 830 return true; 830 831 } 831 832 832 - bool is_dynptr_type_expected(struct bpf_verifier_env *env, 833 - struct bpf_reg_state *reg, 834 - enum bpf_arg_type arg_type) 833 + static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg, 834 + enum bpf_arg_type arg_type) 835 835 { 836 836 struct bpf_func_state *state = func(env, reg); 837 837 enum bpf_dynptr_type dynptr_type; ··· 5857 5859 return 0; 5858 5860 } 5859 5861 5862 + int process_dynptr_func(struct bpf_verifier_env *env, int regno, 5863 + enum bpf_arg_type arg_type, 5864 + struct bpf_call_arg_meta *meta) 5865 + { 5866 + struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno]; 5867 + 5868 + /* We only need to check for initialized / uninitialized helper 5869 + * dynptr args if the dynptr is not PTR_TO_DYNPTR, as the 5870 + * assumption is that if it is, that a helper function 5871 + * initialized the dynptr on behalf of the BPF program. 5872 + */ 5873 + if (base_type(reg->type) == PTR_TO_DYNPTR) 5874 + return 0; 5875 + if (arg_type & MEM_UNINIT) { 5876 + if (!is_dynptr_reg_valid_uninit(env, reg)) { 5877 + verbose(env, "Dynptr has to be an uninitialized dynptr\n"); 5878 + return -EINVAL; 5879 + } 5880 + 5881 + /* We only support one dynptr being uninitialized at the moment, 5882 + * which is sufficient for the helper functions we have right now. 5883 + */ 5884 + if (meta->uninit_dynptr_regno) { 5885 + verbose(env, "verifier internal error: multiple uninitialized dynptr args\n"); 5886 + return -EFAULT; 5887 + } 5888 + 5889 + meta->uninit_dynptr_regno = regno; 5890 + } else { 5891 + if (!is_dynptr_reg_valid_init(env, reg)) { 5892 + verbose(env, 5893 + "Expected an initialized dynptr as arg #%d\n", 5894 + regno); 5895 + return -EINVAL; 5896 + } 5897 + 5898 + if (!is_dynptr_type_expected(env, reg, arg_type)) { 5899 + const char *err_extra = ""; 5900 + 5901 + switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { 5902 + case DYNPTR_TYPE_LOCAL: 5903 + err_extra = "local"; 5904 + break; 5905 + case DYNPTR_TYPE_RINGBUF: 5906 + err_extra = "ringbuf"; 5907 + break; 5908 + default: 5909 + err_extra = "<unknown>"; 5910 + break; 5911 + } 5912 + verbose(env, 5913 + "Expected a dynptr of type %s as arg #%d\n", 5914 + err_extra, regno); 5915 + return -EINVAL; 5916 + } 5917 + } 5918 + return 0; 5919 + } 5920 + 5860 5921 static bool arg_type_is_mem_size(enum bpf_arg_type type) 5861 5922 { 5862 5923 return type == ARG_CONST_SIZE || ··· 6447 6390 err = check_mem_size_reg(env, reg, regno, true, meta); 6448 6391 break; 6449 6392 case ARG_PTR_TO_DYNPTR: 6450 - /* We only need to check for initialized / uninitialized helper 6451 - * dynptr args if the dynptr is not PTR_TO_DYNPTR, as the 6452 - * assumption is that if it is, that a helper function 6453 - * initialized the dynptr on behalf of the BPF program. 6454 - */ 6455 - if (base_type(reg->type) == PTR_TO_DYNPTR) 6456 - break; 6457 - if (arg_type & MEM_UNINIT) { 6458 - if (!is_dynptr_reg_valid_uninit(env, reg)) { 6459 - verbose(env, "Dynptr has to be an uninitialized dynptr\n"); 6460 - return -EINVAL; 6461 - } 6462 - 6463 - /* We only support one dynptr being uninitialized at the moment, 6464 - * which is sufficient for the helper functions we have right now. 6465 - */ 6466 - if (meta->uninit_dynptr_regno) { 6467 - verbose(env, "verifier internal error: multiple uninitialized dynptr args\n"); 6468 - return -EFAULT; 6469 - } 6470 - 6471 - meta->uninit_dynptr_regno = regno; 6472 - } else if (!is_dynptr_reg_valid_init(env, reg)) { 6473 - verbose(env, 6474 - "Expected an initialized dynptr as arg #%d\n", 6475 - arg + 1); 6476 - return -EINVAL; 6477 - } else if (!is_dynptr_type_expected(env, reg, arg_type)) { 6478 - const char *err_extra = ""; 6479 - 6480 - switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { 6481 - case DYNPTR_TYPE_LOCAL: 6482 - err_extra = "local"; 6483 - break; 6484 - case DYNPTR_TYPE_RINGBUF: 6485 - err_extra = "ringbuf"; 6486 - break; 6487 - default: 6488 - err_extra = "<unknown>"; 6489 - break; 6490 - } 6491 - verbose(env, 6492 - "Expected a dynptr of type %s as arg #%d\n", 6493 - err_extra, arg + 1); 6494 - return -EINVAL; 6495 - } 6393 + if (process_dynptr_func(env, regno, arg_type, meta)) 6394 + return -EACCES; 6496 6395 break; 6497 6396 case ARG_CONST_ALLOC_SIZE_OR_ZERO: 6498 6397 if (!tnum_is_const(reg->var_off)) { ··· 8842 8829 return ret; 8843 8830 break; 8844 8831 case KF_ARG_PTR_TO_DYNPTR: 8845 - if (reg->type != PTR_TO_STACK) { 8846 - verbose(env, "arg#%d expected pointer to stack\n", i); 8832 + if (reg->type != PTR_TO_STACK && 8833 + reg->type != PTR_TO_DYNPTR) { 8834 + verbose(env, "arg#%d expected pointer to stack or dynptr_ptr\n", i); 8847 8835 return -EINVAL; 8848 8836 } 8849 8837 8850 - if (!is_dynptr_reg_valid_init(env, reg)) { 8851 - verbose(env, "arg#%d pointer type %s %s must be valid and initialized\n", 8852 - i, btf_type_str(ref_t), ref_tname); 8853 - return -EINVAL; 8854 - } 8855 - 8856 - if (!is_dynptr_type_expected(env, reg, ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL)) { 8857 - verbose(env, "arg#%d pointer type %s %s points to unsupported dynamic pointer type\n", 8858 - i, btf_type_str(ref_t), ref_tname); 8859 - return -EINVAL; 8860 - } 8838 + ret = process_dynptr_func(env, regno, ARG_PTR_TO_DYNPTR, NULL); 8839 + if (ret < 0) 8840 + return ret; 8861 8841 break; 8862 8842 case KF_ARG_PTR_TO_LIST_HEAD: 8863 8843 if (reg->type != PTR_TO_MAP_VALUE &&
+2 -5
tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c
··· 18 18 const char *expected_verifier_err_msg; 19 19 int expected_runtime_err; 20 20 } kfunc_dynptr_tests[] = { 21 - {"dynptr_type_not_supp", 22 - "arg#0 pointer type STRUCT bpf_dynptr_kern points to unsupported dynamic pointer type", 0}, 23 - {"not_valid_dynptr", 24 - "arg#0 pointer type STRUCT bpf_dynptr_kern must be valid and initialized", 0}, 25 - {"not_ptr_to_stack", "arg#0 expected pointer to stack", 0}, 21 + {"not_valid_dynptr", "Expected an initialized dynptr as arg #1", 0}, 22 + {"not_ptr_to_stack", "arg#0 expected pointer to stack or dynptr_ptr", 0}, 26 23 {"dynptr_data_null", NULL, -EBADMSG}, 27 24 }; 28 25
-12
tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
··· 33 33 char _license[] SEC("license") = "GPL"; 34 34 35 35 SEC("?lsm.s/bpf") 36 - int BPF_PROG(dynptr_type_not_supp, int cmd, union bpf_attr *attr, 37 - unsigned int size) 38 - { 39 - char write_data[64] = "hello there, world!!"; 40 - struct bpf_dynptr ptr; 41 - 42 - bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); 43 - 44 - return bpf_verify_pkcs7_signature(&ptr, &ptr, NULL); 45 - } 46 - 47 - SEC("?lsm.s/bpf") 48 36 int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size) 49 37 { 50 38 unsigned long val;