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

bpf: check bpf_dummy_struct_ops program params for test runs

When doing BPF_PROG_TEST_RUN for bpf_dummy_struct_ops programs,
reject execution when NULL is passed for non-nullable params.
For programs with non-nullable params verifier assumes that
such params are never NULL and thus might optimize out NULL checks.

Suggested-by: Kui-Feng Lee <sinquersw@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20240424012821.595216-5-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
980ca8ce f612210d

+50 -1
+50 -1
net/bpf/bpf_dummy_struct_ops.c
··· 79 79 args->args[3], args->args[4]); 80 80 } 81 81 82 + static const struct bpf_ctx_arg_aux *find_ctx_arg_info(struct bpf_prog_aux *aux, int offset) 83 + { 84 + int i; 85 + 86 + for (i = 0; i < aux->ctx_arg_info_size; i++) 87 + if (aux->ctx_arg_info[i].offset == offset) 88 + return &aux->ctx_arg_info[i]; 89 + 90 + return NULL; 91 + } 92 + 93 + /* There is only one check at the moment: 94 + * - zero should not be passed for pointer parameters not marked as nullable. 95 + */ 96 + static int check_test_run_args(struct bpf_prog *prog, struct bpf_dummy_ops_test_args *args) 97 + { 98 + const struct btf_type *func_proto = prog->aux->attach_func_proto; 99 + 100 + for (u32 arg_no = 0; arg_no < btf_type_vlen(func_proto) ; ++arg_no) { 101 + const struct btf_param *param = &btf_params(func_proto)[arg_no]; 102 + const struct bpf_ctx_arg_aux *info; 103 + const struct btf_type *t; 104 + int offset; 105 + 106 + if (args->args[arg_no] != 0) 107 + continue; 108 + 109 + /* Program is validated already, so there is no need 110 + * to check if t is NULL. 111 + */ 112 + t = btf_type_skip_modifiers(bpf_dummy_ops_btf, param->type, NULL); 113 + if (!btf_type_is_ptr(t)) 114 + continue; 115 + 116 + offset = btf_ctx_arg_offset(bpf_dummy_ops_btf, func_proto, arg_no); 117 + info = find_ctx_arg_info(prog->aux, offset); 118 + if (info && (info->reg_type & PTR_MAYBE_NULL)) 119 + continue; 120 + 121 + return -EINVAL; 122 + } 123 + 124 + return 0; 125 + } 126 + 82 127 extern const struct bpf_link_ops bpf_struct_ops_link_lops; 83 128 84 129 int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, ··· 132 87 const struct bpf_struct_ops *st_ops = &bpf_bpf_dummy_ops; 133 88 const struct btf_type *func_proto; 134 89 struct bpf_dummy_ops_test_args *args; 135 - struct bpf_tramp_links *tlinks; 90 + struct bpf_tramp_links *tlinks = NULL; 136 91 struct bpf_tramp_link *link = NULL; 137 92 void *image = NULL; 138 93 unsigned int op_idx; ··· 153 108 args = dummy_ops_init_args(kattr, btf_type_vlen(func_proto)); 154 109 if (IS_ERR(args)) 155 110 return PTR_ERR(args); 111 + 112 + err = check_test_run_args(prog, args); 113 + if (err) 114 + goto out; 156 115 157 116 tlinks = kcalloc(BPF_TRAMP_MAX, sizeof(*tlinks), GFP_KERNEL); 158 117 if (!tlinks) {