Add verifier tests for direct packet pointers kept live across skb dynptr writer kfunc calls.
The writer cases must reject because stale packet pointers must not remain usable after the kfunc can mutate skb packet storage. Add a bpf_dynptr_copy() control where the skb dynptr is only the source. That case must continue to load because it does not write through the skb-backed dynptr. Signed-off-by: Yiyang Chen <[email protected]> --- .../testing/selftests/bpf/progs/dynptr_fail.c | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 344fb2aa0813d..bd51c9b93742a 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -1274,6 +1274,95 @@ int skb_invalid_data_slice4(struct __sk_buff *skb) return SK_PASS; } +char dynptr_kfunc_data[8] = "test"; +char dynptr_kfunc_dst[8]; + +extern int bpf_dynptr_copy(const struct bpf_dynptr *dst, __u64 dst_off, + const struct bpf_dynptr *src, __u64 src_off, + __u64 size) __ksym __weak; +extern int bpf_dynptr_memset(const struct bpf_dynptr *ptr, __u64 offset, + __u64 size, __u8 val) __ksym __weak; +extern int bpf_probe_read_kernel_dynptr(const struct bpf_dynptr *dptr, + __u64 off, __u64 size, + const void *unsafe_ptr__ign) __ksym __weak; + +/* Direct packet pointers are invalidated after a dynptr kfunc writes to an skb */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int skb_pkt_ptr_invalid_after_dynptr_memset(struct __sk_buff *skb) +{ + __u8 *data = (void *)(long)skb->data; + __u8 *data_end = (void *)(long)skb->data_end; + struct bpf_dynptr ptr; + + if (data + 1 > data_end) + return SK_DROP; + + bpf_dynptr_from_skb(skb, 0, &ptr); + bpf_dynptr_memset(&ptr, 0, 1, 0); + + /* this should fail */ + return *data; +} + +/* Direct packet pointers are invalidated after bpf_dynptr_copy() writes to an skb */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int skb_pkt_ptr_invalid_after_dynptr_copy_dst(struct __sk_buff *skb) +{ + __u8 *data = (void *)(long)skb->data; + __u8 *data_end = (void *)(long)skb->data_end; + struct bpf_dynptr dst, src; + + if (data + 1 > data_end) + return SK_DROP; + + bpf_dynptr_from_skb(skb, 0, &dst); + bpf_dynptr_from_mem(dynptr_kfunc_data, sizeof(dynptr_kfunc_data), 0, &src); + bpf_dynptr_copy(&dst, 0, &src, 0, 1); + + /* this should fail */ + return *data; +} + +/* Direct packet pointers stay valid when an skb dynptr is only copied from */ +SEC("?tc") +__success +int skb_pkt_ptr_valid_after_dynptr_copy_src(struct __sk_buff *skb) +{ + __u8 *data = (void *)(long)skb->data; + __u8 *data_end = (void *)(long)skb->data_end; + struct bpf_dynptr dst, src; + + if (data + 1 > data_end) + return SK_DROP; + + bpf_dynptr_from_skb(skb, 0, &src); + bpf_dynptr_from_mem(dynptr_kfunc_dst, sizeof(dynptr_kfunc_dst), 0, &dst); + bpf_dynptr_copy(&dst, 0, &src, 0, 1); + + return *data; +} + +/* Direct packet pointers are invalidated after probe-read writes to an skb dynptr */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int skb_pkt_ptr_invalid_after_probe_read_kernel_dynptr(struct __sk_buff *skb) +{ + __u8 *data = (void *)(long)skb->data; + __u8 *data_end = (void *)(long)skb->data_end; + struct bpf_dynptr ptr; + + if (data + 1 > data_end) + return SK_DROP; + + bpf_dynptr_from_skb(skb, 0, &ptr); + bpf_probe_read_kernel_dynptr(&ptr, 0, 1, dynptr_kfunc_data); + + /* this should fail */ + return *data; +} + /* Read-only skb data slice is invalidated on write to skb metadata */ SEC("?tc") __failure __msg("invalid mem access 'scalar'") -- 2.34.1

