mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-25 13:43:55 +08:00
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: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7c895ef884
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -140,12 +140,12 @@ int use_after_invalid(void *ctx)
|
||||
|
||||
bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
|
||||
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
|
||||
|
||||
bpf_ringbuf_submit_dynptr(&ptr, 0);
|
||||
|
||||
/* this should fail */
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -338,7 +338,7 @@ int invalid_helper2(void *ctx)
|
||||
get_map_val_dynptr(&ptr);
|
||||
|
||||
/* this should fail */
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0);
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -377,7 +377,7 @@ int invalid_write2(void *ctx)
|
||||
memcpy((void *)&ptr + 8, &x, sizeof(x));
|
||||
|
||||
/* this should fail */
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
|
||||
|
||||
bpf_ringbuf_submit_dynptr(&ptr, 0);
|
||||
|
||||
@ -473,7 +473,7 @@ int invalid_read2(void *ctx)
|
||||
get_map_val_dynptr(&ptr);
|
||||
|
||||
/* this should fail */
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0);
|
||||
bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,10 +43,10 @@ int test_read_write(void *ctx)
|
||||
bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
|
||||
|
||||
/* Write data into the dynptr */
|
||||
err = err ?: bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data));
|
||||
err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
|
||||
|
||||
/* Read the data that was written into the dynptr */
|
||||
err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
|
||||
err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
|
||||
|
||||
/* Ensure the data we read matches the data we wrote */
|
||||
for (i = 0; i < sizeof(read_data); i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user