mirror of
https://github.com/torvalds/linux.git
synced 2026-09-27 11:02:03 +02:00
bpf: Prevent variable arena/non-arena register contents
The verifier marks ALU instructions that include at least
one arena operand with needs_zext: These instructions are
fixed up after verification to be ALU32 instructions to
ensure that the result is a valid offset into an arena.
However, different code paths may provide two non-arena
64-bit arguments to the same instruction. The result of
the operation in that code path is wrong, since it is
now unexpectedly truncated to 32 bits and zero-extended.
Add logic to the verifier to ensure every instruction either
always has at least one PTR_TO_ARENA argument, or never does.
Since needs_zext already tracks the first scenario, add a
prevent_zext field in bpf_insn_aux to track the latter.
Reject instructions that use arena arguments and have prevent_zext
set, or do not have arena arguments and have needs_zext set.
Fixes: 6082b6c328 ("bpf: Recognize addr_space_cast instruction in the verifier.")
Reported-by: Nicholas Carlini <nicholas@carlini.com>
Suggested-by: Nicholas Carlini <nicholas@carlini.com>
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20260922172028.6269-8-emil@etsalapatis.com
This commit is contained in:
parent
1ed69a54d3
commit
f85f5917aa
|
|
@ -680,6 +680,7 @@ struct bpf_insn_aux_data {
|
|||
bool nospec_result; /* result is unsafe under speculation, nospec must follow */
|
||||
bool zext_dst; /* this insn zero extends dst reg */
|
||||
bool needs_zext; /* alu op needs to clear upper bits */
|
||||
bool prevent_zext; /* alu op cannot be zext (already used with 64-bit scalars) */
|
||||
bool non_sleepable; /* helper/kfunc may be called from non-sleepable context */
|
||||
bool is_iter_next; /* bpf_iter_<type>_next() kfunc call */
|
||||
bool call_with_percpu_alloc_ptr; /* {this,per}_cpu_ptr() with prog percpu alloc */
|
||||
|
|
|
|||
|
|
@ -15741,6 +15741,7 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
|
|||
struct bpf_reg_state *regs = state->regs, *dst_reg, *src_reg;
|
||||
struct bpf_reg_state *ptr_reg = NULL, off_reg = {0};
|
||||
bool alu32 = (BPF_CLASS(insn->code) != BPF_ALU64);
|
||||
struct bpf_insn_aux_data *aux = cur_aux(env);
|
||||
u8 opcode = BPF_OP(insn->code);
|
||||
int err;
|
||||
|
||||
|
|
@ -15752,12 +15753,23 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
|
|||
|
||||
/* Case where at least one operand is an arena. */
|
||||
if (dst_reg->type == PTR_TO_ARENA || (src_reg && src_reg->type == PTR_TO_ARENA)) {
|
||||
struct bpf_insn_aux_data *aux = cur_aux(env);
|
||||
|
||||
if (dst_reg->type != PTR_TO_ARENA)
|
||||
*dst_reg = *src_reg;
|
||||
|
||||
if (BPF_CLASS(insn->code) == BPF_ALU64) {
|
||||
/*
|
||||
* Only arena pointers set needs_zext, but doing so
|
||||
* modifies the instruction at fixup time to an ALU32
|
||||
* and makes it unsuitable for 64-bit scalar args. We
|
||||
* prevent zext from being set if the instruction has
|
||||
* been previously called with non-arena registers.
|
||||
*/
|
||||
if (aux->prevent_zext) {
|
||||
verbose(env, "same insn cannot be used with and without arena pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 32-bit operations zero upper bits automatically.
|
||||
* 64-bit operations need to be converted to 32.
|
||||
|
|
@ -15770,6 +15782,16 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Prevent the instruction from being used with arena pointers (see above). */
|
||||
if (env->prog->aux->arena && BPF_CLASS(insn->code) == BPF_ALU64) {
|
||||
if (aux->needs_zext) {
|
||||
verbose(env, "same insn cannot be used with and without arena pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
aux->prevent_zext = true;
|
||||
}
|
||||
|
||||
if (dst_reg->type != SCALAR_VALUE)
|
||||
ptr_reg = dst_reg;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user