Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/linux/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 6 additions & 7 deletions include/linux/if_vlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,16 +355,17 @@ static inline int __vlan_insert_inner_tag(struct sk_buff *skb,
__be16 vlan_proto, u16 vlan_tci,
unsigned int mac_len)
{
const u8 meta_len = mac_len > ETH_TLEN ? skb_metadata_len(skb) : 0;
struct vlan_ethhdr *veth;

if (skb_cow_head(skb, VLAN_HLEN) < 0)
if (skb_cow_head(skb, meta_len + VLAN_HLEN) < 0)
return -ENOMEM;

skb_push(skb, VLAN_HLEN);

/* Move the mac header sans proto to the beginning of the new header. */
if (likely(mac_len > ETH_TLEN))
memmove(skb->data, skb->data + VLAN_HLEN, mac_len - ETH_TLEN);
skb_postpush_data_move(skb, VLAN_HLEN, mac_len - ETH_TLEN);
if (skb_mac_header_was_set(skb))
skb->mac_header -= VLAN_HLEN;

Expand Down Expand Up @@ -731,18 +732,16 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
*
* Expects the skb to contain a VLAN tag in the payload, and to have skb->data
* pointing at the MAC header.
*
* Returns: a new pointer to skb->data, or NULL on failure to pull.
*/
static inline void *vlan_remove_tag(struct sk_buff *skb, u16 *vlan_tci)
static inline void vlan_remove_tag(struct sk_buff *skb, u16 *vlan_tci)
{
struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);

*vlan_tci = ntohs(vhdr->h_vlan_TCI);

memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
vlan_set_encap_proto(skb, vhdr);
return __skb_pull(skb, VLAN_HLEN);
__skb_pull(skb, VLAN_HLEN);
skb_postpull_data_move(skb, VLAN_HLEN, 2 * ETH_ALEN);
}

/**
Expand Down
75 changes: 75 additions & 0 deletions include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -4561,6 +4561,81 @@ static inline void skb_metadata_clear(struct sk_buff *skb)
skb_metadata_set(skb, 0);
}

/**
* skb_data_move - Move packet data and metadata after skb_push() or skb_pull().
* @skb: packet to operate on
* @len: number of bytes pushed or pulled from &sk_buff->data
* @n: number of bytes to memmove() from pre-push/pull &sk_buff->data
*
* Moves @n bytes of packet data, can be zero, and all bytes of skb metadata.
*
* Assumes metadata is located immediately before &sk_buff->data prior to the
* push/pull, and that sufficient headroom exists to hold it after an
* skb_push(). Otherwise, metadata is cleared and a one-time warning is issued.
*
* Prefer skb_postpull_data_move() or skb_postpush_data_move() to calling this
* helper directly.
*/
static inline void skb_data_move(struct sk_buff *skb, const int len,
const unsigned int n)
{
const u8 meta_len = skb_metadata_len(skb);
u8 *meta, *meta_end;

if (!len || (!n && !meta_len))
return;

if (!meta_len)
goto no_metadata;

meta_end = skb_metadata_end(skb);
meta = meta_end - meta_len;

if (WARN_ON_ONCE(meta_end + len != skb->data ||
meta_len > skb_headroom(skb))) {
skb_metadata_clear(skb);
goto no_metadata;
}

memmove(meta + len, meta, meta_len + n);
return;

no_metadata:
memmove(skb->data, skb->data - len, n);
}

/**
* skb_postpull_data_move - Move packet data and metadata after skb_pull().
* @skb: packet to operate on
* @len: number of bytes pulled from &sk_buff->data
* @n: number of bytes to memmove() from pre-pull &sk_buff->data
*
* See skb_data_move() for details.
*/
static inline void skb_postpull_data_move(struct sk_buff *skb,
const unsigned int len,
const unsigned int n)
{
DEBUG_NET_WARN_ON_ONCE(len > INT_MAX);
skb_data_move(skb, len, n);
}

/**
* skb_postpush_data_move - Move packet data and metadata after skb_push().
* @skb: packet to operate on
* @len: number of bytes pushed onto &sk_buff->data
* @n: number of bytes to memmove() from pre-push &sk_buff->data
*
* See skb_data_move() for details.
*/
static inline void skb_postpush_data_move(struct sk_buff *skb,
const unsigned int len,
const unsigned int n)
{
DEBUG_NET_WARN_ON_ONCE(len > INT_MAX);
skb_data_move(skb, -len, n);
}

struct sk_buff *skb_clone_sk(struct sk_buff *skb);

#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
Expand Down
6 changes: 2 additions & 4 deletions kernel/bpf/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1890,10 +1890,8 @@ int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u64 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;
Expand Down
34 changes: 22 additions & 12 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3260,11 +3260,11 @@ static void bpf_skb_change_protocol(struct sk_buff *skb, u16 proto)

static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)
{
/* Caller already did skb_cow() with len as headroom,
/* Caller already did skb_cow() with meta_len+len as headroom,
* so no need to do it here.
*/
skb_push(skb, len);
memmove(skb->data, skb->data + len, off);
skb_postpush_data_move(skb, len, off);
memset(skb->data + off, 0, len);

/* No skb_postpush_rcsum(skb, skb->data + off, len)
Expand All @@ -3288,7 +3288,7 @@ static int bpf_skb_generic_pop(struct sk_buff *skb, u32 off, u32 len)
old_data = skb->data;
__skb_pull(skb, len);
skb_postpull_rcsum(skb, old_data + off, len);
memmove(skb->data, old_data, off);
skb_postpull_data_move(skb, len, off);

return 0;
}
Expand Down Expand Up @@ -3333,10 +3333,11 @@ static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len)
static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
{
const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
const u8 meta_len = skb_metadata_len(skb);
u32 off = skb_mac_header_len(skb);
int ret;

ret = skb_cow(skb, len_diff);
ret = skb_cow(skb, meta_len + len_diff);
if (unlikely(ret < 0))
return ret;

Expand Down Expand Up @@ -3496,6 +3497,7 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
u8 inner_mac_len = flags >> BPF_ADJ_ROOM_ENCAP_L2_SHIFT;
bool encap = flags & BPF_F_ADJ_ROOM_ENCAP_L3_MASK;
u16 mac_len = 0, inner_net = 0, inner_trans = 0;
const u8 meta_len = skb_metadata_len(skb);
unsigned int gso_type = SKB_GSO_DODGY;
int ret;

Expand All @@ -3506,7 +3508,7 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
return -ENOTSUPP;
}

ret = skb_cow_head(skb, len_diff);
ret = skb_cow_head(skb, meta_len + len_diff);
if (unlikely(ret < 0))
return ret;

Expand Down Expand Up @@ -3880,6 +3882,7 @@ static const struct bpf_func_proto sk_skb_change_tail_proto = {
static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
u64 flags)
{
const u8 meta_len = skb_metadata_len(skb);
u32 max_len = BPF_SKB_MAX_LEN;
u32 new_len = skb->len + head_room;
int ret;
Expand All @@ -3888,7 +3891,7 @@ static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
new_len < skb->len))
return -EINVAL;

ret = skb_cow(skb, head_room);
ret = skb_cow(skb, meta_len + head_room);
if (likely(!ret)) {
/* Idea for this helper is that we currently only
* allow to expand on mac header. This means that
Expand All @@ -3900,6 +3903,7 @@ static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
* for redirection into L2 device.
*/
__skb_push(skb, head_room);
skb_postpush_data_move(skb, head_room, 0);
memset(skb->data, 0, head_room);
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);
Expand Down Expand Up @@ -12022,6 +12026,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)
Expand Down Expand Up @@ -12049,9 +12065,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
Expand All @@ -12069,9 +12082,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;
}

Expand Down
6 changes: 4 additions & 2 deletions net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -2218,6 +2218,10 @@ EXPORT_SYMBOL(__pskb_copy_fclone);
*
* All the pointers pointing into skb header may change and must be
* reloaded after call to this function.
*
* Note: If you skb_push() the start of the buffer after reallocating the
* header, call skb_postpush_data_move() first to move the metadata out of
* the way before writing to &sk_buff->data.
*/

int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
Expand Down Expand Up @@ -2289,8 +2293,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb->nohdr = 0;
atomic_set(&skb_shinfo(skb)->dataref, 1);

skb_metadata_clear(skb);

/* It is not generally safe to change skb->truesize.
* For the moment, we really care of rx path, or
* when skb is orphaned (not attached to a socket).
Expand Down
Loading
Loading