4c696caca8
added patch quic-go.patch (boo#1222473) OBS-URL: https://build.opensuse.org/request/show/1169703 OBS-URL: https://build.opensuse.org/package/show/server:dns/dnscrypt-proxy?expand=0&rev=51
118 lines
3.6 KiB
Diff
118 lines
3.6 KiB
Diff
From: cunix@mail.de
|
|
Date: 2024-04-21 12:00:00
|
|
Subject: Memory Exhaustion Attack against QUIC's Connection ID Mechanism
|
|
References: https://github.com/quic-go/quic-go/commit/4a99b816ae3ab03ae5449d15aac45147c85ed47a
|
|
https://github.com/quic-go/quic-go/security/advisories/GHSA-c33x-xqrf-c478
|
|
https://bugzilla.suse.com/show_bug.cgi?id=1222473
|
|
|
|
This tries to backport commit
|
|
https://github.com/quic-go/quic-go/commit/4a99b816ae3ab03ae5449d15aac45147c85ed47a.patch
|
|
from Marten Seemann <martenseemann@gmail.com>
|
|
to the vendored older version of quic-go.
|
|
|
|
dnscrypt-proxy upstream already vendors version 0.42 of quic-go with hack
|
|
included, but is not released.
|
|
|
|
Patch should be dropped with next release of dnscrypt-proxy.
|
|
|
|
---
|
|
|
|
diff -r -U 5 a/vendor/github.com/quic-go/quic-go/connection.go b/vendor/github.com/quic-go/quic-go/connection.go
|
|
--- a/vendor/github.com/quic-go/quic-go/connection.go
|
|
+++ b/vendor/github.com/quic-go/quic-go/connection.go
|
|
@@ -516,11 +516,14 @@
|
|
|
|
var sendQueueAvailable <-chan struct{}
|
|
|
|
runLoop:
|
|
for {
|
|
- // Close immediately if requested
|
|
+ if s.framer.QueuedTooManyControlFrames() {
|
|
+ s.closeLocal(&qerr.TransportError{ErrorCode: InternalError})
|
|
+ }
|
|
+ // Close immediately if requested
|
|
select {
|
|
case closeErr = <-s.closeChan:
|
|
break runLoop
|
|
default:
|
|
}
|
|
diff -r -U 5 a/vendor/github.com/quic-go/quic-go/framer.go b/vendor/github.com/quic-go/quic-go/framer.go
|
|
--- a/vendor/github.com/quic-go/quic-go/framer.go
|
|
+++ b/vendor/github.com/quic-go/quic-go/framer.go
|
|
@@ -19,22 +19,32 @@
|
|
|
|
AddActiveStream(protocol.StreamID)
|
|
AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount)
|
|
|
|
Handle0RTTRejection() error
|
|
+
|
|
+ // QueuedTooManyControlFrames says if the control frame queue exceeded its maximum queue length.
|
|
+ // This is a hack.
|
|
+ // It is easier to implement than propagating an error return value in QueueControlFrame.
|
|
+ // The correct solution would be to queue frames with their respective structs.
|
|
+ // See https://github.com/quic-go/quic-go/issues/4271 for the queueing of stream-related control frames.
|
|
+ QueuedTooManyControlFrames() bool
|
|
}
|
|
|
|
+const maxControlFrames = 16 << 10
|
|
+
|
|
type framerI struct {
|
|
mutex sync.Mutex
|
|
|
|
streamGetter streamGetter
|
|
|
|
activeStreams map[protocol.StreamID]struct{}
|
|
streamQueue ringbuffer.RingBuffer[protocol.StreamID]
|
|
|
|
controlFrameMutex sync.Mutex
|
|
controlFrames []wire.Frame
|
|
+ queuedTooManyControlFrames bool
|
|
}
|
|
|
|
var _ framer = &framerI{}
|
|
|
|
func newFramer(streamGetter streamGetter) framer {
|
|
@@ -56,11 +66,24 @@
|
|
f.controlFrameMutex.Unlock()
|
|
return hasData
|
|
}
|
|
|
|
func (f *framerI) QueueControlFrame(frame wire.Frame) {
|
|
+ var returnearly bool
|
|
f.controlFrameMutex.Lock()
|
|
+ // This is a hack.
|
|
+ if len(f.controlFrames) >= maxControlFrames {
|
|
+ returnearly = true
|
|
+ }
|
|
+ f.controlFrameMutex.Unlock()
|
|
+ if returnearly {
|
|
+ f.mutex.Lock()
|
|
+ f.queuedTooManyControlFrames = true
|
|
+ f.mutex.Unlock()
|
|
+ return
|
|
+ }
|
|
+ f.controlFrameMutex.Lock()
|
|
f.controlFrames = append(f.controlFrames, frame)
|
|
f.controlFrameMutex.Unlock()
|
|
}
|
|
|
|
func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount) {
|
|
@@ -78,10 +101,17 @@
|
|
}
|
|
f.controlFrameMutex.Unlock()
|
|
return frames, length
|
|
}
|
|
|
|
+func (f *framerI) QueuedTooManyControlFrames() bool {
|
|
+ f.mutex.Lock()
|
|
+ toomany := f.queuedTooManyControlFrames
|
|
+ f.mutex.Unlock()
|
|
+ return toomany
|
|
+}
|
|
+
|
|
func (f *framerI) AddActiveStream(id protocol.StreamID) {
|
|
f.mutex.Lock()
|
|
if _, ok := f.activeStreams[id]; !ok {
|
|
f.streamQueue.PushBack(id)
|
|
f.activeStreams[id] = struct{}{}
|