UPSTREAM: bpf: Make per_cpu_ptr return rdonly PTR_TO_MEM.
commit 34d3a78c681e8e7844b43d1a2f4671a04249c821 upstream. 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 Cc: stable@vger.kernel.org # 5.15.x Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit15166bb300
) Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ia4b902ba12ab23cde1d0457e6619f42521032253
This commit is contained in:
parent
d7ebee8df3
commit
e1714bff1c
|
@ -667,7 +667,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,
|
||||
};
|
||||
|
@ -680,7 +680,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,
|
||||
};
|
||||
|
||||
|
|
|
@ -4166,15 +4166,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;
|
||||
|
@ -6370,6 +6385,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;
|
||||
|
@ -9172,7 +9194,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
|||
|
||||
if (insn->src_reg == BPF_PSEUDO_BTF_ID) {
|
||||
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;
|
||||
|
@ -11313,7 +11335,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