Skip to content

Commit 34d3a78

Browse files
haoluo1022Alexei Starovoitov
authored andcommitted
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: 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]
1 parent cf9f2f8 commit 34d3a78

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
@@ -682,7 +682,7 @@ BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
682682
const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
683683
.func = bpf_per_cpu_ptr,
684684
.gpl_only = false,
685-
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL,
685+
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
686686
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
687687
.arg2_type = ARG_ANYTHING,
688688
};
@@ -695,7 +695,7 @@ BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
695695
const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
696696
.func = bpf_this_cpu_ptr,
697697
.gpl_only = false,
698-
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID,
698+
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY,
699699
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
700700
};
701701

kernel/bpf/verifier.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4399,15 +4399,30 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
43994399
mark_reg_unknown(env, regs, value_regno);
44004400
}
44014401
}
4402-
} else if (reg->type == PTR_TO_MEM) {
4402+
} else if (base_type(reg->type) == PTR_TO_MEM) {
4403+
bool rdonly_mem = type_is_rdonly_mem(reg->type);
4404+
4405+
if (type_may_be_null(reg->type)) {
4406+
verbose(env, "R%d invalid mem access '%s'\n", regno,
4407+
reg_type_str(env, reg->type));
4408+
return -EACCES;
4409+
}
4410+
4411+
if (t == BPF_WRITE && rdonly_mem) {
4412+
verbose(env, "R%d cannot write into %s\n",
4413+
regno, reg_type_str(env, reg->type));
4414+
return -EACCES;
4415+
}
4416+
44034417
if (t == BPF_WRITE && value_regno >= 0 &&
44044418
is_pointer_value(env, value_regno)) {
44054419
verbose(env, "R%d leaks addr into mem\n", value_regno);
44064420
return -EACCES;
44074421
}
4422+
44084423
err = check_mem_region_access(env, regno, off, size,
44094424
reg->mem_size, false);
4410-
if (!err && t == BPF_READ && value_regno >= 0)
4425+
if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem))
44114426
mark_reg_unknown(env, regs, value_regno);
44124427
} else if (reg->type == PTR_TO_CTX) {
44134428
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
66546669
regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag;
66556670
regs[BPF_REG_0].mem_size = tsize;
66566671
} else {
6672+
/* MEM_RDONLY may be carried from ret_flag, but it
6673+
* doesn't apply on PTR_TO_BTF_ID. Fold it, otherwise
6674+
* it will confuse the check of PTR_TO_BTF_ID in
6675+
* check_mem_access().
6676+
*/
6677+
ret_flag &= ~MEM_RDONLY;
6678+
66576679
regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag;
66586680
regs[BPF_REG_0].btf = meta.ret_btf;
66596681
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)
94559477
mark_reg_known_zero(env, regs, insn->dst_reg);
94569478

94579479
dst_reg->type = aux->btf_var.reg_type;
9458-
switch (dst_reg->type) {
9480+
switch (base_type(dst_reg->type)) {
94599481
case PTR_TO_MEM:
94609482
dst_reg->mem_size = aux->btf_var.mem_size;
94619483
break;
@@ -11678,7 +11700,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1167811700
err = -EINVAL;
1167911701
goto err_put;
1168011702
}
11681-
aux->btf_var.reg_type = PTR_TO_MEM;
11703+
aux->btf_var.reg_type = PTR_TO_MEM | MEM_RDONLY;
1168211704
aux->btf_var.mem_size = tsize;
1168311705
} else {
1168411706
aux->btf_var.reg_type = PTR_TO_BTF_ID;

0 commit comments

Comments
 (0)