diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-09-08 20:54:00 +0000 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-09-09 09:48:02 +0000 |
commit | c6883cb188454c7ca95e704e10f4415a2d008dee (patch) | |
tree | ace9416266ebdfa2aa87a9230f529f33c94d34dc | |
parent | version: bump (diff) | |
download | wireguard-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.h | 20 | ||||
-rw-r--r-- | driver/receive.c | 5 |
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; |