From: Amery Hung <ameryhung@gmail.com>
To: bpf@vger.kernel.org
Cc: alexei.starovoitov@gmail.com, andrii@kernel.org,
daniel@iogearbox.net, eddyz87@gmail.com, memxor@gmail.com,
ameryhung@gmail.com, kernel-team@meta.com
Subject: [PATCH bpf-next v1 10/12] bpf: Track packet changes in call metadata
Date: Fri, 25 Sep 2026 14:12:54 -0700 [thread overview]
Message-ID: <20260925211256.1834061-11-ameryhung@gmail.com> (raw)
In-Reply-To: <20260925211256.1834061-1-ameryhung@gmail.com>
Helper, kfunc, and global subprog calls each determine whether a call
can invalidate packet pointers, but carry the result through
call-specific variables or look it up again where packet state is
cleared.
Record the effect in bpf_call_arg_meta. Initialize it from the helper
or kfunc identity and from the subprog propagated changes_pkt_data
flag. Keep the dynptr helper backing-type refinement and tail-call
handling on the common field, then have all three call paths clear
packet pointers from it.
No functional change is intended.
Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
include/linux/bpf_verifier.h | 1 +
kernel/bpf/verifier.c | 54 +++++++++++++++++++-----------------
2 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 144da990ee8c..590ac30a5691 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1640,6 +1640,7 @@ struct bpf_call_arg_meta {
u32 func_id;
const struct bpf_func_proto *fn;
const struct btf_type *func_proto;
+ bool pkt_changed;
u8 release_regno;
u32 ret_btf_id;
u32 subprogno;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 73a1c4877427..212cada61aa6 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -10827,22 +10827,22 @@ static void gen_subprog_arg_proto(const struct bpf_subprog_info *sub, const stru
}
static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
- struct btf *btf,
- struct bpf_reg_state *regs)
+ struct btf *btf, struct bpf_reg_state *regs,
+ struct bpf_call_arg_meta *meta)
{
struct bpf_subprog_info *sub = subprog_info(env, subprog);
struct bpf_func_state *caller = cur_func(env);
struct bpf_verifier_log *log = &env->log;
const struct btf_param *args, *stack_args;
const struct btf_type *func, *func_proto;
- struct bpf_call_arg_meta meta;
struct bpf_func_proto *fn;
u32 arg, slot, nslots;
int ret, err;
- memset(&meta, 0, sizeof(meta));
- meta.btf = btf;
- meta.func_name = bpf_subprog_name(env, subprog);
+ memset(meta, 0, sizeof(*meta));
+ meta->btf = btf;
+ meta->pkt_changed = sub->changes_pkt_data;
+ meta->func_name = bpf_subprog_name(env, subprog);
ret = btf_prepare_func_args(env, subprog);
if (ret) {
@@ -10867,8 +10867,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
fn = &env->bpf_subprog_scratch;
gen_subprog_arg_proto(sub, btf, func_proto, fn);
- meta.fn = fn;
- meta.func_proto = func_proto;
+ meta->fn = fn;
+ meta->func_proto = func_proto;
/* check that BTF function arguments match actual types that the
* verifier sees.
@@ -10887,7 +10887,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
arg_type == ARG_PTR_TO_CTX || arg_type == ARG_PTR_TO_DYNPTR ||
base_type(arg_type) == ARG_PTR_TO_ARENA ||
base_type(arg_type) == ARG_PTR_TO_BTF_ID) {
- ret = check_func_arg(env, arg, slot, 0, &meta, env->insn_idx);
+ ret = check_func_arg(env, arg, slot, 0, meta, env->insn_idx);
if (ret)
return ret;
} else if (base_type(arg_type) == ARG_PTR_TO_MEM) {
@@ -10921,7 +10921,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
}
for (k = 1; k < nslots; k++) {
- ret = check_arg_extra_slot(env, caller, slot + k, &meta);
+ ret = check_arg_extra_slot(env, caller, slot + k, meta);
if (ret)
return ret;
}
@@ -10938,7 +10938,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
*/
static int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
- struct bpf_reg_state *regs)
+ struct bpf_reg_state *regs,
+ struct bpf_call_arg_meta *meta)
{
struct bpf_prog *prog = env->prog;
struct btf *btf = prog->aux->btf;
@@ -10955,7 +10956,7 @@ static int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
if (prog->aux->func_info_aux[subprog].unreliable)
return -EINVAL;
- err = btf_check_func_arg_match(env, subprog, btf, regs);
+ err = btf_check_func_arg_match(env, subprog, btf, regs, meta);
/* Compiler optimizations can remove arguments from static functions
* or mismatched type can be passed into a global function.
* In such cases mark the function as unreliable from BTF point of view.
@@ -10970,11 +10971,12 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
set_callee_state_fn set_callee_state_cb)
{
struct bpf_verifier_state *state = env->cur_state, *callback_state;
+ struct bpf_call_arg_meta meta;
struct bpf_func_state *caller, *callee;
int err;
caller = state->frame[state->curframe];
- err = btf_check_subprog_call(env, subprog, caller->regs);
+ err = btf_check_subprog_call(env, subprog, caller->regs, &meta);
if (err == -EFAULT)
return err;
@@ -11100,6 +11102,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx)
{
struct bpf_verifier_state *state = env->cur_state;
+ struct bpf_call_arg_meta meta;
struct bpf_func_state *caller;
int err, subprog, target_insn;
u32 i, nregs;
@@ -11111,7 +11114,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
return -EFAULT;
caller = state->frame[state->curframe];
- err = btf_check_subprog_call(env, subprog, caller->regs);
+ err = btf_check_subprog_call(env, subprog, caller->regs, &meta);
if (err == -EFAULT)
return err;
if (bpf_subprog_is_global(env, subprog)) {
@@ -11154,7 +11157,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
subprog, sub_name);
sub_aux->called[in_sleepable_context(env)] = true;
returns_void = subprog_returns_void(env, subprog);
- if (env->subprog_info[subprog].changes_pkt_data)
+ if (meta.pkt_changed)
clear_all_pkt_pointers(env);
if (returns_void)
bpf_diag_record_scrub(env, &caller->regs[BPF_REG_0], BPF_DIAG_MOD_CALLER_SAVED);
@@ -11212,6 +11215,7 @@ static int check_func_callx(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx)
{
struct bpf_func_state *caller = cur_func(env);
+ struct bpf_call_arg_meta meta;
struct bpf_reg_state *reg;
const char *reason;
int err, subprog;
@@ -11247,7 +11251,7 @@ static int check_func_callx(struct bpf_verifier_env *env, struct bpf_insn *insn,
/* PTR_TO_FUNC is a pointer to a static subprog */
subprog = reg->subprogno;
- err = btf_check_subprog_call(env, subprog, caller->regs);
+ err = btf_check_subprog_call(env, subprog, caller->regs, &meta);
if (err == -EFAULT)
return err;
@@ -12111,7 +12115,6 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
struct bpf_call_arg_meta meta;
const char *operation;
int insn_idx = *insn_idx_p;
- bool changes_data;
int i, err, func_id;
/* find function prototype */
@@ -12153,15 +12156,15 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
return -EINVAL;
}
+ memset(&meta, 0, sizeof(meta));
+ meta.pkt_changed = bpf_helper_changes_pkt_data(func_id);
+
/* With LD_ABS/IND some JITs save/restore skb from r1. */
- changes_data = bpf_helper_changes_pkt_data(func_id);
- if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) {
+ if (meta.pkt_changed && fn->arg1_type != ARG_PTR_TO_CTX) {
verifier_bug(env, "func %s#%d: r1 != ctx", func_id_name(func_id), func_id);
return -EFAULT;
}
- memset(&meta, 0, sizeof(meta));
-
err = check_func_proto(env, fn, &meta);
if (err) {
verifier_bug(env, "incorrect func proto %s#%d", func_id_name(func_id), func_id);
@@ -12332,7 +12335,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
/* this will trigger clear_all_pkt_pointers(), which will
* invalidate all dynptr slices associated with the skb
*/
- changes_data = true;
+ meta.pkt_changed = true;
break;
}
@@ -12617,11 +12620,11 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
return err;
env->insn_idx--;
} else {
- changes_data = false;
+ meta.pkt_changed = false;
}
}
- if (changes_data)
+ if (meta.pkt_changed)
clear_all_pkt_pointers(env);
return 0;
}
@@ -14753,6 +14756,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
if (err)
return err;
+ meta.pkt_changed = bpf_is_kfunc_pkt_changing(&meta);
desc_btf = meta.btf;
func_name = meta.func_name;
insn_aux = &env->insn_aux_data[insn_idx];
@@ -15180,7 +15184,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
}
- if (bpf_is_kfunc_pkt_changing(&meta))
+ if (meta.pkt_changed)
clear_all_pkt_pointers(env);
proto_slots = kfunc_abi_slots(&desc->func_model);
--
2.52.0
next prev parent reply other threads:[~2026-09-25 21:13 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 21:12 [PATCH bpf-next v1 00/12] Unify subprog argument checks Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 01/12] bpf: Fix kfunc nullability diagnostics after wide arguments Amery Hung
2026-09-26 8:48 ` Alexei Starovoitov
2026-09-28 17:42 ` Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 02/12] bpf: Identify subprog calls in argument metadata Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 03/12] bpf: Build argument prototypes for subprog calls Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 04/12] bpf: Check subprog scalar arguments in the common path Amery Hung
2026-09-25 22:01 ` bot+bpf-ci
2026-09-25 21:12 ` [PATCH bpf-next v1 05/12] bpf: Check global subprog untrusted " Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 06/12] bpf: Check subprog context " Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 07/12] bpf: Check subprog arena " Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 08/12] bpf: Check subprog dynptr " Amery Hung
2026-09-25 21:26 ` sashiko-bot
2026-09-25 21:12 ` [PATCH bpf-next v1 09/12] bpf: Check global subprog BTF-ID " Amery Hung
2026-09-25 21:12 ` Amery Hung [this message]
2026-09-26 8:49 ` [PATCH bpf-next v1 10/12] bpf: Track packet changes in call metadata Alexei Starovoitov
2026-09-28 17:42 ` Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 11/12] bpf: Check global subprog memory arguments in the common path Amery Hung
2026-09-25 21:12 ` [PATCH bpf-next v1 12/12] bpf: Check all subprog " Amery Hung
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=20260925211256.1834061-11-ameryhung@gmail.com \
--to=ameryhung@gmail.com \
--cc=alexei.starovoitov@gmail.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=kernel-team@meta.com \
--cc=memxor@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.