Skip to content

Commit da5eff7

Browse files
jsitnickiKernel Patches Daemon
authored andcommitted
net: Helper to move packet data and metadata after skb_push/pull
Lay groundwork for fixing BPF helpers available to TC(X) programs. When skb_push() or skb_pull() is called in a TC(X) ingress BPF program, the skb metadata must be kept in front of the MAC header. Otherwise, BPF programs using the __sk_buff->data_meta pseudo-pointer lose access to it. Introduce a helper that moves both metadata and a specified number of packet data bytes together, suitable as a drop-in replacement for memmove(). Signed-off-by: Jakub Sitnicki <[email protected]>
1 parent 1f11231 commit da5eff7

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

include/linux/skbuff.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4561,6 +4561,81 @@ static inline void skb_metadata_clear(struct sk_buff *skb)
45614561
skb_metadata_set(skb, 0);
45624562
}
45634563

4564+
/**
4565+
* skb_data_move - Move packet data and metadata after skb_push() or skb_pull().
4566+
* @skb: packet to operate on
4567+
* @len: number of bytes pushed or pulled from &sk_buff->data
4568+
* @n: number of bytes to memmove() from pre-push/pull &sk_buff->data
4569+
*
4570+
* Moves @n bytes of packet data, can be zero, and all bytes of skb metadata.
4571+
*
4572+
* Assumes metadata is located immediately before &sk_buff->data prior to the
4573+
* push/pull, and that sufficient headroom exists to hold it after an
4574+
* skb_push(). Otherwise, metadata is cleared and a one-time warning is issued.
4575+
*
4576+
* Prefer skb_postpull_data_move() or skb_postpush_data_move() to calling this
4577+
* helper directly.
4578+
*/
4579+
static inline void skb_data_move(struct sk_buff *skb, const int len,
4580+
const unsigned int n)
4581+
{
4582+
const u8 meta_len = skb_metadata_len(skb);
4583+
u8 *meta, *meta_end;
4584+
4585+
if (!len || (!n && !meta_len))
4586+
return;
4587+
4588+
if (!meta_len)
4589+
goto no_metadata;
4590+
4591+
meta_end = skb_metadata_end(skb);
4592+
meta = meta_end - meta_len;
4593+
4594+
if (WARN_ON_ONCE(meta_end + len != skb->data ||
4595+
meta_len > skb_headroom(skb))) {
4596+
skb_metadata_clear(skb);
4597+
goto no_metadata;
4598+
}
4599+
4600+
memmove(meta + len, meta, meta_len + n);
4601+
return;
4602+
4603+
no_metadata:
4604+
memmove(skb->data, skb->data - len, n);
4605+
}
4606+
4607+
/**
4608+
* skb_postpull_data_move - Move packet data and metadata after skb_pull().
4609+
* @skb: packet to operate on
4610+
* @len: number of bytes pulled from &sk_buff->data
4611+
* @n: number of bytes to memmove() from pre-pull &sk_buff->data
4612+
*
4613+
* See skb_data_move() for details.
4614+
*/
4615+
static inline void skb_postpull_data_move(struct sk_buff *skb,
4616+
const unsigned int len,
4617+
const unsigned int n)
4618+
{
4619+
DEBUG_NET_WARN_ON_ONCE(len > INT_MAX);
4620+
skb_data_move(skb, len, n);
4621+
}
4622+
4623+
/**
4624+
* skb_postpush_data_move - Move packet data and metadata after skb_push().
4625+
* @skb: packet to operate on
4626+
* @len: number of bytes pushed onto &sk_buff->data
4627+
* @n: number of bytes to memmove() from pre-push &sk_buff->data
4628+
*
4629+
* See skb_data_move() for details.
4630+
*/
4631+
static inline void skb_postpush_data_move(struct sk_buff *skb,
4632+
const unsigned int len,
4633+
const unsigned int n)
4634+
{
4635+
DEBUG_NET_WARN_ON_ONCE(len > INT_MAX);
4636+
skb_data_move(skb, -len, n);
4637+
}
4638+
45644639
struct sk_buff *skb_clone_sk(struct sk_buff *skb);
45654640

45664641
#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING

0 commit comments

Comments
 (0)