Commit 7c895ef8 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Daniel Borkmann says:

====================
bpf 2022-07-08

We've added 3 non-merge commits during the last 2 day(s) which contain
a total of 7 files changed, 40 insertions(+), 24 deletions(-).

The main changes are:

1) Fix cBPF splat triggered by skb not having a mac header, from Eric Dumazet.

2) Fix spurious packet loss in generic XDP when pushing packets out (note
   that native XDP is not affected by the issue), from Johan Almbladh.

3) Fix bpf_dynptr_{read,write}() helper signatures with flag argument before
   its set in stone as UAPI, from Joanne Koong.

* https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf:
  bpf: Add flags arg to bpf_dynptr_read and bpf_dynptr_write APIs
  bpf: Make sure mac_header was set before using it
  xdp: Fix spurious packet loss in generic XDP TX path
====================

Link: https://lore.kernel.org/r/20220708213418.19626-1-daniel@iogearbox.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 32b3ad14 f8d3da4e
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -5222,22 +5222,25 @@ union bpf_attr {
 *	Return
 *		Nothing. Always succeeds.
 *
 * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
 * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
 *	Description
 *		Read *len* bytes from *src* into *dst*, starting from *offset*
 *		into *src*.
 *		*flags* is currently unused.
 *	Return
 *		0 on success, -E2BIG if *offset* + *len* exceeds the length
 *		of *src*'s data, -EINVAL if *src* is an invalid dynptr.
 *		of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
 *		*flags* is not 0.
 *
 * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
 * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
 *	Description
 *		Write *len* bytes from *src* into *dst*, starting from *offset*
 *		into *dst*.
 *		*flags* is currently unused.
 *	Return
 *		0 on success, -E2BIG if *offset* + *len* exceeds the length
 *		of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
 *		is a read-only dynptr.
 *		is a read-only dynptr or if *flags* is not 0.
 *
 * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
 *	Description
+5 −3
Original line number Diff line number Diff line
@@ -68,11 +68,13 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
{
	u8 *ptr = NULL;

	if (k >= SKF_NET_OFF)
	if (k >= SKF_NET_OFF) {
		ptr = skb_network_header(skb) + k - SKF_NET_OFF;
	else if (k >= SKF_LL_OFF)
	} else if (k >= SKF_LL_OFF) {
		if (unlikely(!skb_mac_header_was_set(skb)))
			return NULL;
		ptr = skb_mac_header(skb) + k - SKF_LL_OFF;

	}
	if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
		return ptr;

+8 −4
Original line number Diff line number Diff line
@@ -1497,11 +1497,12 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
	.arg4_type	= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
};

BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset)
BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src,
	   u32, offset, u64, flags)
{
	int err;

	if (!src->data)
	if (!src->data || flags)
		return -EINVAL;

	err = bpf_dynptr_check_off_len(src, offset, len);
@@ -1521,13 +1522,15 @@ const struct bpf_func_proto bpf_dynptr_read_proto = {
	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
	.arg3_type	= ARG_PTR_TO_DYNPTR,
	.arg4_type	= ARG_ANYTHING,
	.arg5_type	= ARG_ANYTHING,
};

BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len)
BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src,
	   u32, len, u64, flags)
{
	int err;

	if (!dst->data || bpf_dynptr_is_rdonly(dst))
	if (!dst->data || flags || bpf_dynptr_is_rdonly(dst))
		return -EINVAL;

	err = bpf_dynptr_check_off_len(dst, offset, len);
@@ -1547,6 +1550,7 @@ const struct bpf_func_proto bpf_dynptr_write_proto = {
	.arg2_type	= ARG_ANYTHING,
	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
	.arg4_type	= ARG_CONST_SIZE_OR_ZERO,
	.arg5_type	= ARG_ANYTHING,
};

BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len)
+6 −2
Original line number Diff line number Diff line
@@ -4863,7 +4863,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
}

/* When doing generic XDP we have to bypass the qdisc layer and the
 * network taps in order to match in-driver-XDP behavior.
 * network taps in order to match in-driver-XDP behavior. This also means
 * that XDP packets are able to starve other packets going through a qdisc,
 * and DDOS attacks will be more effective. In-driver-XDP use dedicated TX
 * queues, so they do not have this starvation issue.
 */
void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
{
@@ -4875,7 +4878,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
	txq = netdev_core_pick_tx(dev, skb, NULL);
	cpu = smp_processor_id();
	HARD_TX_LOCK(dev, txq, cpu);
	if (!netif_xmit_stopped(txq)) {
	if (!netif_xmit_frozen_or_drv_stopped(txq)) {
		rc = netdev_start_xmit(skb, dev, txq, 0);
		if (dev_xmit_complete(rc))
			free_skb = false;
@@ -4883,6 +4886,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
	HARD_TX_UNLOCK(dev, txq);
	if (free_skb) {
		trace_xdp_exception(dev, xdp_prog, XDP_TX);
		dev_core_stats_tx_dropped_inc(dev);
		kfree_skb(skb);
	}
}
+7 −4
Original line number Diff line number Diff line
@@ -5222,22 +5222,25 @@ union bpf_attr {
 *	Return
 *		Nothing. Always succeeds.
 *
 * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
 * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
 *	Description
 *		Read *len* bytes from *src* into *dst*, starting from *offset*
 *		into *src*.
 *		*flags* is currently unused.
 *	Return
 *		0 on success, -E2BIG if *offset* + *len* exceeds the length
 *		of *src*'s data, -EINVAL if *src* is an invalid dynptr.
 *		of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
 *		*flags* is not 0.
 *
 * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
 * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
 *	Description
 *		Write *len* bytes from *src* into *dst*, starting from *offset*
 *		into *dst*.
 *		*flags* is currently unused.
 *	Return
 *		0 on success, -E2BIG if *offset* + *len* exceeds the length
 *		of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
 *		is a read-only dynptr.
 *		is a read-only dynptr or if *flags* is not 0.
 *
 * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
 *	Description
Loading