Skip to content

Commit 58415d5

Browse files
committed
bpf: Make per_cpu_ptr return rdonly PTR_TO_MEM.
jira VULN-136 cve CVE-2022-0500 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: Brett Mastbergen <[email protected]>
1 parent ae76ec7 commit 58415d5

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
@@ -670,7 +670,7 @@ BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
670670
const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
671671
.func = bpf_per_cpu_ptr,
672672
.gpl_only = false,
673-
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL,
673+
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
674674
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
675675
.arg2_type = ARG_ANYTHING,
676676
};
@@ -683,7 +683,7 @@ BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
683683
const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
684684
.func = bpf_this_cpu_ptr,
685685
.gpl_only = false,
686-
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID,
686+
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY,
687687
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
688688
};
689689

kernel/bpf/verifier.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4078,15 +4078,30 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
40784078
mark_reg_unknown(env, regs, value_regno);
40794079
}
40804080
}
4081-
} else if (reg->type == PTR_TO_MEM) {
4081+
} else if (base_type(reg->type) == PTR_TO_MEM) {
4082+
bool rdonly_mem = type_is_rdonly_mem(reg->type);
4083+
4084+
if (type_may_be_null(reg->type)) {
4085+
verbose(env, "R%d invalid mem access '%s'\n", regno,
4086+
reg_type_str(env, reg->type));
4087+
return -EACCES;
4088+
}
4089+
4090+
if (t == BPF_WRITE && rdonly_mem) {
4091+
verbose(env, "R%d cannot write into %s\n",
4092+
regno, reg_type_str(env, reg->type));
4093+
return -EACCES;
4094+
}
4095+
40824096
if (t == BPF_WRITE && value_regno >= 0 &&
40834097
is_pointer_value(env, value_regno)) {
40844098
verbose(env, "R%d leaks addr into mem\n", value_regno);
40854099
return -EACCES;
40864100
}
4101+
40874102
err = check_mem_region_access(env, regno, off, size,
40884103
reg->mem_size, false);
4089-
if (!err && t == BPF_READ && value_regno >= 0)
4104+
if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem))
40904105
mark_reg_unknown(env, regs, value_regno);
40914106
} else if (reg->type == PTR_TO_CTX) {
40924107
enum bpf_reg_type reg_type = SCALAR_VALUE;
@@ -6098,6 +6113,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
60986113
regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag;
60996114
regs[BPF_REG_0].mem_size = tsize;
61006115
} else {
6116+
/* MEM_RDONLY may be carried from ret_flag, but it
6117+
* doesn't apply on PTR_TO_BTF_ID. Fold it, otherwise
6118+
* it will confuse the check of PTR_TO_BTF_ID in
6119+
* check_mem_access().
6120+
*/
6121+
ret_flag &= ~MEM_RDONLY;
6122+
61016123
regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag;
61026124
regs[BPF_REG_0].btf = meta.ret_btf;
61036125
regs[BPF_REG_0].btf_id = meta.ret_btf_id;
@@ -8883,7 +8905,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
88838905
mark_reg_known_zero(env, regs, insn->dst_reg);
88848906

88858907
dst_reg->type = aux->btf_var.reg_type;
8886-
switch (dst_reg->type) {
8908+
switch (base_type(dst_reg->type)) {
88878909
case PTR_TO_MEM:
88888910
dst_reg->mem_size = aux->btf_var.mem_size;
88898911
break;
@@ -10981,7 +11003,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1098111003
err = -EINVAL;
1098211004
goto err_put;
1098311005
}
10984-
aux->btf_var.reg_type = PTR_TO_MEM;
11006+
aux->btf_var.reg_type = PTR_TO_MEM | MEM_RDONLY;
1098511007
aux->btf_var.mem_size = tsize;
1098611008
} else {
1098711009
aux->btf_var.reg_type = PTR_TO_BTF_ID;

0 commit comments

Comments
 (0)