* [PATCH bpf 1/2] bpf: Fix packet pointer invalidation for skb dynptr writes
@ 2026-06-15 12:07 Yiyang Chen
2026-06-15 15:51 ` Alexei Starovoitov
0 siblings, 1 reply; 2+ messages in thread
From: Yiyang Chen @ 2026-06-15 12:07 UTC (permalink / raw)
To: bpf
Cc: Yiyang Chen, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, John Fastabend, Shuah Khan, linux-kselftest,
linux-kernel
skb-backed dynptr writer kfuncs can mutate skb packet storage.
The verifier currently treats kfunc calls as packet-changing only for
bpf_xdp_pull_data().
That leaves direct packet pointers usable after skb dynptr writer kfuncs.
The helper path already clears packet pointers for bpf_dynptr_write().
Mark kfunc calls packet-changing when argument 0 is a writable skb or
skb-meta dynptr destination. This covers bpf_dynptr_copy(),
bpf_dynptr_memset(), and probe/copy-from-user dynptr writers.
Source-only dynptr arguments are left unchanged.
Fixes: daec295a70941 ("bpf/helpers: Introduce bpf_dynptr_copy kfunc")
Fixes: a498ee7576de ("bpf: Implement dynptr copy kfuncs")
Fixes: 5fc5d8fded57 ("bpf: Add bpf_dynptr_memset() kfunc")
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
---
include/linux/bpf_verifier.h | 1 +
kernel/bpf/verifier.c | 62 +++++++++++++++++++++++++++++++++++-
2 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 39a851e690ec4..c7d0c20a4961b 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1448,6 +1448,7 @@ struct bpf_kfunc_call_arg_meta {
/* Out parameters */
u8 release_regno;
bool r0_rdonly;
+ bool pkt_dynptr_write;
u32 ret_btf_id;
u64 r0_size;
u32 subprogno;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf281c..5ea51bd284f84 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11016,6 +11016,16 @@ enum special_kfunc_type {
KF_bpf_xdp_pull_data,
KF_bpf_dynptr_slice,
KF_bpf_dynptr_slice_rdwr,
+ KF_bpf_dynptr_copy,
+ KF_bpf_dynptr_memset,
+ KF_bpf_probe_read_user_dynptr,
+ KF_bpf_probe_read_kernel_dynptr,
+ KF_bpf_probe_read_user_str_dynptr,
+ KF_bpf_probe_read_kernel_str_dynptr,
+ KF_bpf_copy_from_user_dynptr,
+ KF_bpf_copy_from_user_str_dynptr,
+ KF_bpf_copy_from_user_task_dynptr,
+ KF_bpf_copy_from_user_task_str_dynptr,
KF_bpf_dynptr_clone,
KF_bpf_percpu_obj_new_impl,
KF_bpf_percpu_obj_new,
@@ -11096,6 +11106,27 @@ BTF_ID_UNUSED
#endif
BTF_ID(func, bpf_dynptr_slice)
BTF_ID(func, bpf_dynptr_slice_rdwr)
+BTF_ID(func, bpf_dynptr_copy)
+BTF_ID(func, bpf_dynptr_memset)
+#ifdef CONFIG_BPF_EVENTS
+BTF_ID(func, bpf_probe_read_user_dynptr)
+BTF_ID(func, bpf_probe_read_kernel_dynptr)
+BTF_ID(func, bpf_probe_read_user_str_dynptr)
+BTF_ID(func, bpf_probe_read_kernel_str_dynptr)
+BTF_ID(func, bpf_copy_from_user_dynptr)
+BTF_ID(func, bpf_copy_from_user_str_dynptr)
+BTF_ID(func, bpf_copy_from_user_task_dynptr)
+BTF_ID(func, bpf_copy_from_user_task_str_dynptr)
+#else
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+BTF_ID_UNUSED
+#endif
BTF_ID(func, bpf_dynptr_clone)
BTF_ID(func, bpf_percpu_obj_new_impl)
BTF_ID(func, bpf_percpu_obj_new)
@@ -11229,7 +11260,33 @@ static bool is_kfunc_bpf_preempt_enable(struct bpf_kfunc_call_arg_meta *meta)
bool bpf_is_kfunc_pkt_changing(struct bpf_kfunc_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data];
+ return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data] ||
+ meta->pkt_dynptr_write;
+}
+
+static bool dynptr_type_pkt_data(enum bpf_dynptr_type type)
+{
+ return type == BPF_DYNPTR_TYPE_SKB ||
+ type == BPF_DYNPTR_TYPE_SKB_META;
+}
+
+static bool is_kfunc_pkt_dynptr_writer(struct bpf_kfunc_call_arg_meta *meta, u32 arg)
+{
+ u32 func_id = meta->func_id;
+
+ if (arg != 0)
+ return false;
+
+ return func_id == special_kfunc_list[KF_bpf_dynptr_copy] ||
+ func_id == special_kfunc_list[KF_bpf_dynptr_memset] ||
+ func_id == special_kfunc_list[KF_bpf_probe_read_user_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_probe_read_kernel_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_probe_read_user_str_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_probe_read_kernel_str_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_copy_from_user_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_copy_from_user_str_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_copy_from_user_task_dynptr] ||
+ func_id == special_kfunc_list[KF_bpf_copy_from_user_task_str_dynptr];
}
static enum kfunc_ptr_arg_type
@@ -12214,6 +12271,9 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
&meta->ref_obj, &meta->dynptr);
if (ret < 0)
return ret;
+ if (is_kfunc_pkt_dynptr_writer(meta, i) &&
+ dynptr_type_pkt_data(meta->dynptr.type))
+ meta->pkt_dynptr_write = true;
break;
}
case KF_ARG_PTR_TO_ITER:
--
2.34.1
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH bpf 1/2] bpf: Fix packet pointer invalidation for skb dynptr writes
2026-06-15 12:07 [PATCH bpf 1/2] bpf: Fix packet pointer invalidation for skb dynptr writes Yiyang Chen
@ 2026-06-15 15:51 ` Alexei Starovoitov
0 siblings, 0 replies; 2+ messages in thread
From: Alexei Starovoitov @ 2026-06-15 15:51 UTC (permalink / raw)
To: Yiyang Chen, bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
John Fastabend, Shuah Khan, linux-kselftest, linux-kernel
On Mon Jun 15, 2026 at 5:07 AM PDT, Yiyang Chen wrote:
> skb-backed dynptr writer kfuncs can mutate skb packet storage.
> The verifier currently treats kfunc calls as packet-changing only for
> bpf_xdp_pull_data().
>
> That leaves direct packet pointers usable after skb dynptr writer kfuncs.
> The helper path already clears packet pointers for bpf_dynptr_write().
>
> Mark kfunc calls packet-changing when argument 0 is a writable skb or
> skb-meta dynptr destination. This covers bpf_dynptr_copy(),
> bpf_dynptr_memset(), and probe/copy-from-user dynptr writers.
> Source-only dynptr arguments are left unchanged.
>
> Fixes: daec295a70941 ("bpf/helpers: Introduce bpf_dynptr_copy kfunc")
> Fixes: a498ee7576de ("bpf: Implement dynptr copy kfuncs")
> Fixes: 5fc5d8fded57 ("bpf: Add bpf_dynptr_memset() kfunc")
> Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
> ---
> include/linux/bpf_verifier.h | 1 +
> kernel/bpf/verifier.c | 62 +++++++++++++++++++++++++++++++++++-
> 2 files changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 39a851e690ec4..c7d0c20a4961b 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -1448,6 +1448,7 @@ struct bpf_kfunc_call_arg_meta {
> /* Out parameters */
> u8 release_regno;
> bool r0_rdonly;
> + bool pkt_dynptr_write;
> u32 ret_btf_id;
> u64 r0_size;
> u32 subprogno;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 2abc79dbf281c..5ea51bd284f84 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11016,6 +11016,16 @@ enum special_kfunc_type {
> KF_bpf_xdp_pull_data,
> KF_bpf_dynptr_slice,
> KF_bpf_dynptr_slice_rdwr,
> + KF_bpf_dynptr_copy,
> + KF_bpf_dynptr_memset,
> + KF_bpf_probe_read_user_dynptr,
> + KF_bpf_probe_read_kernel_dynptr,
> + KF_bpf_probe_read_user_str_dynptr,
> + KF_bpf_probe_read_kernel_str_dynptr,
> + KF_bpf_copy_from_user_dynptr,
> + KF_bpf_copy_from_user_str_dynptr,
> + KF_bpf_copy_from_user_task_dynptr,
> + KF_bpf_copy_from_user_task_str_dynptr,
> KF_bpf_dynptr_clone,
> KF_bpf_percpu_obj_new_impl,
> KF_bpf_percpu_obj_new,
> @@ -11096,6 +11106,27 @@ BTF_ID_UNUSED
> #endif
> BTF_ID(func, bpf_dynptr_slice)
> BTF_ID(func, bpf_dynptr_slice_rdwr)
> +BTF_ID(func, bpf_dynptr_copy)
> +BTF_ID(func, bpf_dynptr_memset)
> +#ifdef CONFIG_BPF_EVENTS
> +BTF_ID(func, bpf_probe_read_user_dynptr)
> +BTF_ID(func, bpf_probe_read_kernel_dynptr)
> +BTF_ID(func, bpf_probe_read_user_str_dynptr)
> +BTF_ID(func, bpf_probe_read_kernel_str_dynptr)
> +BTF_ID(func, bpf_copy_from_user_dynptr)
> +BTF_ID(func, bpf_copy_from_user_str_dynptr)
> +BTF_ID(func, bpf_copy_from_user_task_dynptr)
> +BTF_ID(func, bpf_copy_from_user_task_str_dynptr)
> +#else
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +BTF_ID_UNUSED
> +#endif
> BTF_ID(func, bpf_dynptr_clone)
> BTF_ID(func, bpf_percpu_obj_new_impl)
> BTF_ID(func, bpf_percpu_obj_new)
> @@ -11229,7 +11260,33 @@ static bool is_kfunc_bpf_preempt_enable(struct bpf_kfunc_call_arg_meta *meta)
>
> bool bpf_is_kfunc_pkt_changing(struct bpf_kfunc_call_arg_meta *meta)
> {
> - return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data];
> + return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data] ||
> + meta->pkt_dynptr_write;
> +}
Nack. You misunderstand what bpf_is_kfunc_pkt_changing() is doing.
pw-bot: cr
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-15 15:51 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-15 12:07 [PATCH bpf 1/2] bpf: Fix packet pointer invalidation for skb dynptr writes Yiyang Chen
2026-06-15 15:51 ` Alexei Starovoitov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®