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