When reviewing local percpu kptr support, Alexei discovered a bug wherea bpf_kptr_xchg() may succeed even if the map value kptr type and locally allocated obj type do not match ([1]). Missed struct btf_id comparison is the reason for the bug. This patch added such struct btf_id comparison and will flag verification failure if types do not match. [1] https://lore.kernel.org/bpf/20230819002907.io3iphmnuk43xblu@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/#t Reported-by: Alexei Starovoitov <ast@xxxxxxxxxx> Fixes: 738c96d5e2e3 ("bpf: Allow local kptrs to be exchanged via bpf_kptr_xchg") Signed-off-by: Yonghong Song <yonghong.song@xxxxxxxxx> --- kernel/bpf/verifier.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 02a021c524ab..4e1ecd4b8497 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7745,7 +7745,18 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno, verbose(env, "verifier internal error: unimplemented handling of MEM_ALLOC\n"); return -EFAULT; } - /* Handled by helper specific checks */ + if (meta->func_id == BPF_FUNC_kptr_xchg) { + struct btf_field *kptr_field = meta->kptr_field; + + if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, reg->off, + kptr_field->kptr.btf, kptr_field->kptr.btf_id, + true)) { + verbose(env, "R%d is of type %s but %s is expected\n", + regno, btf_type_name(reg->btf, reg->btf_id), + btf_type_name(kptr_field->kptr.btf, kptr_field->kptr.btf_id)); + return -EACCES; + } + } break; case PTR_TO_BTF_ID | MEM_PERCPU: case PTR_TO_BTF_ID | MEM_PERCPU | PTR_TRUSTED: -- 2.34.1