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

Merge branch 'support-passing-bpf-iterator-to-kfuncs'

Andrii Nakryiko says:

====================
Support passing BPF iterator to kfuncs

Add support for passing BPF iterator state to any kfunc. Such kfunc has to
declare such argument with valid `struct bpf_iter_<type> *` type and should
use "__iter" suffix in argument name, following the established suffix-based
convention. We add a simple test/demo iterator getter in bpf_testmod.
====================

Link: https://lore.kernel.org/r/20240808232230.2848712-1-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+127 -29
+5
include/linux/btf.h
··· 580 580 int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type); 581 581 bool btf_types_are_same(const struct btf *btf1, u32 id1, 582 582 const struct btf *btf2, u32 id2); 583 + int btf_check_iter_arg(struct btf *btf, const struct btf_type *func, int arg_idx); 583 584 #else 584 585 static inline const struct btf_type *btf_type_by_id(const struct btf *btf, 585 586 u32 type_id) ··· 654 653 const struct btf *btf2, u32 id2) 655 654 { 656 655 return false; 656 + } 657 + static inline int btf_check_iter_arg(struct btf *btf, const struct btf_type *func, int arg_idx) 658 + { 659 + return -EOPNOTSUPP; 657 660 } 658 661 #endif 659 662
+36 -14
kernel/bpf/btf.c
··· 8047 8047 BTF_TRACING_TYPE_xxx 8048 8048 #undef BTF_TRACING_TYPE 8049 8049 8050 + /* Validate well-formedness of iter argument type. 8051 + * On success, return positive BTF ID of iter state's STRUCT type. 8052 + * On error, negative error is returned. 8053 + */ 8054 + int btf_check_iter_arg(struct btf *btf, const struct btf_type *func, int arg_idx) 8055 + { 8056 + const struct btf_param *arg; 8057 + const struct btf_type *t; 8058 + const char *name; 8059 + int btf_id; 8060 + 8061 + if (btf_type_vlen(func) <= arg_idx) 8062 + return -EINVAL; 8063 + 8064 + arg = &btf_params(func)[arg_idx]; 8065 + t = btf_type_skip_modifiers(btf, arg->type, NULL); 8066 + if (!t || !btf_type_is_ptr(t)) 8067 + return -EINVAL; 8068 + t = btf_type_skip_modifiers(btf, t->type, &btf_id); 8069 + if (!t || !__btf_type_is_struct(t)) 8070 + return -EINVAL; 8071 + 8072 + name = btf_name_by_offset(btf, t->name_off); 8073 + if (!name || strncmp(name, ITER_PREFIX, sizeof(ITER_PREFIX) - 1)) 8074 + return -EINVAL; 8075 + 8076 + return btf_id; 8077 + } 8078 + 8050 8079 static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name, 8051 8080 const struct btf_type *func, u32 func_flags) 8052 8081 { 8053 8082 u32 flags = func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY); 8054 - const char *name, *sfx, *iter_name; 8055 - const struct btf_param *arg; 8083 + const char *sfx, *iter_name; 8056 8084 const struct btf_type *t; 8057 8085 char exp_name[128]; 8058 8086 u32 nr_args; 8087 + int btf_id; 8059 8088 8060 8089 /* exactly one of KF_ITER_{NEW,NEXT,DESTROY} can be set */ 8061 8090 if (!flags || (flags & (flags - 1))) ··· 8095 8066 if (nr_args < 1) 8096 8067 return -EINVAL; 8097 8068 8098 - arg = &btf_params(func)[0]; 8099 - t = btf_type_skip_modifiers(btf, arg->type, NULL); 8100 - if (!t || !btf_type_is_ptr(t)) 8101 - return -EINVAL; 8102 - t = btf_type_skip_modifiers(btf, t->type, NULL); 8103 - if (!t || !__btf_type_is_struct(t)) 8104 - return -EINVAL; 8105 - 8106 - name = btf_name_by_offset(btf, t->name_off); 8107 - if (!name || strncmp(name, ITER_PREFIX, sizeof(ITER_PREFIX) - 1)) 8108 - return -EINVAL; 8069 + btf_id = btf_check_iter_arg(btf, func, 0); 8070 + if (btf_id < 0) 8071 + return btf_id; 8109 8072 8110 8073 /* sizeof(struct bpf_iter_<type>) should be a multiple of 8 to 8111 8074 * fit nicely in stack slots 8112 8075 */ 8076 + t = btf_type_by_id(btf, btf_id); 8113 8077 if (t->size == 0 || (t->size % 8)) 8114 8078 return -EINVAL; 8115 8079 8116 8080 /* validate bpf_iter_<type>_{new,next,destroy}(struct bpf_iter_<type> *) 8117 8081 * naming pattern 8118 8082 */ 8119 - iter_name = name + sizeof(ITER_PREFIX) - 1; 8083 + iter_name = btf_name_by_offset(btf, t->name_off) + sizeof(ITER_PREFIX) - 1; 8120 8084 if (flags & KF_ITER_NEW) 8121 8085 sfx = "new"; 8122 8086 else if (flags & KF_ITER_NEXT)
+24 -11
kernel/bpf/verifier.c
··· 7970 7970 return meta->kfunc_flags & KF_ITER_DESTROY; 7971 7971 } 7972 7972 7973 - static bool is_kfunc_arg_iter(struct bpf_kfunc_call_arg_meta *meta, int arg) 7973 + static bool is_kfunc_arg_iter(struct bpf_kfunc_call_arg_meta *meta, int arg_idx, 7974 + const struct btf_param *arg) 7974 7975 { 7975 7976 /* btf_check_iter_kfuncs() guarantees that first argument of any iter 7976 7977 * kfunc is iter state pointer 7977 7978 */ 7978 - return arg == 0 && is_iter_kfunc(meta); 7979 + if (is_iter_kfunc(meta)) 7980 + return arg_idx == 0; 7981 + 7982 + /* iter passed as an argument to a generic kfunc */ 7983 + return btf_param_match_suffix(meta->btf, arg, "__iter"); 7979 7984 } 7980 7985 7981 7986 static int process_iter_arg(struct bpf_verifier_env *env, int regno, int insn_idx, ··· 7988 7983 { 7989 7984 struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno]; 7990 7985 const struct btf_type *t; 7991 - const struct btf_param *arg; 7992 - int spi, err, i, nr_slots; 7993 - u32 btf_id; 7986 + int spi, err, i, nr_slots, btf_id; 7994 7987 7995 - /* btf_check_iter_kfuncs() ensures we don't need to validate anything here */ 7996 - arg = &btf_params(meta->func_proto)[0]; 7997 - t = btf_type_skip_modifiers(meta->btf, arg->type, NULL); /* PTR */ 7998 - t = btf_type_skip_modifiers(meta->btf, t->type, &btf_id); /* STRUCT */ 7988 + /* For iter_{new,next,destroy} functions, btf_check_iter_kfuncs() 7989 + * ensures struct convention, so we wouldn't need to do any BTF 7990 + * validation here. But given iter state can be passed as a parameter 7991 + * to any kfunc, if arg has "__iter" suffix, we need to be a bit more 7992 + * conservative here. 7993 + */ 7994 + btf_id = btf_check_iter_arg(meta->btf, meta->func_proto, regno - 1); 7995 + if (btf_id < 0) { 7996 + verbose(env, "expected valid iter pointer as arg #%d\n", regno); 7997 + return -EINVAL; 7998 + } 7999 + t = btf_type_by_id(meta->btf, btf_id); 7999 8000 nr_slots = t->size / BPF_REG_SIZE; 8000 8001 8001 8002 if (is_iter_new_kfunc(meta)) { ··· 8023 8012 if (err) 8024 8013 return err; 8025 8014 } else { 8026 - /* iter_next() or iter_destroy() expect initialized iter state*/ 8015 + /* iter_next() or iter_destroy(), as well as any kfunc 8016 + * accepting iter argument, expect initialized iter state 8017 + */ 8027 8018 err = is_iter_reg_valid_init(env, reg, meta->btf, btf_id, nr_slots); 8028 8019 switch (err) { 8029 8020 case 0: ··· 11395 11382 if (is_kfunc_arg_dynptr(meta->btf, &args[argno])) 11396 11383 return KF_ARG_PTR_TO_DYNPTR; 11397 11384 11398 - if (is_kfunc_arg_iter(meta, argno)) 11385 + if (is_kfunc_arg_iter(meta, argno, &args[argno])) 11399 11386 return KF_ARG_PTR_TO_ITER; 11400 11387 11401 11388 if (is_kfunc_arg_list_head(meta->btf, &args[argno]))
+12 -4
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
··· 141 141 142 142 __bpf_kfunc int bpf_iter_testmod_seq_new(struct bpf_iter_testmod_seq *it, s64 value, int cnt) 143 143 { 144 - if (cnt < 0) { 145 - it->cnt = 0; 144 + it->cnt = cnt; 145 + 146 + if (cnt < 0) 146 147 return -EINVAL; 147 - } 148 148 149 149 it->value = value; 150 - it->cnt = cnt; 151 150 152 151 return 0; 153 152 } ··· 159 160 it->cnt--; 160 161 161 162 return &it->value; 163 + } 164 + 165 + __bpf_kfunc s64 bpf_iter_testmod_seq_value(int val, struct bpf_iter_testmod_seq* it__iter) 166 + { 167 + if (it__iter->cnt < 0) 168 + return 0; 169 + 170 + return val + it__iter->value; 162 171 } 163 172 164 173 __bpf_kfunc void bpf_iter_testmod_seq_destroy(struct bpf_iter_testmod_seq *it) ··· 538 531 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_new, KF_ITER_NEW) 539 532 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL) 540 533 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY) 534 + BTF_ID_FLAGS(func, bpf_iter_testmod_seq_value) 541 535 BTF_ID_FLAGS(func, bpf_kfunc_common_test) 542 536 BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test) 543 537 BTF_ID_FLAGS(func, bpf_testmod_ctx_create, KF_ACQUIRE | KF_RET_NULL)
+50
tools/testing/selftests/bpf/progs/iters_testmod_seq.c
··· 12 12 13 13 extern int bpf_iter_testmod_seq_new(struct bpf_iter_testmod_seq *it, s64 value, int cnt) __ksym; 14 14 extern s64 *bpf_iter_testmod_seq_next(struct bpf_iter_testmod_seq *it) __ksym; 15 + extern s64 bpf_iter_testmod_seq_value(int blah, struct bpf_iter_testmod_seq *it) __ksym; 15 16 extern void bpf_iter_testmod_seq_destroy(struct bpf_iter_testmod_seq *it) __ksym; 16 17 17 18 const volatile __s64 exp_empty = 0 + 1; ··· 75 74 res_truncated = sum; 76 75 77 76 return 0; 77 + } 78 + 79 + SEC("?raw_tp") 80 + __failure 81 + __msg("expected an initialized iter_testmod_seq as arg #2") 82 + int testmod_seq_getter_before_bad(const void *ctx) 83 + { 84 + struct bpf_iter_testmod_seq it; 85 + 86 + return bpf_iter_testmod_seq_value(0, &it); 87 + } 88 + 89 + SEC("?raw_tp") 90 + __failure 91 + __msg("expected an initialized iter_testmod_seq as arg #2") 92 + int testmod_seq_getter_after_bad(const void *ctx) 93 + { 94 + struct bpf_iter_testmod_seq it; 95 + s64 sum = 0, *v; 96 + 97 + bpf_iter_testmod_seq_new(&it, 100, 100); 98 + 99 + while ((v = bpf_iter_testmod_seq_next(&it))) { 100 + sum += *v; 101 + } 102 + 103 + bpf_iter_testmod_seq_destroy(&it); 104 + 105 + return sum + bpf_iter_testmod_seq_value(0, &it); 106 + } 107 + 108 + SEC("?socket") 109 + __success __retval(1000000) 110 + int testmod_seq_getter_good(const void *ctx) 111 + { 112 + struct bpf_iter_testmod_seq it; 113 + s64 sum = 0, *v; 114 + 115 + bpf_iter_testmod_seq_new(&it, 100, 100); 116 + 117 + while ((v = bpf_iter_testmod_seq_next(&it))) { 118 + sum += *v; 119 + } 120 + 121 + sum *= bpf_iter_testmod_seq_value(0, &it); 122 + 123 + bpf_iter_testmod_seq_destroy(&it); 124 + 125 + return sum; 78 126 } 79 127 80 128 char _license[] SEC("license") = "GPL";