From af22d273aa1f61fb86ec712b3ed785da73c3296e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 6 Aug 2026 22:10:45 +0200 Subject: bpf, arm64: Fix exception table metadata for arena load-acquire Same problem as on x86-64: add_exception_handler() decides whether an instruction is a load by its class, and a load-acquire is of BPF_STX class even though it reads from src_reg into dst_reg. As a result ... if (BPF_CLASS(insn->code) != BPF_LDX) dst_reg = DONT_CLEAR; ... drops the register to clear, and ... if (BPF_CLASS(insn->code) == BPF_LDX) arena_reg = bpf2a64[insn->src_reg]; else arena_reg = bpf2a64[insn->dst_reg]; ... hands ex_handler_bpf() the value register instead of the address register. A load-acquire from an arena pointer that faults on an unmapped page is therefore reported as a WRITE at a bogus address, and dst_reg keeps its previous value instead of being cleared to 0. Note that emit_atomic_ld_st() already picks src_reg as the address for BPF_LOAD_ACQ, so only the exception table metadata was out of sync with the emitted access. Same as on x86-64, use bpf_atomic_is_load_acq() so a load-acquire takes the load path. Fixes: 9bb12368d539 ("bpf, arm64: Support load-acquire and store-release instructions") Signed-off-by: Daniel Borkmann Reviewed-by: Puranjay Mohan Link: https://lore.kernel.org/bpf/20260806201047.333389-4-daniel@iogearbox.net Signed-off-by: Kumar Kartikeya Dwivedi --- arch/arm64/net/bpf_jit_comp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 4cdc7dfb05ba..d14d297ebb96 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1178,7 +1178,12 @@ static int add_exception_handler(const struct bpf_insn *insn, ex->insn = ins_offset; - if (BPF_CLASS(insn->code) != BPF_LDX) + /* + * A load-acquire is of BPF_STX class, but reads from src_reg into + * dst_reg like a BPF_LDX does, hence it must not be treated as a store + * here. + */ + if (BPF_CLASS(insn->code) != BPF_LDX && !bpf_atomic_is_load_acq(insn)) dst_reg = DONT_CLEAR; ex->fixup = FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg); @@ -1193,7 +1198,7 @@ static int add_exception_handler(const struct bpf_insn *insn, * memory access. Pass the reg holding the unmodified 32-bit address to * ex_handler_bpf. */ - if (BPF_CLASS(insn->code) == BPF_LDX) + if (BPF_CLASS(insn->code) == BPF_LDX || bpf_atomic_is_load_acq(insn)) arena_reg = bpf2a64[insn->src_reg]; else arena_reg = bpf2a64[insn->dst_reg]; -- cgit v1.2.3