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 <[email protected]>
> ---
> 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