Add a new flag for the bpf_dynptr_from_skb helper to let users to create dynptrs to skb metadata area. Access paths are stubbed out. Implemented by the following changes. Signed-off-by: Jakub Sitnicki --- include/uapi/linux/bpf.h | 9 ++++++++ net/core/filter.c | 60 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 719ba230032f..ab5730d2fb29 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -7591,4 +7591,13 @@ enum bpf_kfunc_flags { BPF_F_PAD_ZEROS = (1ULL << 0), }; +/** + * enum bpf_dynptr_from_skb_flags - Flags for bpf_dynptr_from_skb() + * + * @BPF_DYNPTR_F_SKB_METADATA: Create dynptr to the SKB metadata area + */ +enum bpf_dynptr_from_skb_flags { + BPF_DYNPTR_F_SKB_METADATA = (1ULL << 0), +}; + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/net/core/filter.c b/net/core/filter.c index 1fee51b72220..3c2948517838 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -11967,12 +11967,27 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return func; } +enum skb_dynptr_offset { + SKB_DYNPTR_METADATA = -1, + SKB_DYNPTR_PAYLOAD = 0, +}; + int bpf_dynptr_skb_read(const struct bpf_dynptr_kern *src, u32 offset, void *dst, u32 len) { const struct sk_buff *skb = src->data; - return ____bpf_skb_load_bytes(skb, offset, dst, len); + switch (src->offset) { + case SKB_DYNPTR_PAYLOAD: + return ____bpf_skb_load_bytes(skb, offset, dst, len); + + case SKB_DYNPTR_METADATA: + return -EOPNOTSUPP; /* not implemented */ + + default: + WARN_ONCE(true, "%s: unknown skb dynptr offset %d\n", __func__, src->offset); + return -EFAULT; + } } int bpf_dynptr_skb_write(const struct bpf_dynptr_kern *dst, u32 offset, @@ -11980,7 +11995,17 @@ int bpf_dynptr_skb_write(const struct bpf_dynptr_kern *dst, u32 offset, { struct sk_buff *skb = dst->data; - return ____bpf_skb_store_bytes(skb, offset, src, len, flags); + switch (dst->offset) { + case SKB_DYNPTR_PAYLOAD: + return ____bpf_skb_store_bytes(skb, offset, src, len, flags); + + case SKB_DYNPTR_METADATA: + return -EOPNOTSUPP; /* not implemented */ + + default: + WARN_ONCE(true, "%s: unknown skb dynptr offset %d\n", __func__, dst->offset); + return -EFAULT; + } } void *bpf_dynptr_skb_slice(const struct bpf_dynptr_kern *ptr, u32 offset, @@ -11988,10 +12013,20 @@ void *bpf_dynptr_skb_slice(const struct bpf_dynptr_kern *ptr, u32 offset, { const struct sk_buff *skb = ptr->data; - if (buf) - return skb_header_pointer(skb, offset, len, buf); - else - return skb_pointer_if_linear(skb, offset, len); + switch (ptr->offset) { + case SKB_DYNPTR_PAYLOAD: + if (buf) + return skb_header_pointer(skb, offset, len, buf); + else + return skb_pointer_if_linear(skb, offset, len); + + case SKB_DYNPTR_METADATA: + return NULL; /* not implemented */ + + default: + WARN_ONCE(true, "%s: unknown skb dynptr offset %d\n", __func__, ptr->offset); + return NULL; + } } __bpf_kfunc_start_defs(); @@ -12000,13 +12035,22 @@ __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags, { struct bpf_dynptr_kern *ptr = (struct bpf_dynptr_kern *)ptr__uninit; struct sk_buff *skb = (struct sk_buff *)s; + u32 offset, size; - if (flags) { + if (unlikely(flags & ~BPF_DYNPTR_F_SKB_METADATA)) { bpf_dynptr_set_null(ptr); return -EINVAL; } - bpf_dynptr_init(ptr, skb, BPF_DYNPTR_TYPE_SKB, 0, skb->len); + if (flags & BPF_DYNPTR_F_SKB_METADATA) { + offset = SKB_DYNPTR_METADATA; + size = skb_metadata_len(skb); + } else { + offset = SKB_DYNPTR_PAYLOAD; + size = skb->len; + } + + bpf_dynptr_init(ptr, skb, BPF_DYNPTR_TYPE_SKB, offset, size); return 0; } -- 2.43.0