Now that we can create a dynptr to skb metadata, make reads to the metadata area possible with bpf_dynptr_read() or through a bpf_dynptr_slice(), and make writes to the metadata area possible with bpf_dynptr_write() or through a bpf_dynptr_slice_rdwr(). Signed-off-by: Jakub Sitnicki --- include/linux/filter.h | 18 ++++++++++++++++++ kernel/bpf/helpers.c | 6 +++--- net/core/filter.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index eca229752cbe..d0f39bf6828c 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1772,6 +1772,9 @@ 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_load_bytes(const struct sk_buff *src, u32 off, void *dst, u32 len); +int bpf_skb_meta_store_bytes(struct sk_buff *dst, u32 off, const void *src, u32 len); +void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 off, u32 len); #else /* CONFIG_NET */ static inline int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) @@ -1806,6 +1809,21 @@ static inline void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, voi unsigned long len, bool flush) { } + +static inline int bpf_skb_meta_load_bytes(const struct sk_buff *src, u32 off, void *dst, u32 len) +{ + return -EOPNOTSUPP; +} + +static inline int bpf_skb_meta_store_bytes(struct sk_buff *dst, u32 off, const void *src, u32 len) +{ + return -EOPNOTSUPP; +} + +static inline void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 off, u32 len) +{ + return NULL; +} #endif /* CONFIG_NET */ #endif /* __LINUX_FILTER_H__ */ 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 */ + 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, u32 len) +{ + u32 meta_len = skb_metadata_len(skb); + + if (len > meta_len || off > meta_len - len) + 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) +{ + const void *p = skb_metadata_pointer(src, off, len); + + 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); + + if (IS_ERR(p)) + return PTR_ERR(p); + + memmove(p, src, len); + return 0; +} + +void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 off, u32 len) +{ + void *p = skb_metadata_pointer(skb, off, len); + + return IS_ERR(p) ? NULL : p; +} + __bpf_kfunc_start_defs(); __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags, struct bpf_dynptr *ptr__uninit) -- 2.43.0