| From fb32f4f606c17b869805d7cede8b03d78339b50a Mon Sep 17 00:00:00 2001 |
| From: "Jason A. Donenfeld" <Jason@zx2c4.com> |
| Date: Mon, 29 Nov 2021 10:39:27 -0500 |
| Subject: wireguard: receive: drop handshakes if queue lock is contended |
| |
| From: Jason A. Donenfeld <Jason@zx2c4.com> |
| |
| commit fb32f4f606c17b869805d7cede8b03d78339b50a upstream. |
| |
| If we're being delivered packets from multiple CPUs so quickly that the |
| ring lock is contended for CPU tries, then it's safe to assume that the |
| queue is near capacity anyway, so just drop the packet rather than |
| spinning. This helps deal with multicore DoS that can interfere with |
| data path performance. It _still_ does not completely fix the issue, but |
| it again chips away at it. |
| |
| Reported-by: Streun Fabio <fstreun@student.ethz.ch> |
| Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") |
| Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/wireguard/receive.c | 16 +++++++++++++--- |
| 1 file changed, 13 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/net/wireguard/receive.c |
| +++ b/drivers/net/wireguard/receive.c |
| @@ -554,9 +554,19 @@ void wg_packet_receive(struct wg_device |
| case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION): |
| case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE): |
| case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): { |
| - int cpu; |
| - if (unlikely(!rng_is_initialized() || |
| - ptr_ring_produce_bh(&wg->handshake_queue.ring, skb))) { |
| + int cpu, ret = -EBUSY; |
| + |
| + if (unlikely(!rng_is_initialized())) |
| + goto drop; |
| + if (atomic_read(&wg->handshake_queue_len) > MAX_QUEUED_INCOMING_HANDSHAKES / 2) { |
| + if (spin_trylock_bh(&wg->handshake_queue.ring.producer_lock)) { |
| + ret = __ptr_ring_produce(&wg->handshake_queue.ring, skb); |
| + spin_unlock_bh(&wg->handshake_queue.ring.producer_lock); |
| + } |
| + } else |
| + ret = ptr_ring_produce_bh(&wg->handshake_queue.ring, skb); |
| + if (ret) { |
| + drop: |
| net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n", |
| wg->dev->name, skb); |
| goto err; |