]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Unclone skb head on bpf_dynptr_write to skb metadata
authorJakub Sitnicki <jakub@cloudflare.com>
Wed, 5 Nov 2025 20:19:40 +0000 (21:19 +0100)
committerMartin KaFai Lau <martin.lau@kernel.org>
Mon, 10 Nov 2025 18:52:31 +0000 (10:52 -0800)
Currently bpf_dynptr_from_skb_meta() marks the dynptr as read-only when
the skb is cloned, preventing writes to metadata.

Remove this restriction and unclone the skb head on bpf_dynptr_write() to
metadata, now that the metadata is preserved during uncloning. This makes
metadata dynptr consistent with skb dynptr, allowing writes regardless of
whether the skb is cloned.

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20251105-skb-meta-rx-path-v4-3-5ceb08a9b37b@cloudflare.com
include/linux/filter.h
kernel/bpf/helpers.c
net/core/filter.c

index e116de7edc58715171762b6aa6d7ca32344c5768..a104b39942305af245b9f2938a0acf7d7ab33c23 100644 (file)
@@ -1781,6 +1781,8 @@ int __bpf_xdp_store_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len);
 void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len);
 void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off,
                      void *buf, unsigned long len, bool flush);
+int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,
+                              const void *from, u32 len, u64 flags);
 void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset);
 #else /* CONFIG_NET */
 static inline int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset,
@@ -1817,6 +1819,13 @@ static inline void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, voi
 {
 }
 
+static inline int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,
+                                            const void *from, u32 len,
+                                            u64 flags)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset)
 {
        return ERR_PTR(-EOPNOTSUPP);
index eb25e70e0bdc0332edd21cde66d9aaadb2090312..3e830fd31f5ffea48c92fbd220b3edcd5f4649da 100644 (file)
@@ -1842,10 +1842,8 @@ int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u32 offset, void *src,
                        return -EINVAL;
                return __bpf_xdp_store_bytes(dst->data, dst->offset + offset, src, len);
        case BPF_DYNPTR_TYPE_SKB_META:
-               if (flags)
-                       return -EINVAL;
-               memmove(bpf_skb_meta_pointer(dst->data, dst->offset + offset), src, len);
-               return 0;
+               return __bpf_skb_meta_store_bytes(dst->data, dst->offset + offset, src,
+                                                 len, flags);
        default:
                WARN_ONCE(true, "bpf_dynptr_write: unknown dynptr type %d\n", type);
                return -EFAULT;
index 52721efba332f03f408c770be8e2b609d2694aa9..673299fd3d5896cdd81dbf32c7b27a4c9f03b0e3 100644 (file)
@@ -12102,6 +12102,18 @@ void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset)
        return skb_metadata_end(skb) - skb_metadata_len(skb) + offset;
 }
 
+int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,
+                              const void *from, u32 len, u64 flags)
+{
+       if (unlikely(flags))
+               return -EINVAL;
+       if (unlikely(bpf_try_make_writable(skb, 0)))
+               return -EFAULT;
+
+       memmove(bpf_skb_meta_pointer(skb, offset), from, len);
+       return 0;
+}
+
 __bpf_kfunc_start_defs();
 __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags,
                                    struct bpf_dynptr *ptr__uninit)
@@ -12129,9 +12141,6 @@ __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags,
  * XDP context with bpf_xdp_adjust_meta(). Serves as an alternative to
  * &__sk_buff->data_meta.
  *
- * If passed @skb_ is a clone which shares the data with the original, the
- * dynptr will be read-only. This limitation may be lifted in the future.
- *
  * Return:
  * * %0         - dynptr ready to use
  * * %-EINVAL   - invalid flags, dynptr set to null
@@ -12149,9 +12158,6 @@ __bpf_kfunc int bpf_dynptr_from_skb_meta(struct __sk_buff *skb_, u64 flags,
 
        bpf_dynptr_init(ptr, skb, BPF_DYNPTR_TYPE_SKB_META, 0, skb_metadata_len(skb));
 
-       if (skb_cloned(skb))
-               bpf_dynptr_set_rdonly(ptr);
-
        return 0;
 }