Re: [PATCH bpf-next v4 2/8] bpf: Enable read/write access to skb metadata through a dynptr
From: Jakub Sitnicki <jakub@cloudflare.com>
Date: 2025-07-24 09:44:04
Also in:
bpf
On Wed, Jul 23, 2025 at 05:02 PM -07, Martin KaFai Lau wrote:
On 7/23/25 10:36 AM, Jakub Sitnicki wrote:quoted
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 9552b32208c5..237fb5f9d625 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c@@ -1781,7 +1781,7 @@ static int __bpf_dynptr_read(void *dst, u32 len, const struct bpf_dynptr_kern *s case BPF_DYNPTR_TYPE_XDP: return __bpf_xdp_load_bytes(src->data, src->offset + offset, dst, len); case BPF_DYNPTR_TYPE_SKB_META: - return -EOPNOTSUPP; /* not implemented */ + return bpf_skb_meta_load_bytes(src->data, src->offset + offset, dst, len); default: WARN_ONCE(true, "bpf_dynptr_read: unknown dynptr type %d\n", type); return -EFAULT;@@ -1839,7 +1839,7 @@ 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: - return -EOPNOTSUPP; /* not implemented */It needs to check the flags here such that the flags can be used in the future: if (flags) return -EINVAL;
Missed that. Thanks.
pw-bot: crquoted
+ return bpf_skb_meta_store_bytes(dst->data, dst->offset + offset, src, len); default: WARN_ONCE(true, "bpf_dynptr_write: unknown dynptr type %d\n", type); return -EFAULT;@@ -2716,7 +2716,7 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr *p, u32 offset, return buffer__opt; } case BPF_DYNPTR_TYPE_SKB_META: - return NULL; /* not implemented */ + return bpf_skb_meta_pointer(ptr->data, ptr->offset + offset, len); default: WARN_ONCE(true, "unknown dynptr type %d\n", type); return NULL;diff --git a/net/core/filter.c b/net/core/filter.c index 0755dfc0fc2f..cf095897d4c1 100644 --- a/net/core/filter.c +++ b/net/core/filter.c@@ -11978,6 +11978,45 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return func; } +static void *skb_metadata_pointer(const struct sk_buff *skb, u32 off, u32len) +{ + u32 meta_len = skb_metadata_len(skb); + + if (len > meta_len || off > meta_len - len)A nit. After reading it again, I think this is a duplicated check. The bpf_dynptr_check_off_len() called in the kfunc should have already checked the same condition.
I took a better-safe-than-sorry approach. Can skb_metadata_len() change after the call to bpf_dynptr_from_skb_meta()? Today it can't, but what if we let TC BPF resize the metadata area in the future? But you're right. It's duplicated code for now and can be dropped.
quoted
+ return ERR_PTR(-E2BIG); /* out of bounds */ + + return skb_metadata_end(skb) - meta_len + off; +} + +int bpf_skb_meta_load_bytes(const struct sk_buff *src, u32 off, void *dst, u32 len)Since it needs a respin, I have a few nit comments that will be useful for reading filter.c. Change the "const struct sk_buff *src" to "const struct sk_buff *skb". It is how other places are naming the arg in filter.c.
No problem. I will unify it with: int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len); int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags);
quoted
+{ + const void *p = skb_metadata_pointer(src, off, len);Not sure if this variable is still needed if skb_metadata_pointer does not return err ptr. If it is still needed, use "const void *ptr" instead of "const void *p". The bpf_xdp_pointer and skb_header_pointer callers in filter.c also use that naming.
Will do.
quoted
+ + if (IS_ERR(p)) + return PTR_ERR(p); + + memmove(dst, p, len); + return 0; +} + +int bpf_skb_meta_store_bytes(struct sk_buff *dst, u32 off, const void *src, u32 len) +{ + void *p = skb_metadata_pointer(dst, off, len);Same for the "struct sk_buff *dst" and "void *p" in this function.
Will change.
quoted
+ + if (IS_ERR(p)) + return PTR_ERR(p); + + memmove(p, src, len); + return 0; +}
Thanks for reviewing.