aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-09-08 20:54:00 +0000
committerJason A. Donenfeld <Jason@zx2c4.com>2021-09-09 09:48:02 +0000
commitc6883cb188454c7ca95e704e10f4415a2d008dee (patch)
treeace9416266ebdfa2aa87a9230f529f33c94d34dc
parentversion: bump (diff)
downloadwireguard-nt-c6883cb188454c7ca95e704e10f4415a2d008dee.tar.xz
wireguard-nt-c6883cb188454c7ca95e704e10f4415a2d008dee.zip
driver: receive: drop handshakes if queue lock is contended
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> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--driver/containers.h20
-rw-r--r--driver/receive.c5
2 files changed, 24 insertions, 1 deletions
diff --git a/driver/containers.h b/driver/containers.h
index 4b5d998..600ef0a 100644
--- a/driver/containers.h
+++ b/driver/containers.h
@@ -173,6 +173,26 @@ PtrRingProduce(_Inout_ PTR_RING *Ring, _In_ __drv_aliasesMem VOID *Ptr)
return Ret;
}
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_Requires_lock_not_held_(Ring->ProducerLock)
+_Must_inspect_result_
+static inline NTSTATUS
+PtrRingTryProduce(_Inout_ PTR_RING *Ring, _In_ __drv_aliasesMem VOID *Ptr)
+{
+ NTSTATUS Ret;
+ KIRQL Irql = KeRaiseIrqlToDpcLevel();
+
+ if (!KeTryToAcquireSpinLockAtDpcLevel(&Ring->ProducerLock))
+ {
+ KeLowerIrql(Irql);
+ return STATUS_LOCK_NOT_GRANTED;
+ }
+ Ret = __PtrRingProduce(Ring, Ptr);
+ KeReleaseSpinLock(&Ring->ProducerLock, Irql);
+
+ return Ret;
+}
+
_Requires_lock_held_(Ring->ConsumerLock)
_Must_inspect_result_
_Post_maybenull_
diff --git a/driver/receive.c b/driver/receive.c
index 0348e32..14711aa 100644
--- a/driver/receive.c
+++ b/driver/receive.c
@@ -578,7 +578,10 @@ PacketReceive(WG_DEVICE *Wg, NET_BUFFER_LIST *First)
case CpuToLe32(MESSAGE_TYPE_HANDSHAKE_INITIATION):
case CpuToLe32(MESSAGE_TYPE_HANDSHAKE_RESPONSE):
case CpuToLe32(MESSAGE_TYPE_HANDSHAKE_COOKIE): {
- if (!NT_SUCCESS(PtrRingProduce(&Wg->HandshakeRxQueue, Nbl)))
+ NTSTATUS Ret = ReadULongNoFence(&Wg->HandshakeRxQueueLen) >= MAX_QUEUED_INCOMING_HANDSHAKES / 2
+ ? PtrRingTryProduce(&Wg->HandshakeRxQueue, Nbl)
+ : PtrRingProduce(&Wg->HandshakeRxQueue, Nbl);
+ if (!NT_SUCCESS(Ret))
{
LogInfoNblRatelimited(Wg, "Dropping handshake packet from %s", Nbl);
goto cleanup;