check_mem_reg() allows bpf_register_is_null() for nullable arguments w/o marking the underlying scalar register precise. Hence a checkpoint created on such a path would prune against arbitrary scalar value. The argument may live on the stack rather than in a register when a call has more than MAX_BPF_FUNC_REG_ARGS arguments, hence the new mark_arg_precision() helper.
Unified · Split
| @@ -4246,6 +4246,15 @@ static int mark_stack_arg_precision(struct bpf_verifier_env *env, int arg_idx) · 4245 unmodified lines | |||
| 4246 | return mark_chain_precision_batch(env, env->cur_state); | 4246 | return mark_chain_precision_batch(env, env->cur_state); |
| 4247 | } | 4247 | } |
| 4248 | 4248 | ||
| 4249 | static int mark_arg_precision(struct bpf_verifier_env *env, argno_t argno) | ||
| 4250 | { | ||
| 4251 | int regno = reg_from_argno(argno); | ||
| 4252 | |||
| 4253 | if (regno >= 0) | ||
| 4254 | return mark_chain_precision(env, regno); | ||
| 4255 | return mark_stack_arg_precision(env, arg_idx_from_argno(argno)); | ||
| 4256 | } | ||
| 4257 | |||
| 4249 | static int check_outgoing_stack_args(struct bpf_verifier_env *env, struct bpf_func_state *caller, | 4258 | static int check_outgoing_stack_args(struct bpf_verifier_env *env, struct bpf_func_state *caller, |
| 4250 | int nargs, const char *callee_name, const struct btf *btf, | 4259 | int nargs, const char *callee_name, const struct btf *btf, |
| 4251 | const struct btf_param *args) | 4260 | const struct btf_param *args) |
| @@ -7175,7 +7184,7 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg · 2923 unmodified lines | |||
| 7175 | int size, err = 0; | 7184 | int size, err = 0; |
| 7176 | 7185 | ||
| 7177 | if (bpf_register_is_null(reg)) | 7186 | if (bpf_register_is_null(reg)) |
| 7178 | return 0; | 7187 | return mark_arg_precision(env, argno); |
| 7179 | if (known_memory) | 7188 | if (known_memory) |
| 7180 | *known_memory = true; | 7189 | *known_memory = true; |
| 7181 | 7190 | ||