Make it possible to read from or write to skb metadata area using the dynptr slices creates with bpf_dynptr_slice() or bpf_dynptr_slice_rdwr(). This prepares ground for access to skb metadata from all BPF hooks which operate on __sk_buff context. Signed-off-by: Jakub Sitnicki --- include/linux/filter.h | 6 ++++++ kernel/bpf/helpers.c | 2 +- net/core/filter.c | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 7709e30ce2bb..a28c3a1593c9 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1776,6 +1776,7 @@ int bpf_skb_meta_load_bytes(const struct sk_buff *src, u32 offset, void *dst, u32 len); int bpf_skb_meta_store_bytes(struct sk_buff *dst, u32 offset, const void *src, u32 len); +void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset, u32 len); #else /* CONFIG_NET */ static inline int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) @@ -1822,6 +1823,11 @@ static inline int bpf_skb_meta_store_bytes(struct sk_buff *dst, u32 offset, { return -EOPNOTSUPP; } + +static inline void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset, u32 len) +{ + return NULL; +} #endif /* CONFIG_NET */ #endif /* __LINUX_FILTER_H__ */ diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index ee057051db94..237fb5f9d625 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -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 3cbadee77492..6d9a462a0042 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -12002,6 +12002,16 @@ int bpf_skb_meta_store_bytes(struct sk_buff *dst, u32 offset, return 0; } +void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset, u32 len) +{ + u32 meta_len = skb_metadata_len(skb); + + if (len > meta_len || offset > meta_len - len) + return NULL; /* out of bounds */ + + return skb_metadata_end(skb) - meta_len + offset; +} + static int dynptr_from_skb_meta(struct __sk_buff *skb_, u64 flags, struct bpf_dynptr *ptr_, bool rdonly) { -- 2.43.0