Skip to content

Commit ff13ede

Browse files
bpf: Make per_cpu_ptr return rdonly PTR_TO_MEM.
jira VULN-140 pre-cve CVE-2022-23222 commit-author Hao Luo <[email protected]> commit 34d3a78 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: 63d9b80 ("bpf: Introducte bpf_this_cpu_ptr()") Fixes: eaa6bcb ("bpf: Introduce bpf_per_cpu_ptr()") Fixes: 4976b71 ("bpf: Introduce pseudo_btf_id") Signed-off-by: Hao Luo <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected] (cherry picked from commit 34d3a78) Signed-off-by: Pratham Patel <[email protected]>
1 parent cbad29d commit ff13ede

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

kernel/bpf/helpers.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
660660
const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
661661
.func = bpf_per_cpu_ptr,
662662
.gpl_only = false,
663-
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL,
663+
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
664664
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
665665
.arg2_type = ARG_ANYTHING,
666666
};
@@ -673,7 +673,7 @@ BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
673673
const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
674674
.func = bpf_this_cpu_ptr,
675675
.gpl_only = false,
676-
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID,
676+
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY,
677677
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
678678
};
679679

kernel/bpf/verifier.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4076,15 +4076,30 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
40764076
mark_reg_unknown(env, regs, value_regno);
40774077
}
40784078
}
4079-
} else if (reg->type == PTR_TO_MEM) {
4079+
} else if (base_type(reg->type) == PTR_TO_MEM) {
4080+
bool rdonly_mem = type_is_rdonly_mem(reg->type);
4081+
4082+
if (type_may_be_null(reg->type)) {
4083+
verbose(env, "R%d invalid mem access '%s'\n", regno,
4084+
reg_type_str(env, reg->type));
4085+
return -EACCES;
4086+
}
4087+
4088+
if (t == BPF_WRITE && rdonly_mem) {
4089+
verbose(env, "R%d cannot write into %s\n",
4090+
regno, reg_type_str(env, reg->type));
4091+
return -EACCES;
4092+
}
4093+
40804094
if (t == BPF_WRITE && value_regno >= 0 &&
40814095
is_pointer_value(env, value_regno)) {
40824096
verbose(env, "R%d leaks addr into mem\n", value_regno);
40834097
return -EACCES;
40844098
}
4099+
40854100
err = check_mem_region_access(env, regno, off, size,
40864101
reg->mem_size, false);
4087-
if (!err && t == BPF_READ && value_regno >= 0)
4102+
if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem))
40884103
mark_reg_unknown(env, regs, value_regno);
40894104
} else if (reg->type == PTR_TO_CTX) {
40904105
enum bpf_reg_type reg_type = SCALAR_VALUE;
@@ -6092,6 +6107,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
60926107
regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag;
60936108
regs[BPF_REG_0].mem_size = tsize;
60946109
} else {
6110+
/* MEM_RDONLY may be carried from ret_flag, but it
6111+
* doesn't apply on PTR_TO_BTF_ID. Fold it, otherwise
6112+
* it will confuse the check of PTR_TO_BTF_ID in
6113+
* check_mem_access().
6114+
*/
6115+
ret_flag &= ~MEM_RDONLY;
6116+
60956117
regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag;
60966118
regs[BPF_REG_0].btf = meta.ret_btf;
60976119
regs[BPF_REG_0].btf_id = meta.ret_btf_id;
@@ -8877,7 +8899,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
88778899
mark_reg_known_zero(env, regs, insn->dst_reg);
88788900

88798901
dst_reg->type = aux->btf_var.reg_type;
8880-
switch (dst_reg->type) {
8902+
switch (base_type(dst_reg->type)) {
88818903
case PTR_TO_MEM:
88828904
dst_reg->mem_size = aux->btf_var.mem_size;
88838905
break;
@@ -10969,7 +10991,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1096910991
err = -EINVAL;
1097010992
goto err_put;
1097110993
}
10972-
aux->btf_var.reg_type = PTR_TO_MEM;
10994+
aux->btf_var.reg_type = PTR_TO_MEM | MEM_RDONLY;
1097310995
aux->btf_var.mem_size = tsize;
1097410996
} else {
1097510997
aux->btf_var.reg_type = PTR_TO_BTF_ID;

0 commit comments

Comments
 (0)