From: Yonghong Song <yonghong.song@linux.dev>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
kernel-team@fb.com
Subject: [PATCH bpf-next v5 08/21] bpf: Walk the exception unwind in the verifier
Date: Tue, 22 Sep 2026 21:59:27 -0700 [thread overview]
Message-ID: <20260923045927.2418543-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260923045846.2414643-1-yonghong.song@linux.dev>
bpf_throw() is about to stop discarding the frames it unwinds and start
running their landing pads instead. Have the verifier walk the same thing,
step for step:
at a throw, with the frame chain in env->cur_state->frame[]:
1. does a record cover the call site control is at?
2. yes: run that record's landing pad in this frame, and on
reaching its resume, pop the frame and go back to 1
3. no: pop the frame and go back to 1
4. frame 0 asks with nothing left to pop: deliver
Doing it this way is what keeps the resource rules unchanged. Whatever a
pad releases is released in the verifier state too, so by the time the walk
reaches the boundary the state says exactly what the program will really
hold there -- and check_resource_leak(), which used to fire the moment a
throw was seen, simply moves to the end of the walk. A frame that no record
covers contributes nothing, so anything it held is still held when the walk
ends, and that is what gets reported.
A pad starts in the state the walker hands it: its own frame's stack and
callee-saved registers, which the walker puts back, and nothing in the
caller-saved ones. r0 is an unknown scalar: LLVM names it as both the
exception pointer and the exception selector register, so a pad reads it
before anything else, and the dispatchers leave a defined value there
rather than whatever the kernel had.
Two things about that walk have to be said out loud, because the
instruction stream does not say them.
A resume belongs to the frame whose landing pad the walker called:
- a JIT lowers it as the way back out of a pad -- a bare return on
x86-64, a branch to the saved address on arm64 -- so it reaches the
walker only from there
- an exception in flight does not say which frame that is: a pad may call
a subprogram whose own pad reaches a resume by ordinary control flow
- so the state records the frame the unwind entered a pad in,
states_equal() keeps two such states apart, a resume in any other frame
is refused, and bpf_insn_successors() reports none for it
The edge from a throw to a pad crosses frames with no instruction in
between, and mark_chain_precision() walks that history backwards:
- left alone it stays in the pad's frame while reading the callee's
instructions: a request for the pad frame's r6 is cleared by the
callee's own write to r6, or reaches a call still set and trips "static
subprog unexpected regs"
- so the history entry for a pad records how many frames the unwind
popped, and the backtrack enters that many, the way it enters one for
BPF_EXIT
- the pad's r0 is whatever the walker left rather than anything an
instruction wrote, so a request for it ends at the edge
- a throwing global subprogram gets no frame of its own, so its exception
arrives at the pad rather than the insn after the call, which
backtrack_insn() has to allow for
This is also where bpf_unwind_resume() becomes callable: the kfunc is
registered here, beside the rule that refuses it outside a pad. Earlier,
nothing refused the call and a JIT rewrites a resume only in a pad, so a
program could reach the kernel body -- a WARN_ONCE whose only job is to say
it should never have been reached.
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
include/linux/bpf_verifier.h | 8 ++-
kernel/bpf/backtrack.c | 41 +++++++++--
kernel/bpf/exception.c | 1 +
kernel/bpf/helpers.c | 1 +
kernel/bpf/liveness.c | 3 +
kernel/bpf/states.c | 6 ++
kernel/bpf/verifier.c | 133 +++++++++++++++++++++++++++--------
7 files changed, 158 insertions(+), 35 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index e12ec91b8150..3146f707e030 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -429,7 +429,8 @@ struct bpf_jmp_history_entry {
u32 prev_idx : 20;
/* special INSN_F_xxx flags */
u32 flags : 4;
- u32 : 8;
+ u32 unwind_frames : 4; /* frames popped to reach this landing pad */
+ u32 : 4;
/*
* additional registers that need precision tracking when this
* jump is backtracked, vector of five 11-bit records
@@ -510,6 +511,9 @@ struct bpf_verifier_state {
bool speculative;
bool in_sleepable;
+ bool unwinding; /* an exception is in flight */
+ u8 unwind_frameno; /* the frame whose landing pad is running */
+
/* first and last insn idx of this verifier state */
u32 first_insn_idx;
u32 last_insn_idx;
@@ -991,6 +995,8 @@ struct bpf_verifier_env {
} cfg;
struct backtrack_state bt;
struct bpf_jmp_history_entry *cur_hist_ent;
+ u8 cur_unwind_frames; /* frames popped to reach this insn, if a pad */
+ u8 unwind_frames; /* frames popped, staged for the next insn */
/* Per-callsite copy of parent's converged at_stack_in for cross-frame fills. */
struct arg_track **callsite_at_stack;
u32 pass_cnt; /* number of times do_check() was called */
diff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c
index 507a366dffa4..88da73345f01 100644
--- a/kernel/bpf/backtrack.c
+++ b/kernel/bpf/backtrack.c
@@ -4,6 +4,7 @@
#include <linux/bpf_verifier.h>
#include <linux/filter.h>
#include <linux/bitmap.h>
+#include "exception.h"
#define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
@@ -47,6 +48,7 @@ int bpf_push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_state
p->flags = insn_flags;
p->spi = spi;
p->frame = frame;
+ p->unwind_frames = env->cur_unwind_frames;
p->linked_regs = linked_regs;
cur->jmp_history_cnt = cnt;
env->cur_hist_ent = p;
@@ -419,10 +421,12 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
* extra instructions from subprog; the next
* instruction after call to global subprog
* should be literally next instruction in
- * caller program
+ * caller program -- or, if the callee threw,
+ * the landing pad of this call site
*/
- verifier_bug_if(idx + 1 != subseq_idx, env,
- "extra insn from subprog");
+ verifier_bug_if(idx + 1 != subseq_idx &&
+ bpf_exc_pad_of_call(env, idx) != subseq_idx,
+ env, "extra insn from subprog");
/* global subprog always sets R0 */
bt_clear_reg(bt, BPF_REG_0);
/* and if it does not set R2, main pass would catch it */
@@ -823,6 +827,7 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
struct bpf_func_state *func;
bool tmp, skip_first = true;
struct bpf_reg_state *reg;
+ u32 pending_unwind = 0;
int i, fr, err;
if (!env->bpf_capable)
@@ -888,11 +893,19 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
}
for (i = last_idx;;) {
+ hist = get_jmp_hist_entry(st, history, i);
+ /*
+ * The insn about to be read sits on the far side of an
+ * unwind edge, so enter the frames that edge crossed
+ * before reading it.
+ */
+ for (; pending_unwind; pending_unwind--)
+ if (bt_subprog_enter(bt))
+ return -EFAULT;
if (skip_first) {
err = 0;
skip_first = false;
} else {
- hist = get_jmp_hist_entry(st, history, i);
err = backtrack_insn(env, i, subseq_idx, hist, bt);
}
if (err == -ENOTSUPP) {
@@ -909,6 +922,21 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
*/
return 0;
subseq_idx = i;
+ if (hist && hist->unwind_frames) {
+ /*
+ * This insn is a landing pad the unwind reached
+ * from a throw or a resume with
+ * hist->unwind_frames frames deeper. The walker
+ * writes r0 on the way in, so no insn defines
+ * it: left set, the request reaches the call
+ * that created this frame, where only r1-r5 may
+ * still be.
+ */
+ bt_clear_reg(bt, BPF_REG_0);
+ if (bt_empty(bt))
+ return 0;
+ pending_unwind = hist->unwind_frames;
+ }
i = get_prev_insn_idx(st, i, &history);
if (i == -ENOENT)
break;
@@ -927,6 +955,11 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
if (!st)
break;
+ if (verifier_bug_if(bt->frame > st->curframe, env,
+ "backtrack frame %d, state curframe %d",
+ bt->frame, st->curframe))
+ return -EFAULT;
+
for (fr = bt->frame; fr >= 0; fr--) {
func = st->frame[fr];
bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr));
diff --git a/kernel/bpf/exception.c b/kernel/bpf/exception.c
index 244ea1b5417c..3270e7ae2e7c 100644
--- a/kernel/bpf/exception.c
+++ b/kernel/bpf/exception.c
@@ -5,6 +5,7 @@
#include <linux/btf.h>
#include <linux/btf_ids.h>
#include <linux/filter.h>
+#include <linux/slab.h>
#include "exception.h"
#define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 249418e60ee4..5eadab4dfa3f 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -5094,6 +5094,7 @@ BTF_ID_FLAGS(func, bpf_task_get_cgroup1, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_task_from_vpid, KF_ACQUIRE | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_throw)
+BTF_ID_FLAGS(func, bpf_unwind_resume)
#ifdef CONFIG_BPF_EVENTS
BTF_ID_FLAGS(func, bpf_send_signal_task)
#endif
diff --git a/kernel/bpf/liveness.c b/kernel/bpf/liveness.c
index 9d44a7dafe5f..00ac8917a716 100644
--- a/kernel/bpf/liveness.c
+++ b/kernel/bpf/liveness.c
@@ -258,6 +258,9 @@ bpf_insn_successors(struct bpf_verifier_env *env, u32 idx)
succ = env->succ;
succ->cnt = 0;
+ if (unlikely(bpf_is_unwind_resume_kfunc(insn)))
+ return succ;
+
opcode_info = &opcode_info_tbl[BPF_CLASS(insn->code) | BPF_OP(insn->code)];
insn_sz = bpf_is_ldimm64(insn) ? 2 : 1;
if (opcode_info->can_fallthrough)
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 66fb11b6c6a7..b101baa43171 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -996,6 +996,12 @@ static bool states_equal(struct bpf_verifier_env *env,
if (old->in_sleepable != cur->in_sleepable)
return false;
+ if (old->unwinding != cur->unwinding)
+ return false;
+
+ if (old->unwinding && old->unwind_frameno != cur->unwind_frameno)
+ return false;
+
if (!refsafe(old, cur, &env->idmap_scratch))
return false;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8163c75ec3fa..53edce3d64ea 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1726,6 +1726,8 @@ int bpf_copy_verifier_state(struct bpf_verifier_state *dst_state,
return err;
dst_state->speculative = src->speculative;
dst_state->in_sleepable = src->in_sleepable;
+ dst_state->unwinding = src->unwinding;
+ dst_state->unwind_frameno = src->unwind_frameno;
dst_state->curframe = src->curframe;
dst_state->branches = src->branches;
dst_state->parent = src->parent;
@@ -10598,8 +10600,8 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
return 0;
}
-static int process_bpf_exit_full(struct bpf_verifier_env *env,
- bool *do_print_state, bool exception_exit);
+static int process_bpf_exit_full(struct bpf_verifier_env *env, bool *do_print_state);
+static int unwind_step(struct bpf_verifier_env *env, u32 callsite, int *insn_idx);
static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx)
@@ -10689,7 +10691,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
verbose(env, "failed to push state for global subprog exception path\n");
return PTR_ERR(branch);
}
- return process_bpf_exit_full(env, NULL, true);
+ return unwind_step(env, *insn_idx, insn_idx);
}
/* continue with next insn after call */
@@ -11078,6 +11080,20 @@ static bool retval_range_within(struct bpf_retval_range range, const struct bpf_
return range.minval <= reg_smin(reg) && reg_smax(reg) <= range.maxval;
}
+static u32 pop_frame(struct bpf_verifier_env *env)
+{
+ struct bpf_verifier_state *state = env->cur_state;
+ struct bpf_func_state *callee = state->frame[state->curframe];
+ struct bpf_func_state *caller = state->frame[state->curframe - 1];
+ u32 callsite = callee->callsite;
+
+ account_processed_insns(env, callee, caller);
+ free_func_state(callee);
+ state->frame[state->curframe--] = NULL;
+ invalidate_outgoing_stack_args(env, caller);
+ return callsite;
+}
+
static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
{
struct bpf_verifier_state *state = env->cur_state, *prev_st;
@@ -11157,12 +11173,7 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
verbose(env, "to caller at %d:\n", *insn_idx);
print_verifier_state(env, state, caller->frameno, true);
}
- account_processed_insns(env, callee, caller);
- /* clear everything in the callee. In case of exceptional exits using
- * bpf_throw, this will be done by copy_verifier_state for extra frames. */
- free_func_state(callee);
- state->frame[state->curframe--] = NULL;
- invalidate_outgoing_stack_args(env, caller);
+ pop_frame(env);
/* for callbacks widen imprecise scalars to make programs like below verify:
*
@@ -14661,7 +14672,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
env->prog->call_session_cookie = true;
if (bpf_is_throw_kfunc(insn))
- return process_bpf_exit_full(env, NULL, true);
+ return unwind_step(env, insn_idx, &env->insn_idx);
return 0;
}
@@ -18586,9 +18597,80 @@ enum {
INSN_IDX_UPDATED = 2,
};
-static int process_bpf_exit_full(struct bpf_verifier_env *env,
- bool *do_print_state,
- bool exception_exit)
+static void unwind_enter_pad(struct bpf_verifier_env *env)
+{
+ struct bpf_verifier_state *state = env->cur_state;
+ struct bpf_func_state *frame = cur_func(env);
+
+ state->unwind_frameno = state->curframe;
+ clear_caller_saved_regs(env, frame->regs);
+ mark_reg_unknown(env, frame->regs, BPF_REG_0);
+}
+
+static int unwind_finish(struct bpf_verifier_env *env)
+{
+ int err = check_resource_leak(env, true, true, "bpf_throw");
+
+ if (err)
+ return err;
+ return PROCESS_BPF_EXIT;
+}
+
+static int unwind_step(struct bpf_verifier_env *env, u32 callsite, int *insn_idx)
+{
+ struct bpf_verifier_state *state = env->cur_state;
+ u8 popped = 0;
+
+ state->unwinding = true;
+ for (;;) {
+ int pad = bpf_exc_pad_of_call(env, callsite);
+
+ if (pad >= 0) {
+ unwind_enter_pad(env);
+ /*
+ * The edge from @callsite to the pad crosses @popped
+ * frames, and nothing in the instruction stream says
+ * so. Record it for mark_chain_precision(), which has
+ * to walk back through the same frames.
+ */
+ env->unwind_frames = popped;
+ *insn_idx = pad;
+ return INSN_IDX_UPDATED;
+ }
+ if (!state->curframe)
+ return unwind_finish(env);
+ callsite = pop_frame(env);
+ popped++;
+ }
+}
+
+static int process_cleanup_resume(struct bpf_verifier_env *env, int *insn_idx)
+{
+ struct bpf_verifier_state *state = env->cur_state;
+ int err;
+
+ if (!state->unwinding) {
+ verbose(env,
+ "bpf_unwind_resume() at insn %u reached without an exception in flight\n",
+ (u32)*insn_idx);
+ return -EINVAL;
+ }
+ if (state->curframe != state->unwind_frameno) {
+ verbose(env,
+ "bpf_unwind_resume() at insn %u is in frame %u, not frame %u whose landing pad the exception entered\n",
+ (u32)*insn_idx, state->curframe, state->unwind_frameno);
+ return -EINVAL;
+ }
+ if (!state->curframe)
+ return unwind_finish(env);
+ err = unwind_step(env, pop_frame(env), insn_idx);
+ /* unwind_step() counted the frames it popped, not the one popped here. */
+ if (err == INSN_IDX_UPDATED)
+ env->unwind_frames++;
+ return err;
+}
+
+static int process_bpf_exit_full(struct bpf_verifier_env *env, bool *do_print_state)
{
struct bpf_func_state *cur_frame = cur_func(env);
@@ -18598,25 +18680,11 @@ static int process_bpf_exit_full(struct bpf_verifier_env *env,
* for which reference_state must match caller reference
* state when it exits.
*/
- int err = check_resource_leak(env, exception_exit,
- exception_exit || !env->cur_state->curframe,
- exception_exit ? "bpf_throw" :
+ int err = check_resource_leak(env, false, !env->cur_state->curframe,
"BPF_EXIT instruction in main prog");
if (err)
return err;
- /* The side effect of the prepare_func_exit which is
- * being skipped is that it frees bpf_func_state.
- * Typically, process_bpf_exit will only be hit with
- * outermost exit. copy_verifier_state in pop_stack will
- * handle freeing of any extra bpf_func_state left over
- * from not processing all nested function exits. We
- * also skip return code checks as they are not needed
- * for exceptional exits.
- */
- if (exception_exit)
- return PROCESS_BPF_EXIT;
-
if (env->cur_state->curframe) {
/* exit from nested function */
err = prepare_func_exit(env, &env->insn_idx);
@@ -18790,6 +18858,8 @@ static int do_check_insn(struct bpf_verifier_env *env, bool *do_print_state)
env->jmps_processed++;
if (opcode == BPF_CALL) {
+ if (bpf_is_unwind_resume_kfunc(insn))
+ return process_cleanup_resume(env, &env->insn_idx);
if (env->cur_state->active_locks) {
if ((insn->src_reg == BPF_REG_0 &&
insn->imm != BPF_FUNC_spin_unlock &&
@@ -18823,7 +18893,7 @@ static int do_check_insn(struct bpf_verifier_env *env, bool *do_print_state)
env->insn_idx += insn->imm + 1;
return INSN_IDX_UPDATED;
} else if (opcode == BPF_EXIT) {
- return process_bpf_exit_full(env, do_print_state, false);
+ return process_bpf_exit_full(env, do_print_state);
}
return check_cond_jmp_op(env, insn, &env->insn_idx);
}
@@ -18864,6 +18934,9 @@ static int do_check(struct bpf_verifier_env *env)
/* reset current history entry on each new instruction */
env->cur_hist_ent = NULL;
+ /* frames the unwind popped to reach this insn, if it is a pad */
+ env->cur_unwind_frames = env->unwind_frames;
+ env->unwind_frames = 0;
env->prev_insn_idx = prev_insn_idx;
if (env->insn_idx >= insn_cnt) {
@@ -18927,7 +19000,7 @@ static int do_check(struct bpf_verifier_env *env)
}
}
- if (bpf_is_jmp_point(env, env->insn_idx)) {
+ if (bpf_is_jmp_point(env, env->insn_idx) || env->cur_unwind_frames) {
err = bpf_push_jmp_history(env, state, 0, 0, 0, 0);
if (err)
return err;
--
2.53.0-Meta
next prev parent reply other threads:[~2026-09-23 4:59 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 4:58 [PATCH bpf-next v5 00/21] bpf: Run exception cleanup landing pads when bpf_throw() unwinds Yonghong Song
2026-09-23 4:58 ` [PATCH bpf-next v5 01/21] bpf: Pack bpf_insn_aux_data flags into bit fields Yonghong Song
2026-09-23 5:40 ` bot+bpf-ci
2026-09-23 19:16 ` Eduard Zingerman
2026-09-23 4:58 ` [PATCH bpf-next v5 02/21] bpf: Accept the compiler's exception cleanup table at program load Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 03/21] bpf: Add the bpf_unwind_resume() kfunc Yonghong Song
2026-09-23 6:13 ` Kumar Kartikeya Dwivedi
2026-09-23 4:59 ` [PATCH bpf-next v5 04/21] bpf: Add lookups for exception cleanup resumes and landing pads Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 05/21] bpf: Prepare for an exception cleanup table before the CFG walk Yonghong Song
2026-09-23 5:40 ` bot+bpf-ci
2026-09-23 4:59 ` [PATCH bpf-next v5 06/21] bpf: Make exception landing pads reachable in the CFG Yonghong Song
2026-09-23 5:51 ` bot+bpf-ci
2026-09-23 19:25 ` Eduard Zingerman
2026-09-23 4:59 ` [PATCH bpf-next v5 07/21] bpf: Explore the landing pads no call site reaches Yonghong Song
2026-09-23 16:26 ` Eduard Zingerman
2026-09-23 17:27 ` Yonghong Song
2026-09-23 18:06 ` Eduard Zingerman
2026-09-23 18:09 ` Yonghong Song
2026-09-23 21:28 ` Alexei Starovoitov
2026-09-23 22:19 ` Eduard Zingerman
2026-09-23 23:20 ` Alexei Starovoitov
2026-09-24 0:13 ` Kumar Kartikeya Dwivedi
2026-09-24 1:53 ` Alexei Starovoitov
2026-09-24 6:12 ` Kumar Kartikeya Dwivedi
2026-09-23 23:09 ` Yonghong Song
2026-09-23 4:59 ` Yonghong Song [this message]
2026-09-23 16:34 ` [PATCH bpf-next v5 08/21] bpf: Walk the exception unwind in the verifier Eduard Zingerman
2026-09-23 18:01 ` Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 09/21] bpf: Refuse exception cleanup shapes bpf_throw() cannot dispatch Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 10/21] bpf: Refuse a private stack for a program with an exception cleanup table Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 11/21] bpf: Dispatch exception cleanup pads from bpf_throw() Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 12/21] bpf, x86: Dispatch exception cleanup pads at run time Yonghong Song
2026-09-23 6:45 ` Eduard Zingerman
2026-09-23 20:45 ` Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 13/21] bpf, arm64: " Yonghong Song
2026-09-23 4:59 ` [PATCH bpf-next v5 14/21] libbpf: Resolve the compiler's _Unwind_Resume to the kernel's kfunc Yonghong Song
2026-09-23 8:36 ` Kumar Kartikeya Dwivedi
2026-09-23 5:00 ` [PATCH bpf-next v5 15/21] libbpf: Add cleanup_info to bpf_prog_load_opts Yonghong Song
2026-09-23 5:00 ` [PATCH bpf-next v5 16/21] libbpf: Collect .bpf_cleanup records and pass them to the kernel Yonghong Song
2026-09-23 5:52 ` Kumar Kartikeya Dwivedi
2026-09-23 5:00 ` [PATCH bpf-next v5 17/21] libbpf: Carry the exception cleanup table through the light skeleton Yonghong Song
2026-09-23 5:00 ` [PATCH bpf-next v5 18/21] libbpf: Let the static linker carry .bpf_cleanup relocations Yonghong Song
2026-09-23 5:40 ` bot+bpf-ci
2026-09-23 5:00 ` [PATCH bpf-next v5 19/21] selftests/bpf: Add an end-to-end .bpf_cleanup exception test Yonghong Song
2026-09-23 5:51 ` bot+bpf-ci
2026-09-23 5:00 ` [PATCH bpf-next v5 20/21] selftests/bpf: Cover the exception cleanup shapes the chain does not reach Yonghong Song
2026-09-23 5:51 ` bot+bpf-ci
2026-09-23 7:50 ` Eduard Zingerman
2026-09-23 5:00 ` [PATCH bpf-next v5 21/21] selftests/bpf: Load an exception cleanup program from a light skeleton Yonghong Song
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=20260923045927.2418543-1-yonghong.song@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=kernel-team@fb.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox