* [PATCH bpf-next v5 0/4] bpf: report arena faults to BPF streams
@ 2025-09-01 19:37 Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 1/4] bpf: arm64: simplify exception table handling Puranjay Mohan
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Puranjay Mohan @ 2025-09-01 19:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Puranjay Mohan, Xu Kuohai, Catalin Marinas, Will Deacon,
Kumar Kartikeya Dwivedi, bpf
Changes in v4->v5:
v4: https://lore.kernel.org/all/20250827153728.28115-1-puranjay@kernel.org/
- Added patch 2 to introducing main_prog_aux for easier access to streams.
- Fixed bug in fault handlers when arena_reg == dst_reg
- Updated selftest to check test above edge case.
- Added comments about the usage of barrier_var() in code and commit message.
Changes in v3->v4:
v3: https://lore.kernel.org/all/20250827150113.15763-1-puranjay@kernel.org/
- Fixed a build issue when CONFIG_BPF_JIT=y and # CONFIG_BPF_SYSCALL is not set
Changes in v2->v3:
v2: https://lore.kernel.org/all/20250811111828.13836-1-puranjay@kernel.org/
- Improved the selftest to check the exact fault address
- Dropped BPF_NO_KFUNC_PROTOTYPES and bpf_arena_alloc/free_pages() usage
- Rebased on bpf-next/master
Changes in v1->v2:
v1: https://lore.kernel.org/all/20250806085847.18633-1-puranjay@kernel.org/
- Changed variable and mask names for consistency (Yonghong)
- Added Acked-by: Yonghong Song <yonghong.song@linux.dev> on two patches
This set adds the support of reporting page faults inside arena to BPF
stderr stream. The reported address is the one that a user would expect
to see if they pass it to bpf_printk();
Here is an example output from a stream and bpf_printk()
ERROR: Arena WRITE access at unmapped address 0xdeaddead0000
CPU: 9 UID: 0 PID: 502 Comm: test_progs
Call trace:
bpf_stream_stage_dump_stack+0xc0/0x150
bpf_prog_report_arena_violation+0x98/0xf0
ex_handler_bpf+0x5c/0x78
fixup_exception+0xf8/0x160
__do_kernel_fault+0x40/0x188
do_bad_area+0x70/0x88
do_translation_fault+0x54/0x98
do_mem_abort+0x4c/0xa8
el1_abort+0x44/0x70
el1h_64_sync_handler+0x50/0x108
el1h_64_sync+0x6c/0x70
bpf_prog_a64a9778d31b8e88_stream_arena_write_fault+0x84/0xc8
*(page) = 1; @ stream.c:100
bpf_prog_test_run_syscall+0x100/0x328
__sys_bpf+0x508/0xb98
__arm64_sys_bpf+0x2c/0x48
invoke_syscall+0x50/0x120
el0_svc_common.constprop.0+0x48/0xf8
do_el0_svc+0x28/0x40
el0_svc+0x48/0xf8
el0t_64_sync_handler+0xa0/0xe8
el0t_64_sync+0x198/0x1a0
Same address is seen by using bpf_printk():
1389.078831: bpf_trace_printk: Read Address: 0xdeaddead0000
To make this possible, some extra metadata has to be passed to the bpf
exception handler, so the bpf exception handling mechanism for both
x86-64 and arm64 have been improved in this set.
The streams selftest has been updated to also test this new feature.
Puranjay Mohan (4):
bpf: arm64: simplify exception table handling
bpf: core: introduce main_prog_aux for stream access
bpf: Report arena faults to BPF stderr
selftests/bpf: Add tests for arena fault reporting
arch/arm64/net/bpf_jit_comp.c | 77 ++++++++++++------
arch/x86/net/bpf_jit_comp.c | 79 ++++++++++++++++++-
include/linux/bpf.h | 7 ++
kernel/bpf/arena.c | 27 +++++++
kernel/bpf/core.c | 3 +-
kernel/bpf/stream.c | 6 +-
kernel/bpf/verifier.c | 1 +
.../testing/selftests/bpf/prog_tests/stream.c | 34 +++++++-
tools/testing/selftests/bpf/progs/stream.c | 61 ++++++++++++++
9 files changed, 263 insertions(+), 32 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH bpf-next v5 1/4] bpf: arm64: simplify exception table handling
2025-09-01 19:37 [PATCH bpf-next v5 0/4] bpf: report arena faults to BPF streams Puranjay Mohan
@ 2025-09-01 19:37 ` Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access Puranjay Mohan
` (2 subsequent siblings)
3 siblings, 0 replies; 11+ messages in thread
From: Puranjay Mohan @ 2025-09-01 19:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Puranjay Mohan, Xu Kuohai, Catalin Marinas, Will Deacon,
Kumar Kartikeya Dwivedi, bpf
Cc: Xu Kuohai
BPF loads with BPF_PROBE_MEM(SX) can load from unsafe pointers and the
JIT adds an exception table entry for the JITed instruction which allows
the exeption handler to set the destination register of the load to zero
and continue execution from the next instruction.
As all arm64 instructions are AARCH64_INSN_SIZE size, the exception
handler can just increment the pc by AARCH64_INSN_SIZE without needing
the exact address of the instruction following the the faulting
instruction.
Simplify the exception table usage in arm64 JIT by only saving the
destination register in ex->fixup and drop everything related to
the fixup_offset. The fault handler is modified to add AARCH64_INSN_SIZE
to the pc.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Xu Kuohai <xukuohai@huawei.com>
---
arch/arm64/net/bpf_jit_comp.c | 25 +++----------------------
1 file changed, 3 insertions(+), 22 deletions(-)
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index a98b8132479a7..9b3162ff63e9c 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1066,19 +1066,18 @@ static void build_epilogue(struct jit_ctx *ctx, bool was_classic)
emit(A64_RET(A64_LR), ctx);
}
-#define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0)
#define BPF_FIXUP_REG_MASK GENMASK(31, 27)
#define DONT_CLEAR 5 /* Unused ARM64 register from BPF's POV */
bool ex_handler_bpf(const struct exception_table_entry *ex,
struct pt_regs *regs)
{
- off_t offset = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup);
int dst_reg = FIELD_GET(BPF_FIXUP_REG_MASK, ex->fixup);
if (dst_reg != DONT_CLEAR)
regs->regs[dst_reg] = 0;
- regs->pc = (unsigned long)&ex->fixup - offset;
+ /* Skip the faulting instruction */
+ regs->pc += AARCH64_INSN_SIZE;
return true;
}
@@ -1088,7 +1087,6 @@ static int add_exception_handler(const struct bpf_insn *insn,
int dst_reg)
{
off_t ins_offset;
- off_t fixup_offset;
unsigned long pc;
struct exception_table_entry *ex;
@@ -1119,22 +1117,6 @@ static int add_exception_handler(const struct bpf_insn *insn,
if (WARN_ON_ONCE(ins_offset >= 0 || ins_offset < INT_MIN))
return -ERANGE;
- /*
- * Since the extable follows the program, the fixup offset is always
- * negative and limited to BPF_JIT_REGION_SIZE. Store a positive value
- * to keep things simple, and put the destination register in the upper
- * bits. We don't need to worry about buildtime or runtime sort
- * modifying the upper bits because the table is already sorted, and
- * isn't part of the main exception table.
- *
- * The fixup_offset is set to the next instruction from the instruction
- * that may fault. The execution will jump to this after handling the
- * fault.
- */
- fixup_offset = (long)&ex->fixup - (pc + AARCH64_INSN_SIZE);
- if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, fixup_offset))
- return -ERANGE;
-
/*
* The offsets above have been calculated using the RO buffer but we
* need to use the R/W buffer for writes.
@@ -1147,8 +1129,7 @@ static int add_exception_handler(const struct bpf_insn *insn,
if (BPF_CLASS(insn->code) != BPF_LDX)
dst_reg = DONT_CLEAR;
- ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, fixup_offset) |
- FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
+ ex->fixup = FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
ex->type = EX_TYPE_BPF;
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access
2025-09-01 19:37 [PATCH bpf-next v5 0/4] bpf: report arena faults to BPF streams Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 1/4] bpf: arm64: simplify exception table handling Puranjay Mohan
@ 2025-09-01 19:37 ` Puranjay Mohan
2025-09-02 2:25 ` Alexei Starovoitov
2025-09-01 19:37 ` [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting Puranjay Mohan
3 siblings, 1 reply; 11+ messages in thread
From: Puranjay Mohan @ 2025-09-01 19:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Puranjay Mohan, Xu Kuohai, Catalin Marinas, Will Deacon,
Kumar Kartikeya Dwivedi, bpf
BPF streams are only valid for the main programs, to make it easier to
access streams from subprogs, introduce main_prog_aux in struct
bpf_prog_aux.
prog->aux->main_prog_aux = prog->aux, for main programs and
prog->aux->main_prog_aux = main_prog->aux, for subprograms.
This makes it easy to access streams like:
stream = bpf_stream_get(stream_id, prog->main_prog_aux);
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
---
include/linux/bpf.h | 1 +
kernel/bpf/core.c | 3 +--
kernel/bpf/stream.c | 6 +++---
kernel/bpf/verifier.c | 1 +
4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 8f6e87f0f3a89..d133171c4d2a9 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1633,6 +1633,7 @@ struct bpf_prog_aux {
/* function name for valid attach_btf_id */
const char *attach_func_name;
struct bpf_prog **func;
+ struct bpf_prog_aux *main_prog_aux;
void *jit_data; /* JIT specific data. arch dependent */
struct bpf_jit_poke_descriptor *poke_tab;
struct bpf_kfunc_desc_tab *kfunc_tab;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index ef01cc644a965..dbbf8e4b6e4c2 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -120,6 +120,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
fp->pages = size / PAGE_SIZE;
fp->aux = aux;
+ fp->aux->main_prog_aux = aux;
fp->aux->prog = fp;
fp->jit_requested = ebpf_jit_enabled();
fp->blinding_requested = bpf_jit_blinding_enabled(fp);
@@ -3292,8 +3293,6 @@ static bool find_from_stack_cb(void *cookie, u64 ip, u64 sp, u64 bp)
rcu_read_unlock();
if (!prog)
return true;
- if (bpf_is_subprog(prog))
- return true;
ctxp->prog = prog;
return false;
}
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index ab592db4a4bf6..a36dee4a95d59 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -343,7 +343,7 @@ int bpf_prog_stream_read(struct bpf_prog *prog, enum bpf_stream_id stream_id, vo
{
struct bpf_stream *stream;
- stream = bpf_stream_get(stream_id, prog->aux);
+ stream = bpf_stream_get(stream_id, prog->aux->main_prog_aux);
if (!stream)
return -ENOENT;
return bpf_stream_read(stream, buf, len);
@@ -367,7 +367,7 @@ __bpf_kfunc int bpf_stream_vprintk(int stream_id, const char *fmt__str, const vo
u32 data_len = len__sz;
int ret, num_args;
- stream = bpf_stream_get(stream_id, aux);
+ stream = bpf_stream_get(stream_id, aux->main_prog_aux);
if (!stream)
return -ENOENT;
@@ -457,7 +457,7 @@ int bpf_stream_stage_commit(struct bpf_stream_stage *ss, struct bpf_prog *prog,
struct bpf_stream *stream;
int ret;
- stream = bpf_stream_get(stream_id, prog->aux);
+ stream = bpf_stream_get(stream_id, prog->aux->main_prog_aux);
if (!stream)
return -EINVAL;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5c9dd16b2c56b..fa110656099c4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -21597,6 +21597,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
func[i]->aux->func_info_cnt = prog->aux->func_info_cnt;
func[i]->aux->poke_tab = prog->aux->poke_tab;
func[i]->aux->size_poke_tab = prog->aux->size_poke_tab;
+ func[i]->aux->main_prog_aux = prog->aux;
for (j = 0; j < prog->aux->size_poke_tab; j++) {
struct bpf_jit_poke_descriptor *poke;
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr
2025-09-01 19:37 [PATCH bpf-next v5 0/4] bpf: report arena faults to BPF streams Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 1/4] bpf: arm64: simplify exception table handling Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access Puranjay Mohan
@ 2025-09-01 19:37 ` Puranjay Mohan
2025-09-02 12:42 ` kernel test robot
2025-09-03 0:01 ` Eduard Zingerman
2025-09-01 19:37 ` [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting Puranjay Mohan
3 siblings, 2 replies; 11+ messages in thread
From: Puranjay Mohan @ 2025-09-01 19:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Puranjay Mohan, Xu Kuohai, Catalin Marinas, Will Deacon,
Kumar Kartikeya Dwivedi, bpf
Begin reporting arena page faults and the faulting address to BPF
program's stderr, this patch adds support in the arm64 and x86-64 JITs,
support for other archs can be added later.
The fault handlers receive the 32 bit address in the arena region so
the upper 32 bits of user_vm_start is added to it before printing the
address. This is what the user would expect to see as this is what is
printed by bpf_printk() is you pass it an address returned by
bpf_arena_alloc_pages();
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
---
arch/arm64/net/bpf_jit_comp.c | 52 +++++++++++++++++++++++
arch/x86/net/bpf_jit_comp.c | 79 +++++++++++++++++++++++++++++++++--
include/linux/bpf.h | 6 +++
kernel/bpf/arena.c | 27 ++++++++++++
4 files changed, 160 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 9b3162ff63e9c..b18abe0b1a104 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1066,6 +1066,30 @@ static void build_epilogue(struct jit_ctx *ctx, bool was_classic)
emit(A64_RET(A64_LR), ctx);
}
+/*
+ * Metadata encoding for exception handling in JITed code.
+ *
+ * Format of `fixup` field in `struct exception_table_entry`:
+ *
+ * Bit layout of `fixup` (32-bit):
+ *
+ * +-----------+--------+-----------+-----------+----------+
+ * | 31-27 | 26-22 | 21 | 20-16 | 15-0 |
+ * | | | | | |
+ * | FIXUP_REG | Unused | 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.
+ * - FIXUP_REG (5 bits): Destination register for the load instruction (cleared on fault) or set to
+ * DONT_CLEAR if it is a store instruction.
+ */
+
+#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_FIXUP_REG_MASK GENMASK(31, 27)
#define DONT_CLEAR 5 /* Unused ARM64 register from BPF's POV */
@@ -1073,11 +1097,22 @@ bool ex_handler_bpf(const struct exception_table_entry *ex,
struct pt_regs *regs)
{
int dst_reg = FIELD_GET(BPF_FIXUP_REG_MASK, ex->fixup);
+ 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);
+ unsigned long addr;
+
+ if (is_arena) {
+ addr = regs->regs[arena_reg] + off;
+ bpf_prog_report_arena_violation(is_write, addr, regs->pc);
+ }
if (dst_reg != DONT_CLEAR)
regs->regs[dst_reg] = 0;
/* Skip the faulting instruction */
regs->pc += AARCH64_INSN_SIZE;
+
return true;
}
@@ -1087,6 +1122,9 @@ static int add_exception_handler(const struct bpf_insn *insn,
int dst_reg)
{
off_t ins_offset;
+ s16 off = insn->off;
+ bool is_arena;
+ int arena_reg;
unsigned long pc;
struct exception_table_entry *ex;
@@ -1100,6 +1138,9 @@ static int add_exception_handler(const struct bpf_insn *insn,
BPF_MODE(insn->code) != BPF_PROBE_ATOMIC)
return 0;
+ is_arena = (BPF_MODE(insn->code) == BPF_PROBE_MEM32) ||
+ (BPF_MODE(insn->code) == BPF_PROBE_ATOMIC);
+
if (!ctx->prog->aux->extable ||
WARN_ON_ONCE(ctx->exentry_idx >= ctx->prog->aux->num_exentries))
return -EINVAL;
@@ -1131,6 +1172,17 @@ static int add_exception_handler(const struct bpf_insn *insn,
ex->fixup = FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
+ if (is_arena) {
+ ex->fixup |= BPF_ARENA_ACCESS;
+ if (BPF_CLASS(insn->code) == BPF_LDX)
+ arena_reg = bpf2a64[insn->src_reg];
+ else
+ arena_reg = bpf2a64[insn->dst_reg];
+
+ ex->fixup |= FIELD_PREP(BPF_FIXUP_OFFSET_MASK, off) |
+ FIELD_PREP(BPF_FIXUP_ARENA_REG_MASK, arena_reg);
+ }
+
ex->type = EX_TYPE_BPF;
ctx->exentry_idx++;
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 7e3fca1646203..644424ae5e5d2 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include <linux/filter.h>
#include <linux/if_vlan.h>
+#include <linux/bitfield.h>
#include <linux/bpf.h>
#include <linux/memory.h>
#include <linux/sort.h>
@@ -1388,16 +1389,67 @@ static int emit_atomic_ld_st_index(u8 **pprog, u32 atomic_op, u32 size,
return 0;
}
+/*
+ * Metadata encoding for exception handling in JITed code.
+ *
+ * Format of `fixup` and `data` fields in `struct exception_table_entry`:
+ *
+ * Bit layout of `fixup` (32-bit):
+ *
+ * +-----------+--------+-----------+---------+----------+
+ * | 31 | 30-24 | 23-16 | 15-8 | 7-0 |
+ * | | | | | |
+ * | ARENA_ACC | Unused | ARENA_REG | DST_REG | INSN_LEN |
+ * +-----------+--------+-----------+---------+----------+
+ *
+ * - INSN_LEN (8 bits): Length of faulting insn (max x86 insn = 15 bytes (fits in 8 bits)).
+ * - DST_REG (8 bits): Offset of dst_reg from reg2pt_regs[] (max offset = 112 (fits in 8 bits)).
+ * This is set to DONT_CLEAR if the insn is a store.
+ * - ARENA_REG (8 bits): Offset of the 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.
+ *
+ * Bit layout of `data` (32-bit):
+ *
+ * +--------------+--------+--------------+
+ * | 31-16 | 15-8 | 7-0 |
+ * | | | |
+ * | ARENA_OFFSET | Unused | EX_TYPE_BPF |
+ * +--------------+--------+--------------+
+ *
+ * - ARENA_OFFSET (16 bits): Offset used to calculate the address for load/store when
+ * accessing the arena region.
+ */
+
#define DONT_CLEAR 1
+#define FIXUP_INSN_LEN_MASK GENMASK(7, 0)
+#define FIXUP_REG_MASK GENMASK(15, 8)
+#define FIXUP_ARENA_REG_MASK GENMASK(23, 16)
+#define FIXUP_ARENA_ACCESS BIT(31)
+#define DATA_ARENA_OFFSET_MASK GENMASK(31, 16)
bool ex_handler_bpf(const struct exception_table_entry *x, struct pt_regs *regs)
{
- u32 reg = x->fixup >> 8;
+ u32 reg = FIELD_GET(FIXUP_REG_MASK, x->fixup);
+ u32 insn_len = FIELD_GET(FIXUP_INSN_LEN_MASK, x->fixup);
+ bool is_arena = !!(x->fixup & FIXUP_ARENA_ACCESS);
+ bool is_write = (reg == DONT_CLEAR);
+ unsigned long addr;
+ s16 off;
+ u32 arena_reg;
+
+ if (is_arena) {
+ arena_reg = FIELD_GET(FIXUP_ARENA_REG_MASK, x->fixup);
+ off = FIELD_GET(DATA_ARENA_OFFSET_MASK, x->data);
+ addr = *(unsigned long *)((void *)regs + arena_reg) + off;
+ bpf_prog_report_arena_violation(is_write, addr, regs->ip);
+ }
/* jump over faulting load and clear dest register */
if (reg != DONT_CLEAR)
*(unsigned long *)((void *)regs + reg) = 0;
- regs->ip += x->fixup & 0xff;
+ regs->ip += insn_len;
+
return true;
}
@@ -2070,6 +2122,8 @@ st: if (is_imm8(insn->off))
{
struct exception_table_entry *ex;
u8 *_insn = image + proglen + (start_of_ldx - temp);
+ u32 arena_reg, fixup_reg;
+ bool is_arena;
s64 delta;
if (!bpf_prog->aux->extable)
@@ -2089,8 +2143,25 @@ st: if (is_imm8(insn->off))
ex->data = EX_TYPE_BPF;
- ex->fixup = (prog - start_of_ldx) |
- ((BPF_CLASS(insn->code) == BPF_LDX ? reg2pt_regs[dst_reg] : DONT_CLEAR) << 8);
+ is_arena = (BPF_MODE(insn->code) == BPF_PROBE_MEM32) ||
+ (BPF_MODE(insn->code) == BPF_PROBE_ATOMIC);
+
+ fixup_reg = (BPF_CLASS(insn->code) == BPF_LDX) ?
+ reg2pt_regs[dst_reg] : DONT_CLEAR;
+
+ ex->fixup = FIELD_PREP(FIXUP_INSN_LEN_MASK, prog - start_of_ldx) |
+ FIELD_PREP(FIXUP_REG_MASK, fixup_reg);
+
+ if (is_arena) {
+ ex->fixup |= FIXUP_ARENA_ACCESS;
+ if (BPF_CLASS(insn->code) == BPF_LDX)
+ arena_reg = reg2pt_regs[src_reg];
+ else
+ arena_reg = reg2pt_regs[dst_reg];
+
+ ex->fixup |= FIELD_PREP(FIXUP_ARENA_REG_MASK, arena_reg);
+ ex->data |= FIELD_PREP(DATA_ARENA_OFFSET_MASK, insn->off);
+ }
}
break;
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index d133171c4d2a9..fa4d964353f30 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2014,6 +2014,7 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
struct bpf_verifier_log *log);
void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map);
void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc);
+void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip);
#else
#define register_bpf_struct_ops(st_ops, type) ({ (void *)(st_ops); 0; })
static inline bool bpf_try_module_get(const void *data, struct module *owner)
@@ -2046,6 +2047,11 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
{
}
+static inline void bpf_prog_report_arena_violation(bool write, unsigned long addr,
+ unsigned long fault_ip)
+{
+}
+
#endif
int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 5b37753799d20..7c6a2bd423c48 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -633,3 +633,30 @@ static int __init kfunc_init(void)
return register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &common_kfunc_set);
}
late_initcall(kfunc_init);
+
+void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip)
+{
+ struct bpf_stream_stage ss;
+ struct bpf_prog *prog;
+ u64 user_vm_start;
+
+ /*
+ * The RCU read lock is held to safely traverse the latch tree, but we
+ * don't need its protection when accessing the prog, since it will not
+ * disappear while we are handling the fault.
+ */
+ rcu_read_lock();
+ prog = bpf_prog_ksym_find(fault_ip);
+ rcu_read_unlock();
+ if (!prog)
+ return;
+
+ user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
+ addr += (user_vm_start >> 32) << 32;
+
+ bpf_stream_stage(ss, prog, BPF_STDERR, ({
+ bpf_stream_printk(ss, "ERROR: Arena %s access at unmapped address 0x%lx\n",
+ write ? "WRITE" : "READ", addr);
+ bpf_stream_dump_stack(ss);
+ }));
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting
2025-09-01 19:37 [PATCH bpf-next v5 0/4] bpf: report arena faults to BPF streams Puranjay Mohan
` (2 preceding siblings ...)
2025-09-01 19:37 ` [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr Puranjay Mohan
@ 2025-09-01 19:37 ` Puranjay Mohan
2025-09-02 16:22 ` Yonghong Song
2025-09-02 22:21 ` Eduard Zingerman
3 siblings, 2 replies; 11+ messages in thread
From: Puranjay Mohan @ 2025-09-01 19:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Puranjay Mohan, Xu Kuohai, Catalin Marinas, Will Deacon,
Kumar Kartikeya Dwivedi, bpf
Add selftests for testing the reporting of arena page faults through BPF
streams. Two new bpf programs are added that read and write to an
unmapped arena address and the fault reporting is verified in the
userspace through streams.
The added bpf programs need to access the user_vm_start in struct
bpf_arena, this is done by casting &arena to struct bpf_arena *, but
barrier_var() is used on this ptr before accessing ptr->user_vm_start;
to stop GCC from issuing an out-of-bound access due to the cast from
smaller map struct to larger "struct bpf_arena"
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
---
.../testing/selftests/bpf/prog_tests/stream.c | 34 ++++++++++-
tools/testing/selftests/bpf/progs/stream.c | 61 +++++++++++++++++++
2 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/stream.c b/tools/testing/selftests/bpf/prog_tests/stream.c
index 9d0e5d93edee7..b2a85364e3c4f 100644
--- a/tools/testing/selftests/bpf/prog_tests/stream.c
+++ b/tools/testing/selftests/bpf/prog_tests/stream.c
@@ -41,6 +41,22 @@ struct {
"([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
"|[ \t]+[^\n]+\n)*",
},
+ {
+ offsetof(struct stream, progs.stream_arena_read_fault),
+ "ERROR: Arena READ access at unmapped address 0x.*\n"
+ "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
+ "Call trace:\n"
+ "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
+ "|[ \t]+[^\n]+\n)*",
+ },
+ {
+ offsetof(struct stream, progs.stream_arena_write_fault),
+ "ERROR: Arena WRITE access at unmapped address 0x.*\n"
+ "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
+ "Call trace:\n"
+ "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
+ "|[ \t]+[^\n]+\n)*",
+ },
};
static int match_regex(const char *pattern, const char *string)
@@ -63,6 +79,7 @@ void test_stream_errors(void)
struct stream *skel;
int ret, prog_fd;
char buf[1024];
+ char fault_addr[64] = {0};
skel = stream__open_and_load();
if (!ASSERT_OK_PTR(skel, "stream__open_and_load"))
@@ -85,6 +102,14 @@ void test_stream_errors(void)
continue;
}
#endif
+#if !defined(__x86_64__) && !defined(__aarch64__)
+ ASSERT_TRUE(1, "Arena fault reporting unsupported, skip.");
+ if (i == 2 || i == 3) {
+ ret = bpf_prog_stream_read(prog_fd, 2, buf, sizeof(buf), &ropts);
+ ASSERT_EQ(ret, 0, "stream read");
+ continue;
+ }
+#endif
ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, sizeof(buf), &ropts);
ASSERT_GT(ret, 0, "stream read");
@@ -92,8 +117,15 @@ void test_stream_errors(void)
buf[ret] = '\0';
ret = match_regex(stream_error_arr[i].errstr, buf);
- if (!ASSERT_TRUE(ret == 1, "regex match"))
+ if (ret && (i == 2 || i == 3)) {
+ sprintf(fault_addr, "0x%lx", skel->bss->fault_addr);
+ ret = match_regex(fault_addr, buf);
+ }
+ if (!ASSERT_TRUE(ret == 1, "regex match")) {
fprintf(stderr, "Output from stream:\n%s\n", buf);
+ if (i == 2 || i == 3)
+ fprintf(stderr, "Fault Addr: 0x%lx\n", skel->bss->fault_addr);
+ }
}
stream__destroy(skel);
diff --git a/tools/testing/selftests/bpf/progs/stream.c b/tools/testing/selftests/bpf/progs/stream.c
index 35790897dc879..8ca6d3396a20a 100644
--- a/tools/testing/selftests/bpf/progs/stream.c
+++ b/tools/testing/selftests/bpf/progs/stream.c
@@ -5,6 +5,7 @@
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
#include "bpf_experimental.h"
+#include "bpf_arena_common.h"
struct arr_elem {
struct bpf_res_spin_lock lock;
@@ -17,10 +18,17 @@ struct {
__type(value, struct arr_elem);
} arrmap SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_ARENA);
+ __uint(map_flags, BPF_F_MMAPABLE);
+ __uint(max_entries, 1); /* number of pages */
+} arena SEC(".maps");
+
#define ENOSPC 28
#define _STR "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
int size;
+u64 fault_addr;
SEC("syscall")
__success __retval(0)
@@ -76,4 +84,57 @@ int stream_syscall(void *ctx)
return 0;
}
+SEC("syscall")
+__success __retval(0)
+int stream_arena_write_fault(void *ctx)
+{
+ struct bpf_arena *ptr = (void *)&arena;
+ u64 user_vm_start;
+
+ /* Prevent GCC bounds warning: casting &arena to struct bpf_arena *
+ * triggers bounds checking since the map definition is smaller than struct
+ * bpf_arena. barrier_var() makes the pointer opaque to GCC, preventing the
+ * bounds analysis
+ */
+ barrier_var(ptr);
+ user_vm_start = ptr->user_vm_start;
+ fault_addr = user_vm_start + 0x7fff;
+ bpf_addr_space_cast(user_vm_start, 0, 1);
+ asm volatile (
+ "r1 = %0;"
+ "r2 = 1;"
+ "*(u32 *)(r1 + 0x7fff) = r2;"
+ :
+ : "r" (user_vm_start)
+ : "r1", "r2"
+ );
+ return 0;
+}
+
+SEC("syscall")
+__success __retval(0)
+int stream_arena_read_fault(void *ctx)
+{
+ struct bpf_arena *ptr = (void *)&arena;
+ u64 user_vm_start;
+
+ /* Prevent GCC bounds warning: casting &arena to struct bpf_arena *
+ * triggers bounds checking since the map definition is smaller than struct
+ * bpf_arena. barrier_var() makes the pointer opaque to GCC, preventing the
+ * bounds analysis
+ */
+ barrier_var(ptr);
+ user_vm_start = ptr->user_vm_start;
+ fault_addr = user_vm_start + 0x7fff;
+ bpf_addr_space_cast(user_vm_start, 0, 1);
+ asm volatile (
+ "r1 = %0;"
+ "r1 = *(u32 *)(r1 + 0x7fff);"
+ :
+ : "r" (user_vm_start)
+ : "r1"
+ );
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access
2025-09-01 19:37 ` [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access Puranjay Mohan
@ 2025-09-02 2:25 ` Alexei Starovoitov
2025-09-02 2:32 ` Kumar Kartikeya Dwivedi
0 siblings, 1 reply; 11+ messages in thread
From: Alexei Starovoitov @ 2025-09-02 2:25 UTC (permalink / raw)
To: Puranjay Mohan
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Xu Kuohai, Catalin Marinas, Will Deacon, Kumar Kartikeya Dwivedi,
bpf
On Mon, Sep 1, 2025 at 12:37 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> BPF streams are only valid for the main programs, to make it easier to
> access streams from subprogs, introduce main_prog_aux in struct
> bpf_prog_aux.
>
> prog->aux->main_prog_aux = prog->aux, for main programs and
> prog->aux->main_prog_aux = main_prog->aux, for subprograms.
>
> This makes it easy to access streams like:
> stream = bpf_stream_get(stream_id, prog->main_prog_aux);
>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> ---
> include/linux/bpf.h | 1 +
> kernel/bpf/core.c | 3 +--
> kernel/bpf/stream.c | 6 +++---
> kernel/bpf/verifier.c | 1 +
> 4 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 8f6e87f0f3a89..d133171c4d2a9 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1633,6 +1633,7 @@ struct bpf_prog_aux {
> /* function name for valid attach_btf_id */
> const char *attach_func_name;
> struct bpf_prog **func;
> + struct bpf_prog_aux *main_prog_aux;
> void *jit_data; /* JIT specific data. arch dependent */
> struct bpf_jit_poke_descriptor *poke_tab;
> struct bpf_kfunc_desc_tab *kfunc_tab;
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index ef01cc644a965..dbbf8e4b6e4c2 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -120,6 +120,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
>
> fp->pages = size / PAGE_SIZE;
> fp->aux = aux;
> + fp->aux->main_prog_aux = aux;
Though I agree that it's not strictly necessary, this approach
is so much easier to reason about.
Kumar, wdyt?
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access
2025-09-02 2:25 ` Alexei Starovoitov
@ 2025-09-02 2:32 ` Kumar Kartikeya Dwivedi
0 siblings, 0 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2025-09-02 2:32 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Puranjay Mohan, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
Hao Luo, Jiri Olsa, Xu Kuohai, Catalin Marinas, Will Deacon, bpf
On Tue, 2 Sept 2025 at 04:25, Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Mon, Sep 1, 2025 at 12:37 PM Puranjay Mohan <puranjay@kernel.org> wrote:
> >
> > BPF streams are only valid for the main programs, to make it easier to
> > access streams from subprogs, introduce main_prog_aux in struct
> > bpf_prog_aux.
> >
> > prog->aux->main_prog_aux = prog->aux, for main programs and
> > prog->aux->main_prog_aux = main_prog->aux, for subprograms.
> >
> > This makes it easy to access streams like:
> > stream = bpf_stream_get(stream_id, prog->main_prog_aux);
> >
> > Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> > ---
> > include/linux/bpf.h | 1 +
> > kernel/bpf/core.c | 3 +--
> > kernel/bpf/stream.c | 6 +++---
> > kernel/bpf/verifier.c | 1 +
> > 4 files changed, 6 insertions(+), 5 deletions(-)
> >
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index 8f6e87f0f3a89..d133171c4d2a9 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
> > @@ -1633,6 +1633,7 @@ struct bpf_prog_aux {
> > /* function name for valid attach_btf_id */
> > const char *attach_func_name;
> > struct bpf_prog **func;
> > + struct bpf_prog_aux *main_prog_aux;
> > void *jit_data; /* JIT specific data. arch dependent */
> > struct bpf_jit_poke_descriptor *poke_tab;
> > struct bpf_kfunc_desc_tab *kfunc_tab;
> > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > index ef01cc644a965..dbbf8e4b6e4c2 100644
> > --- a/kernel/bpf/core.c
> > +++ b/kernel/bpf/core.c
> > @@ -120,6 +120,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
> >
> > fp->pages = size / PAGE_SIZE;
> > fp->aux = aux;
> > + fp->aux->main_prog_aux = aux;
>
> Though I agree that it's not strictly necessary, this approach
> is so much easier to reason about.
>
> Kumar, wdyt?
Yeah, nbd, this looks fine as well.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr
2025-09-01 19:37 ` [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr Puranjay Mohan
@ 2025-09-02 12:42 ` kernel test robot
2025-09-03 0:01 ` Eduard Zingerman
1 sibling, 0 replies; 11+ messages in thread
From: kernel test robot @ 2025-09-02 12:42 UTC (permalink / raw)
To: Puranjay Mohan, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
Hao Luo, Jiri Olsa, Xu Kuohai, Catalin Marinas, Will Deacon,
Kumar Kartikeya Dwivedi, bpf
Cc: llvm, oe-kbuild-all
Hi Puranjay,
kernel test robot noticed the following build errors:
[auto build test ERROR on bpf-next/master]
url: https://github.com/intel-lab-lkp/linux/commits/Puranjay-Mohan/bpf-arm64-simplify-exception-table-handling/20250902-033833
base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link: https://lore.kernel.org/r/20250901193730.43543-4-puranjay%40kernel.org
patch subject: [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr
config: x86_64-buildonly-randconfig-002-20250902 (https://download.01.org/0day-ci/archive/20250902/202509022034.z1178h4W-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250902/202509022034.z1178h4W-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509022034.z1178h4W-lkp@intel.com/
All errors (new ones prefixed by >>):
>> kernel/bpf/arena.c:637:6: error: redefinition of 'bpf_prog_report_arena_violation'
637 | void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip)
| ^
include/linux/bpf.h:2050:20: note: previous definition is here
2050 | static inline void bpf_prog_report_arena_violation(bool write, unsigned long addr,
| ^
1 error generated.
vim +/bpf_prog_report_arena_violation +637 kernel/bpf/arena.c
636
> 637 void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting
2025-09-01 19:37 ` [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting Puranjay Mohan
@ 2025-09-02 16:22 ` Yonghong Song
2025-09-02 22:21 ` Eduard Zingerman
1 sibling, 0 replies; 11+ messages in thread
From: Yonghong Song @ 2025-09-02 16:22 UTC (permalink / raw)
To: Puranjay Mohan, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Xu Kuohai, Catalin Marinas, Will Deacon, Kumar Kartikeya Dwivedi,
bpf
On 9/1/25 12:37 PM, Puranjay Mohan wrote:
> Add selftests for testing the reporting of arena page faults through BPF
> streams. Two new bpf programs are added that read and write to an
> unmapped arena address and the fault reporting is verified in the
> userspace through streams.
>
> The added bpf programs need to access the user_vm_start in struct
> bpf_arena, this is done by casting &arena to struct bpf_arena *, but
> barrier_var() is used on this ptr before accessing ptr->user_vm_start;
> to stop GCC from issuing an out-of-bound access due to the cast from
> smaller map struct to larger "struct bpf_arena"
>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
LGTM with one nit below.
Acked-by: Yonghong Song <yonghong.song@linux.dev>
> ---
> .../testing/selftests/bpf/prog_tests/stream.c | 34 ++++++++++-
> tools/testing/selftests/bpf/progs/stream.c | 61 +++++++++++++++++++
> 2 files changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/stream.c b/tools/testing/selftests/bpf/prog_tests/stream.c
> index 9d0e5d93edee7..b2a85364e3c4f 100644
> --- a/tools/testing/selftests/bpf/prog_tests/stream.c
> +++ b/tools/testing/selftests/bpf/prog_tests/stream.c
> @@ -41,6 +41,22 @@ struct {
> "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> "|[ \t]+[^\n]+\n)*",
> },
> + {
> + offsetof(struct stream, progs.stream_arena_read_fault),
> + "ERROR: Arena READ access at unmapped address 0x.*\n"
> + "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
> + "Call trace:\n"
> + "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> + "|[ \t]+[^\n]+\n)*",
> + },
> + {
> + offsetof(struct stream, progs.stream_arena_write_fault),
> + "ERROR: Arena WRITE access at unmapped address 0x.*\n"
> + "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
> + "Call trace:\n"
> + "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> + "|[ \t]+[^\n]+\n)*",
> + },
> };
>
> static int match_regex(const char *pattern, const char *string)
> @@ -63,6 +79,7 @@ void test_stream_errors(void)
> struct stream *skel;
> int ret, prog_fd;
> char buf[1024];
> + char fault_addr[64] = {0};
Looks like the above '= {0}' is not necessary as the only usage
is below:
+ sprintf(fault_addr, "0x%lx", skel->bss->fault_addr);
+ ret = match_regex(fault_addr, buf);
>
> skel = stream__open_and_load();
> if (!ASSERT_OK_PTR(skel, "stream__open_and_load"))
> @@ -85,6 +102,14 @@ void test_stream_errors(void)
> continue;
> }
> #endif
> +#if !defined(__x86_64__) && !defined(__aarch64__)
> + ASSERT_TRUE(1, "Arena fault reporting unsupported, skip.");
> + if (i == 2 || i == 3) {
> + ret = bpf_prog_stream_read(prog_fd, 2, buf, sizeof(buf), &ropts);
> + ASSERT_EQ(ret, 0, "stream read");
> + continue;
> + }
> +#endif
>
> ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, sizeof(buf), &ropts);
> ASSERT_GT(ret, 0, "stream read");
> @@ -92,8 +117,15 @@ void test_stream_errors(void)
> buf[ret] = '\0';
>
> ret = match_regex(stream_error_arr[i].errstr, buf);
> - if (!ASSERT_TRUE(ret == 1, "regex match"))
> + if (ret && (i == 2 || i == 3)) {
> + sprintf(fault_addr, "0x%lx", skel->bss->fault_addr);
> + ret = match_regex(fault_addr, buf);
> + }
> + if (!ASSERT_TRUE(ret == 1, "regex match")) {
> fprintf(stderr, "Output from stream:\n%s\n", buf);
> + if (i == 2 || i == 3)
> + fprintf(stderr, "Fault Addr: 0x%lx\n", skel->bss->fault_addr);
> + }
> }
>
> stream__destroy(skel);
>
[...]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting
2025-09-01 19:37 ` [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting Puranjay Mohan
2025-09-02 16:22 ` Yonghong Song
@ 2025-09-02 22:21 ` Eduard Zingerman
1 sibling, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2025-09-02 22:21 UTC (permalink / raw)
To: Puranjay Mohan, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Xu Kuohai, Catalin Marinas, Will Deacon, Kumar Kartikeya Dwivedi,
bpf
On Mon, 2025-09-01 at 19:37 +0000, Puranjay Mohan wrote:
[...]
> diff --git a/tools/testing/selftests/bpf/prog_tests/stream.c b/tools/testing/selftests/bpf/prog_tests/stream.c
> index 9d0e5d93edee7..b2a85364e3c4f 100644
> --- a/tools/testing/selftests/bpf/prog_tests/stream.c
> +++ b/tools/testing/selftests/bpf/prog_tests/stream.c
> @@ -41,6 +41,22 @@ struct {
> "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> "|[ \t]+[^\n]+\n)*",
> },
> + {
> + offsetof(struct stream, progs.stream_arena_read_fault),
> + "ERROR: Arena READ access at unmapped address 0x.*\n"
> + "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
> + "Call trace:\n"
> + "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> + "|[ \t]+[^\n]+\n)*",
> + },
> + {
> + offsetof(struct stream, progs.stream_arena_write_fault),
> + "ERROR: Arena WRITE access at unmapped address 0x.*\n"
> + "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
> + "Call trace:\n"
> + "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> + "|[ \t]+[^\n]+\n)*",
> + },
I commented when prog_tests/stream.c was first introduced but it was
decided to postpone the change back then.
It would be nice to have the above expressed in terms similar to
bpf_misc.h:__msg() macro. E.g. name it __bpf_{stdout,stderr} and
have something like this in the progs/stream.c:
SEC("syscall")
__success __retval(0)
__bpf_stderr("ERROR: Arena WRITE access at unmapped address 0x{{.*}}")
__bpf_stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
...
int stream_arena_write_fault(void *ctx)
{
...
}
Now that more tests are added, what do you think about such extension?
> };
>
> static int match_regex(const char *pattern, const char *string)
[...]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr
2025-09-01 19:37 ` [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr Puranjay Mohan
2025-09-02 12:42 ` kernel test robot
@ 2025-09-03 0:01 ` Eduard Zingerman
1 sibling, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2025-09-03 0:01 UTC (permalink / raw)
To: Puranjay Mohan, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Xu Kuohai, Catalin Marinas, Will Deacon, Kumar Kartikeya Dwivedi,
bpf
On Mon, 2025-09-01 at 19:37 +0000, Puranjay Mohan wrote:
> Begin reporting arena page faults and the faulting address to BPF
> program's stderr, this patch adds support in the arm64 and x86-64 JITs,
> support for other archs can be added later.
>
> The fault handlers receive the 32 bit address in the arena region so
> the upper 32 bits of user_vm_start is added to it before printing the
> address. This is what the user would expect to see as this is what is
> printed by bpf_printk() is you pass it an address returned by
> bpf_arena_alloc_pages();
>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> Acked-by: Yonghong Song <yonghong.song@linux.dev>
> ---
Fwiw, aside from a nit below the patch looks good to me.
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 7e3fca1646203..644424ae5e5d2 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
[...]
> @@ -2089,8 +2143,25 @@ st: if (is_imm8(insn->off))
>
> ex->data = EX_TYPE_BPF;
>
> - ex->fixup = (prog - start_of_ldx) |
> - ((BPF_CLASS(insn->code) == BPF_LDX ? reg2pt_regs[dst_reg] : DONT_CLEAR) << 8);
> + is_arena = (BPF_MODE(insn->code) == BPF_PROBE_MEM32) ||
> + (BPF_MODE(insn->code) == BPF_PROBE_ATOMIC);
Nit:
It looks like label `populate_extable` is always reachable from either
BPF_PROB_MEM32 or BPF_PROBE_ATOMIC instruction. Non-arena use cases
for BPF_PROBE_MEM{,SX} are handled separately. So, it appears that
this condition is always true.
> +
> + fixup_reg = (BPF_CLASS(insn->code) == BPF_LDX) ?
> + reg2pt_regs[dst_reg] : DONT_CLEAR;
> +
> + ex->fixup = FIELD_PREP(FIXUP_INSN_LEN_MASK, prog - start_of_ldx) |
> + FIELD_PREP(FIXUP_REG_MASK, fixup_reg);
> +
> + if (is_arena) {
> + ex->fixup |= FIXUP_ARENA_ACCESS;
> + if (BPF_CLASS(insn->code) == BPF_LDX)
> + arena_reg = reg2pt_regs[src_reg];
> + else
> + arena_reg = reg2pt_regs[dst_reg];
> +
> + ex->fixup |= FIELD_PREP(FIXUP_ARENA_REG_MASK, arena_reg);
> + ex->data |= FIELD_PREP(DATA_ARENA_OFFSET_MASK, insn->off);
> + }
> }
> break;
>
[...]
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-09-03 0:01 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-01 19:37 [PATCH bpf-next v5 0/4] bpf: report arena faults to BPF streams Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 1/4] bpf: arm64: simplify exception table handling Puranjay Mohan
2025-09-01 19:37 ` [PATCH bpf-next v5 2/4] bpf: core: introduce main_prog_aux for stream access Puranjay Mohan
2025-09-02 2:25 ` Alexei Starovoitov
2025-09-02 2:32 ` Kumar Kartikeya Dwivedi
2025-09-01 19:37 ` [PATCH bpf-next v5 3/4] bpf: Report arena faults to BPF stderr Puranjay Mohan
2025-09-02 12:42 ` kernel test robot
2025-09-03 0:01 ` Eduard Zingerman
2025-09-01 19:37 ` [PATCH bpf-next v5 4/4] selftests/bpf: Add tests for arena fault reporting Puranjay Mohan
2025-09-02 16:22 ` Yonghong Song
2025-09-02 22:21 ` Eduard Zingerman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).