mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
bpf: Allow bitwise ops, shifts and mul/div on pointers with CAP_PERFMON
Rust's core::fmt keeps a flag in the low bit of a pointer: r2 = *(u64 *)(r1 + 0) r3 = r2 r3 &= 1 r2 >>= 1 The verifier rejects it: r0 &= 8 R0 bitwise operator &= on pointer prohibited Negation and byte swap of a pointer already produce a number when allow_ptr_leaks is set. Do the same for bitwise ops, shifts, *=, /= and %=, 64-bit and 32-bit. The result is an unknown number. With CAP_PERFMON the program can store the pointer and load it back as a number already. += and -= are not changed: they keep the pointer, 32-bit += is rejected. Pointers that allow no arithmetic and pointers that may be NULL are still rejected. Two tests in verifier_value_illegal_alu store through the result of &= and /=. They are rejected at the store now. Update expected messages. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20261002124714.180012-2-alexei.starovoitov@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
parent
5ec398d9ec
commit
72c0681c0e
|
|
@ -15571,8 +15571,14 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn
|
|||
u32 dst = insn->dst_reg;
|
||||
const char *reason;
|
||||
int ret, bounds_ret;
|
||||
bool to_scalar;
|
||||
|
||||
dst_reg = ®s[dst];
|
||||
/*
|
||||
* Only += and -= keep a pointer. Any other op makes a number of it,
|
||||
* which is fine when the program may see values of pointers anyway.
|
||||
*/
|
||||
to_scalar = opcode != BPF_ADD && opcode != BPF_SUB && env->allow_ptr_leaks;
|
||||
|
||||
if ((known && (smin_val != smax_val || umin_val != umax_val)) ||
|
||||
smin_val > smax_val || umin_val > umax_val) {
|
||||
|
|
@ -15583,7 +15589,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (BPF_CLASS(insn->code) != BPF_ALU64) {
|
||||
if (BPF_CLASS(insn->code) != BPF_ALU64 && !to_scalar) {
|
||||
/* 32-bit ALU ops on pointers produce (meaningless) scalars */
|
||||
if (opcode == BPF_SUB && env->allow_ptr_leaks) {
|
||||
__mark_reg_unknown(env, dst_reg);
|
||||
|
|
@ -15649,6 +15655,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
if (to_scalar) {
|
||||
__mark_reg_unknown(env, dst_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For 'scalar += pointer', dst_reg inherits the complete pointer
|
||||
* register state. Individual fields may be adjusted later by pointer
|
||||
* arithmetic. Callers guarantee that below does not overwrite off_reg.
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ struct {
|
|||
|
||||
SEC("socket")
|
||||
__description("map element value illegal alu op, 1")
|
||||
__failure __msg("R0 bitwise operator &= on pointer")
|
||||
__failure_unpriv
|
||||
__failure __msg("R0 invalid mem access 'scalar'")
|
||||
__failure_unpriv __msg_unpriv("R0 bitwise operator &= on pointer")
|
||||
__naked void value_illegal_alu_op_1(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
|
|
@ -70,8 +70,8 @@ l0_%=: exit; \
|
|||
|
||||
SEC("socket")
|
||||
__description("map element value illegal alu op, 3")
|
||||
__failure __msg("R0 pointer arithmetic with /= operator")
|
||||
__failure_unpriv
|
||||
__failure __msg("R0 invalid mem access 'scalar'")
|
||||
__failure_unpriv __msg_unpriv("R0 pointer arithmetic with /= operator")
|
||||
__naked void value_illegal_alu_op_3(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user