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;
+}
+
+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


Reply via email to