Skip to content

Commit 93c230e

Browse files
iamkafaiAlexei Starovoitov
authored andcommitted
bpf: Enforce id generation for all may-be-null register type
The commit af7ec13 ("bpf: Add bpf_skc_to_tcp6_sock() helper") introduces RET_PTR_TO_BTF_ID_OR_NULL and the commit eaa6bcb ("bpf: Introduce bpf_per_cpu_ptr()") introduces RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL. Note that for RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, the reg0->type could become PTR_TO_MEM_OR_NULL which is not covered by BPF_PROBE_MEM. The BPF_REG_0 will then hold a _OR_NULL pointer type. This _OR_NULL pointer type requires the bpf program to explicitly do a NULL check first. After NULL check, the verifier will mark all registers having the same reg->id as safe to use. However, the reg->id is not set for those new _OR_NULL return types. One of the ways that may be wrong is, checking NULL for one btf_id typed pointer will end up validating all other btf_id typed pointers because all of them have id == 0. The later tests will exercise this path. To fix it and also avoid similar issue in the future, this patch moves the id generation logic out of each individual RET type test in check_helper_call(). Instead, it does one reg_type_may_be_null() test and then do the id generation if needed. This patch also adds a WARN_ON_ONCE in mark_ptr_or_null_reg() to catch future breakage. The _OR_NULL pointer usage in the bpf_iter_reg.ctx_arg_info is fine because it just happens that the existing id generation after check_ctx_access() has covered it. It is also using the reg_type_may_be_null() to decide if id generation is needed or not. Fixes: af7ec13 ("bpf: Add bpf_skc_to_tcp6_sock() helper") Fixes: eaa6bcb ("bpf: Introduce bpf_per_cpu_ptr()") Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20201019194212.1050855-1-kafai@fb.com
1 parent 76702a2 commit 93c230e

1 file changed

Lines changed: 5 additions & 6 deletions

File tree

kernel/bpf/verifier.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5133,24 +5133,19 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
51335133
regs[BPF_REG_0].id = ++env->id_gen;
51345134
} else {
51355135
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
5136-
regs[BPF_REG_0].id = ++env->id_gen;
51375136
}
51385137
} else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) {
51395138
mark_reg_known_zero(env, regs, BPF_REG_0);
51405139
regs[BPF_REG_0].type = PTR_TO_SOCKET_OR_NULL;
5141-
regs[BPF_REG_0].id = ++env->id_gen;
51425140
} else if (fn->ret_type == RET_PTR_TO_SOCK_COMMON_OR_NULL) {
51435141
mark_reg_known_zero(env, regs, BPF_REG_0);
51445142
regs[BPF_REG_0].type = PTR_TO_SOCK_COMMON_OR_NULL;
5145-
regs[BPF_REG_0].id = ++env->id_gen;
51465143
} else if (fn->ret_type == RET_PTR_TO_TCP_SOCK_OR_NULL) {
51475144
mark_reg_known_zero(env, regs, BPF_REG_0);
51485145
regs[BPF_REG_0].type = PTR_TO_TCP_SOCK_OR_NULL;
5149-
regs[BPF_REG_0].id = ++env->id_gen;
51505146
} else if (fn->ret_type == RET_PTR_TO_ALLOC_MEM_OR_NULL) {
51515147
mark_reg_known_zero(env, regs, BPF_REG_0);
51525148
regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL;
5153-
regs[BPF_REG_0].id = ++env->id_gen;
51545149
regs[BPF_REG_0].mem_size = meta.mem_size;
51555150
} else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL ||
51565151
fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID) {
@@ -5199,6 +5194,9 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
51995194
return -EINVAL;
52005195
}
52015196

5197+
if (reg_type_may_be_null(regs[BPF_REG_0].type))
5198+
regs[BPF_REG_0].id = ++env->id_gen;
5199+
52025200
if (is_ptr_cast_function(func_id)) {
52035201
/* For release_reference() */
52045202
regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
@@ -7212,7 +7210,8 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state,
72127210
struct bpf_reg_state *reg, u32 id,
72137211
bool is_null)
72147212
{
7215-
if (reg_type_may_be_null(reg->type) && reg->id == id) {
7213+
if (reg_type_may_be_null(reg->type) && reg->id == id &&
7214+
!WARN_ON_ONCE(!reg->id)) {
72167215
/* Old offset (both fixed and variable parts) should
72177216
* have been known-zero, because we don't allow pointer
72187217
* arithmetic on pointers that might be NULL.

0 commit comments

Comments
 (0)