bpf: Make per_cpu_ptr return rdonly PTR_TO_MEM.
Tag the return type of {per, this}_cpu_ptr with RDONLY_MEM. The returned value of this pair of helpers is kernel object, which can not be updated by bpf programs. Previously these two helpers return PTR_OT_MEM for kernel objects of scalar type, which allows one to directly modify the memory. Now with RDONLY_MEM tagging, the verifier will reject programs that write into RDONLY_MEM. Fixes:63d9b80dcf
("bpf: Introducte bpf_this_cpu_ptr()") Fixes:eaa6bcb71e
("bpf: Introduce bpf_per_cpu_ptr()") Fixes:4976b718c3
("bpf: Introduce pseudo_btf_id") Signed-off-by: Hao Luo <haoluo@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20211217003152.48334-8-haoluo@google.com
This commit is contained in:
parent
cf9f2f8d62
commit
34d3a78c68
@ -682,7 +682,7 @@ BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
|
||||
const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
|
||||
.func = bpf_per_cpu_ptr,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL,
|
||||
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
|
||||
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
|
||||
.arg2_type = ARG_ANYTHING,
|
||||
};
|
||||
@ -695,7 +695,7 @@ BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
|
||||
const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
|
||||
.func = bpf_this_cpu_ptr,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID,
|
||||
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY,
|
||||
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
|
||||
};
|
||||
|
||||
|
@ -4399,15 +4399,30 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
||||
mark_reg_unknown(env, regs, value_regno);
|
||||
}
|
||||
}
|
||||
} else if (reg->type == PTR_TO_MEM) {
|
||||
} else if (base_type(reg->type) == PTR_TO_MEM) {
|
||||
bool rdonly_mem = type_is_rdonly_mem(reg->type);
|
||||
|
||||
if (type_may_be_null(reg->type)) {
|
||||
verbose(env, "R%d invalid mem access '%s'\n", regno,
|
||||
reg_type_str(env, reg->type));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (t == BPF_WRITE && rdonly_mem) {
|
||||
verbose(env, "R%d cannot write into %s\n",
|
||||
regno, reg_type_str(env, reg->type));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (t == BPF_WRITE && value_regno >= 0 &&
|
||||
is_pointer_value(env, value_regno)) {
|
||||
verbose(env, "R%d leaks addr into mem\n", value_regno);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
err = check_mem_region_access(env, regno, off, size,
|
||||
reg->mem_size, false);
|
||||
if (!err && t == BPF_READ && value_regno >= 0)
|
||||
if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem))
|
||||
mark_reg_unknown(env, regs, value_regno);
|
||||
} else if (reg->type == PTR_TO_CTX) {
|
||||
enum bpf_reg_type reg_type = SCALAR_VALUE;
|
||||
@ -6654,6 +6669,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
|
||||
regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag;
|
||||
regs[BPF_REG_0].mem_size = tsize;
|
||||
} else {
|
||||
/* MEM_RDONLY may be carried from ret_flag, but it
|
||||
* doesn't apply on PTR_TO_BTF_ID. Fold it, otherwise
|
||||
* it will confuse the check of PTR_TO_BTF_ID in
|
||||
* check_mem_access().
|
||||
*/
|
||||
ret_flag &= ~MEM_RDONLY;
|
||||
|
||||
regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag;
|
||||
regs[BPF_REG_0].btf = meta.ret_btf;
|
||||
regs[BPF_REG_0].btf_id = meta.ret_btf_id;
|
||||
@ -9455,7 +9477,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
||||
mark_reg_known_zero(env, regs, insn->dst_reg);
|
||||
|
||||
dst_reg->type = aux->btf_var.reg_type;
|
||||
switch (dst_reg->type) {
|
||||
switch (base_type(dst_reg->type)) {
|
||||
case PTR_TO_MEM:
|
||||
dst_reg->mem_size = aux->btf_var.mem_size;
|
||||
break;
|
||||
@ -11678,7 +11700,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
|
||||
err = -EINVAL;
|
||||
goto err_put;
|
||||
}
|
||||
aux->btf_var.reg_type = PTR_TO_MEM;
|
||||
aux->btf_var.reg_type = PTR_TO_MEM | MEM_RDONLY;
|
||||
aux->btf_var.mem_size = tsize;
|
||||
} else {
|
||||
aux->btf_var.reg_type = PTR_TO_BTF_ID;
|
||||
|
Loading…
Reference in New Issue
Block a user