There is a number of BPF helper functions that use ARG_ANYTHING to mark parameters that are used as memory addresses. An address of BPF stack slot could be passed as such parameter for two such helper functions: - bpf_probe_read_kernel - bpf_probe_read_kernel_str This might lead to a surprising behavior in combination with nocsr rewrites, e.g. consider the program below: 1: r1 = 1; /* nocsr pattern with stack offset -16 */ 2: *(u64 *)(r10 - 16) = r1; 3: call %[bpf_get_smp_processor_id]; 4: r1 = *(u64 *)(r10 - 16); 5: r1 = r10; 6: r1 += -8; 7: r2 = 1; 8: r3 = r10; 9: r3 += -16; /* bpf_probe_read_kernel(dst: &fp[-8], size: 1, src: &fp[-16]) */ 10: call %[bpf_probe_read_kernel]; 11: exit; Here nocsr rewrite logic would remove instructions (2) and (4). However, (2) writes a value that is later read by a call at (10). Function check_func_arg() is called from check_helper_call() and is responsible for memory access checks, when helper argument type is declared as ARG_PTR_TO_... . However, for ARG_ANYTHING this function returns early and does not call check_stack_{read,write}(). This patch opts to add a check_nocsr_stack_contract() to the ARG_ANYTHING return path if passed parameter is a pointer to stack. Signed-off-by: Eduard Zingerman <eddyz87@xxxxxxxxx> --- kernel/bpf/verifier.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 438daf36a694..77affc563a64 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8684,11 +8684,15 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, return err; if (arg_type == ARG_ANYTHING) { + /* return value depends on env->allow_ptr_leaks */ if (is_pointer_value(env, regno)) { verbose(env, "R%d leaks addr into helper function\n", regno); return -EACCES; } + if (reg->type == PTR_TO_STACK) + check_nocsr_stack_contract(env, cur_func(env), insn_idx, + reg->smin_value + reg->off); return 0; } -- 2.45.2