bpf: Extract is_addr_space_cast32() utility function

bpf_do_misc_fixups() converts the following address space cast
instructions to 32-bit moves:

- cast from address space 1 (user) to address space 0 (kernel)
- cast from address space 0 (kernel) to address space 1 (user)
  iff associated arena map has a BPF_F_NO_USER_CONV flag.

Extract a predicate detecting such instructions for use in the
following patches.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20260807-static-zext-v4-2-b6c270013c77@gmail.com
This commit is contained in:
Eduard Zingerman 2026-08-07 13:59:31 -07:00 committed by Daniel Borkmann
parent 483a1bb0b6
commit d977dca7d0

View File

@ -20,6 +20,26 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn)
insn->imm == BPF_CMPXCHG;
}
/* Returns true if 'insn' is an address space cast instruction translated as BPF_ALU op */
static bool is_addr_space_cast32(struct bpf_prog *prog, const struct bpf_insn *insn)
{
struct bpf_map *arena = (struct bpf_map *)prog->aux->arena;
if (insn->code != (BPF_ALU64 | BPF_MOV | BPF_X) || insn->off != BPF_ADDR_SPACE_CAST)
return false;
/* cast from as(1) to as(0) */
if (insn->imm == 1)
return true;
/* cast from as(0) to as(1) */
if (insn->imm == 1 << 16)
return arena && arena->map_flags & BPF_F_NO_USER_CONV;
/* non-BPF_F_NO_USER_CONV cast from as(0) to as(1) should be handled by JIT */
return false;
}
/* Return the regno defined by the insn, or -1. */
static int insn_def_regno(const struct bpf_insn *insn)
{
@ -1513,15 +1533,12 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
}
for (i = 0; i < insn_cnt;) {
if (insn->code == (BPF_ALU64 | BPF_MOV | BPF_X) && insn->imm) {
if ((insn->off == BPF_ADDR_SPACE_CAST && insn->imm == 1) ||
(((struct bpf_map *)env->prog->aux->arena)->map_flags & BPF_F_NO_USER_CONV)) {
/* convert to 32-bit mov that clears upper 32-bit */
insn->code = BPF_ALU | BPF_MOV | BPF_X;
/* clear off and imm, so it's a normal 'wX = wY' from JIT pov */
insn->off = 0;
insn->imm = 0;
} /* cast from as(0) to as(1) should be handled by JIT */
if (is_addr_space_cast32(env->prog, insn)) {
/* convert to 32-bit mov that clears upper 32-bit */
insn->code = BPF_ALU | BPF_MOV | BPF_X;
/* clear off and imm, so it's a normal 'wX = wY' from JIT pov */
insn->off = 0;
insn->imm = 0;
goto next_insn;
}