[PATCH bpf-next v2 4/6] bpf, arm64: Fix exception table metadata for arena load-acquire
Daniel Borkmann <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]>
Reviewed-by: Puranjay Mohan <[email protected]>
Cc: Peilin Ye <[email protected]>
---
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];
--
2.43.0