All of lore.kernel.org
 help / color / mirror / Atom feed
From: Puranjay Mohan <puranjay@kernel.org>
To: Daniel Borkmann <daniel@iogearbox.net>, memxor@gmail.com
Cc: eddyz87@gmail.com, bpf@vger.kernel.org,
	Puranjay Mohan <puranjay12@gmail.com>
Subject: Re: [PATCH bpf-next 4/6] bpf, arm64: Clear fetch destination on faulting arena atomic
Date: Mon, 10 Aug 2026 19:31:13 +0100	[thread overview]
Message-ID: <m2tsp1j09a.fsf@kernel.org> (raw)
In-Reply-To: <20260810134346.466004-4-daniel@iogearbox.net>

Daniel Borkmann <daniel@iogearbox.net> writes:

> Same problem as on x86-64: add_exception_handler() folds "there is no
> destination register to clear" and "this is a store" into one DONT_CLEAR
> value ...
>
>   if (BPF_CLASS(insn->code) != BPF_LDX && !bpf_atomic_is_load_acq(insn))
>           dst_reg = DONT_CLEAR;
>
> ... which ex_handler_bpf() then reads back as the access direction:
>
>   bool is_write = (dst_reg == DONT_CLEAR);
>
> A RMW carrying BPF_FETCH is both. emit_lse_atomic() reads the old value
> into src_reg for BPF_{ADD,AND,OR,XOR} | BPF_FETCH and BPF_XCHG, and into
> r0 for BPF_CMPXCHG, so a fault over an unmapped arena page is correctly
> reported as a WRITE but leaves that register holding a stale value instead
> of the 0 that every other BPF_PROBE_* access delivers. Same as on x86-64,
> add a separate ARENA_WRITE bit for the direction and fill FIXUP_REG in
> from bpf_atomic_load_reg().
>
> Fixes: e612b5c1d3ee ("bpf, arm64: Add support for lse atomics in bpf_arena")
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Puranjay Mohan <puranjay@kernel.org>
> ---
>  arch/arm64/net/bpf_jit_comp.c | 36 +++++++++++++++++++++++++----------
>  1 file changed, 26 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
> index d14d297ebb96..796ff9193cfb 100644
> --- a/arch/arm64/net/bpf_jit_comp.c
> +++ b/arch/arm64/net/bpf_jit_comp.c
> @@ -1082,23 +1082,27 @@ static void build_epilogue(struct jit_ctx *ctx, bool was_classic)
>   *
>   * Bit layout of `fixup` (32-bit):
>   *
> - * +-----------+--------+-----------+-----------+----------+
> - * |   31-27   | 26-22  |     21    |   20-16   |   15-0   |
> - * |           |        |           |           |          |
> - * | FIXUP_REG | Unused | ARENA_ACC | ARENA_REG |  OFFSET  |
> - * +-----------+--------+-----------+-----------+----------+
> + * +-----------+--------+-------------+-----------+-----------+----------+
> + * |   31-27   | 26-23  |      22     |     21    |   20-16   |   15-0   |
> + * |           |        |             |           |           |          |
> + * | FIXUP_REG | Unused | ARENA_WRITE | ARENA_ACC | ARENA_REG |  OFFSET  |
> + * +-----------+--------+-------------+-----------+-----------+----------+
>   *
>   * - OFFSET (16 bits): Offset used to compute address for Load/Store instruction.
>   * - ARENA_REG (5 bits): Register that is used to calculate the address for load/store when
>   *                       accessing the arena region.
>   * - ARENA_ACCESS (1 bit): This bit is set when the faulting instruction accessed the arena region.
> + * - ARENA_WRITE (1 bit): This bit is set when the faulting instruction wrote to the arena region.
> + *                        It is independent of FIXUP_REG, since a read-modify-write both writes to
> + *                        memory and reads the old value into a register.
>   * - FIXUP_REG (5 bits): Destination register for the load instruction (cleared on fault) or set to
> - *                       DONT_CLEAR if it is a store instruction.
> + *                       DONT_CLEAR if the instruction does not read into a register.
>   */
>  
>  #define BPF_FIXUP_OFFSET_MASK      GENMASK(15, 0)
>  #define BPF_FIXUP_ARENA_REG_MASK   GENMASK(20, 16)
>  #define BPF_ARENA_ACCESS           BIT(21)
> +#define BPF_ARENA_WRITE            BIT(22)
>  #define BPF_FIXUP_REG_MASK	GENMASK(31, 27)
>  #define DONT_CLEAR 5 /* Unused ARM64 register from BPF's POV */
>  
> @@ -1109,7 +1113,7 @@ bool ex_handler_bpf(const struct exception_table_entry *ex,
>  	s16 off = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup);
>  	int arena_reg = FIELD_GET(BPF_FIXUP_ARENA_REG_MASK, ex->fixup);
>  	bool is_arena = !!(ex->fixup & BPF_ARENA_ACCESS);
> -	bool is_write = (dst_reg == DONT_CLEAR);
> +	bool is_write = !!(ex->fixup & BPF_ARENA_WRITE);
>  	unsigned long addr;
>  
>  	if (is_arena) {
> @@ -1132,7 +1136,7 @@ static int add_exception_handler(const struct bpf_insn *insn,
>  {
>  	off_t ins_offset;
>  	s16 off = insn->off;
> -	bool is_arena;
> +	bool is_arena, is_write = false;
>  	int arena_reg;
>  	unsigned long pc;
>  	struct exception_table_entry *ex;
> @@ -1183,13 +1187,25 @@ static int add_exception_handler(const struct bpf_insn *insn,
>  	 * 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;
> +	if (BPF_CLASS(insn->code) != BPF_LDX && !bpf_atomic_is_load_acq(insn)) {
> +		/*
> +		 * A store has no destination register to clear, except for a
> +		 * read-modify-write with BPF_FETCH, which also reads the old
> +		 * value into src_reg, or into r0 for a BPF_CMPXCHG. Either way
> +		 * the access is still reported as a write.
> +		 */
> +		int load_reg = bpf_atomic_load_reg(insn);
> +
> +		dst_reg = load_reg < 0 ? DONT_CLEAR : bpf2a64[load_reg];
> +		is_write = true;
> +	}
>  
>  	ex->fixup = FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
>  
>  	if (is_arena) {
>  		ex->fixup |= BPF_ARENA_ACCESS;
> +		if (is_write)
> +			ex->fixup |= BPF_ARENA_WRITE;
>  		/*
>  		 * insn->src_reg/dst_reg holds the address in the arena region with upper 32-bits
>  		 * being zero because of a preceding addr_space_cast(r<n>, 0x0, 0x1) instruction.
> -- 
> 2.43.0


Reviewed-by: Puranjay Mohan <puranjay@kernel.org>

  parent reply	other threads:[~2026-08-10 18:31 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10 13:43 [PATCH bpf-next 1/6] bpf: Derive the atomic load register in one place Daniel Borkmann
2026-08-10 13:43 ` [PATCH bpf-next 2/6] bpf, riscv: Clear fetch destination on faulting arena atomic Daniel Borkmann
2026-08-10 13:43 ` [PATCH bpf-next 3/6] bpf, x86: " Daniel Borkmann
2026-08-10 14:07   ` sashiko-bot
2026-08-10 14:08     ` Daniel Borkmann
2026-08-10 17:26   ` Eduard Zingerman
2026-08-10 18:22   ` Puranjay Mohan
2026-08-10 13:43 ` [PATCH bpf-next 4/6] bpf, arm64: " Daniel Borkmann
2026-08-10 18:20   ` Eduard Zingerman
2026-08-10 18:30     ` Puranjay Mohan
2026-08-10 18:36       ` Eduard Zingerman
2026-08-10 18:31   ` Puranjay Mohan [this message]
2026-08-10 13:43 ` [PATCH bpf-next 5/6] bpf, s390: " Daniel Borkmann
2026-08-10 13:43 ` [PATCH bpf-next 6/6] selftests/bpf: Add arena fault tests for atomics with fetch Daniel Borkmann
2026-08-10 18:56   ` Eduard Zingerman
2026-08-10 15:08 ` [PATCH bpf-next 1/6] bpf: Derive the atomic load register in one place bot+bpf-ci
2026-08-10 17:10 ` Eduard Zingerman
2026-08-10 18:13   ` Daniel Borkmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m2tsp1j09a.fsf@kernel.org \
    --to=puranjay@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=memxor@gmail.com \
    --cc=puranjay12@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.