Skip to content

Commit 12254a0

Browse files
authored
Fix unsafe header re-use on close and timeout (#2)
This commit takes a minimal approach to fixing unsafe header re-use during close and timeout by reallocating the header in those cases. Partially fixes: coder/coder#2429 Related: hashicorp#40
1 parent 7051340 commit 12254a0

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

stream.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package yamux
22

33
import (
44
"bytes"
5+
"errors"
56
"io"
67
"sync"
78
"sync/atomic"
@@ -200,6 +201,10 @@ START:
200201
// Send the header
201202
s.sendHdr.encode(typeData, flags, s.id, max)
202203
if err = s.session.waitForSendErr(s.sendHdr, body, s.sendErr); err != nil {
204+
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
205+
// Message left in ready queue, header re-use is unsafe.
206+
s.sendHdr = header(make([]byte, headerSize))
207+
}
203208
return 0, err
204209
}
205210

@@ -273,6 +278,10 @@ func (s *Stream) sendWindowUpdate() error {
273278
// Send the header
274279
s.controlHdr.encode(typeWindowUpdate, flags, s.id, delta)
275280
if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil {
281+
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
282+
// Message left in ready queue, header re-use is unsafe.
283+
s.controlHdr = header(make([]byte, headerSize))
284+
}
276285
return err
277286
}
278287
return nil
@@ -287,6 +296,10 @@ func (s *Stream) sendClose() error {
287296
flags |= flagFIN
288297
s.controlHdr.encode(typeWindowUpdate, flags, s.id, 0)
289298
if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil {
299+
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
300+
// Message left in ready queue, header re-use is unsafe.
301+
s.controlHdr = header(make([]byte, headerSize))
302+
}
290303
return err
291304
}
292305
return nil
@@ -362,8 +375,9 @@ func (s *Stream) closeTimeout() {
362375
// Send a RST so the remote side closes too.
363376
s.sendLock.Lock()
364377
defer s.sendLock.Unlock()
365-
s.sendHdr.encode(typeWindowUpdate, flagRST, s.id, 0)
366-
s.session.sendNoWait(s.sendHdr)
378+
hdr := header(make([]byte, headerSize))
379+
hdr.encode(typeWindowUpdate, flagRST, s.id, 0)
380+
s.session.sendNoWait(hdr)
367381
}
368382

369383
// forceClose is used for when the session is exiting

0 commit comments

Comments
 (0)