From 2becdd6414c10765f80cd124e3bed1d816fa4a72 Mon Sep 17 00:00:00 2001 From: mmmray <142015632+mmmray@users.noreply.github.com> Date: Fri, 26 Jul 2024 04:36:55 +0200 Subject: [PATCH] SplitHTTP server: Fix panic during concurrent Close and Push (#3593) When Close and Push are called concurrently, it may happen that Push attempts to write to an already-closed channel, and trigger a panic. From a user perspective, it results in logs like this: http: panic serving 172.19.0.6:50476: send on closed channel It's probably triggered when download is closed at the same time an upload packet is submitted. These panics don't crash the server and the inbound is still usable. --- transport/internet/splithttp/upload_queue.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/transport/internet/splithttp/upload_queue.go b/transport/internet/splithttp/upload_queue.go index 2d1fb5f4..23124c4f 100644 --- a/transport/internet/splithttp/upload_queue.go +++ b/transport/internet/splithttp/upload_queue.go @@ -6,6 +6,7 @@ package splithttp import ( "container/heap" "io" + "sync" "github.com/xtls/xray-core/common/errors" ) @@ -16,11 +17,12 @@ type Packet struct { } type uploadQueue struct { - pushedPackets chan Packet - heap uploadHeap - nextSeq uint64 - closed bool - maxPackets int + pushedPackets chan Packet + writeCloseMutex sync.Mutex + heap uploadHeap + nextSeq uint64 + closed bool + maxPackets int } func NewUploadQueue(maxPackets int) *uploadQueue { @@ -34,6 +36,9 @@ func NewUploadQueue(maxPackets int) *uploadQueue { } func (h *uploadQueue) Push(p Packet) error { + h.writeCloseMutex.Lock() + defer h.writeCloseMutex.Unlock() + if h.closed { return errors.New("splithttp packet queue closed") } @@ -43,6 +48,9 @@ func (h *uploadQueue) Push(p Packet) error { } func (h *uploadQueue) Close() error { + h.writeCloseMutex.Lock() + defer h.writeCloseMutex.Unlock() + h.closed = true close(h.pushedPackets) return nil