Skip to content

Commit 279210d

Browse files
ericktFiloSottile
authored andcommitted
ssh: don't err out on channel request msgs to unknown channels
rfc4254 section 5.4 states that channel request messages sent to an unrecognized channel should be replied with a `SSH_MSG_CHANNEL_FAILURE`, rather than erring out and closing the mux. This can occur with servers like openssh-portable, which can begin to close a channel and also use that channel for keepalives before it has received a closed response from the client. Fixes golang/go#38908 Change-Id: Id68b77e16b2889d3a21d505ed8018f9f457e067a GitHub-Last-Rev: 8a92f87 GitHub-Pull-Request: golang#136 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/232659 Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]>
1 parent 06a226f commit 279210d

File tree

2 files changed

+236
-1
lines changed

2 files changed

+236
-1
lines changed

ssh/mux.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (m *mux) onePacket() error {
240240
id := binary.BigEndian.Uint32(packet[1:])
241241
ch := m.chanList.getChan(id)
242242
if ch == nil {
243-
return fmt.Errorf("ssh: invalid channel %d", id)
243+
return m.handleUnknownChannelPacket(id, packet)
244244
}
245245

246246
return ch.handlePacket(packet)
@@ -328,3 +328,24 @@ func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
328328
return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
329329
}
330330
}
331+
332+
func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) error {
333+
msg, err := decode(packet)
334+
if err != nil {
335+
return err
336+
}
337+
338+
switch msg := msg.(type) {
339+
// RFC 4254 section 5.4 says unrecognized channel requests should
340+
// receive a failure response.
341+
case *channelRequestMsg:
342+
if msg.WantReply {
343+
return m.sendMessage(channelRequestFailureMsg{
344+
PeersID: msg.PeersID,
345+
})
346+
}
347+
return nil
348+
default:
349+
return fmt.Errorf("ssh: invalid channel %d", id)
350+
}
351+
}

ssh/mux_test.go

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"io/ioutil"
1010
"sync"
1111
"testing"
12+
"time"
1213
)
1314

1415
func muxPair() (*mux, *mux) {
@@ -288,6 +289,219 @@ func TestMuxChannelRequest(t *testing.T) {
288289
}
289290
}
290291

292+
func TestMuxUnknownChannelRequests(t *testing.T) {
293+
clientPipe, serverPipe := memPipe()
294+
client := newMux(clientPipe)
295+
defer serverPipe.Close()
296+
defer client.Close()
297+
298+
kDone := make(chan struct{})
299+
go func() {
300+
// Ignore unknown channel messages that don't want a reply.
301+
err := serverPipe.writePacket(Marshal(channelRequestMsg{
302+
PeersID: 1,
303+
Request: "[email protected]",
304+
WantReply: false,
305+
RequestSpecificData: []byte{},
306+
}))
307+
if err != nil {
308+
t.Fatalf("send: %v", err)
309+
}
310+
311+
// Send a keepalive, which should get a channel failure message
312+
// in response.
313+
err = serverPipe.writePacket(Marshal(channelRequestMsg{
314+
PeersID: 2,
315+
Request: "[email protected]",
316+
WantReply: true,
317+
RequestSpecificData: []byte{},
318+
}))
319+
if err != nil {
320+
t.Fatalf("send: %v", err)
321+
}
322+
323+
packet, err := serverPipe.readPacket()
324+
if err != nil {
325+
t.Fatalf("read packet: %v", err)
326+
}
327+
decoded, err := decode(packet)
328+
if err != nil {
329+
t.Fatalf("decode failed: %v", err)
330+
}
331+
332+
switch msg := decoded.(type) {
333+
case *channelRequestFailureMsg:
334+
if msg.PeersID != 2 {
335+
t.Fatalf("received response to wrong message: %v", msg)
336+
}
337+
default:
338+
t.Fatalf("unexpected channel message: %v", msg)
339+
}
340+
341+
kDone <- struct{}{}
342+
343+
// Receive and respond to the keepalive to confirm the mux is
344+
// still processing requests.
345+
packet, err = serverPipe.readPacket()
346+
if err != nil {
347+
t.Fatalf("read packet: %v", err)
348+
}
349+
if packet[0] != msgGlobalRequest {
350+
t.Fatalf("expected global request")
351+
}
352+
353+
err = serverPipe.writePacket(Marshal(globalRequestFailureMsg{
354+
Data: []byte{},
355+
}))
356+
if err != nil {
357+
t.Fatalf("failed to send failure msg: %v", err)
358+
}
359+
360+
close(kDone)
361+
}()
362+
363+
// Wait for the server to send the keepalive message and receive back a
364+
// response.
365+
select {
366+
case <-kDone:
367+
case <-time.After(10 * time.Second):
368+
t.Fatalf("server never received ack")
369+
}
370+
371+
// Confirm client hasn't closed.
372+
if _, _, err := client.SendRequest("[email protected]", true, nil); err != nil {
373+
t.Fatalf("failed to send keepalive: %v", err)
374+
}
375+
376+
select {
377+
case <-kDone:
378+
case <-time.After(10 * time.Second):
379+
t.Fatalf("server never shut down")
380+
}
381+
}
382+
383+
func TestMuxClosedChannel(t *testing.T) {
384+
clientPipe, serverPipe := memPipe()
385+
client := newMux(clientPipe)
386+
defer serverPipe.Close()
387+
defer client.Close()
388+
389+
kDone := make(chan struct{})
390+
go func() {
391+
// Open the channel.
392+
packet, err := serverPipe.readPacket()
393+
if err != nil {
394+
t.Fatalf("read packet: %v", err)
395+
}
396+
if packet[0] != msgChannelOpen {
397+
t.Fatalf("expected chan open")
398+
}
399+
400+
var openMsg channelOpenMsg
401+
if err := Unmarshal(packet, &openMsg); err != nil {
402+
t.Fatalf("unmarshal: %v", err)
403+
}
404+
405+
// Send back the opened channel confirmation.
406+
err = serverPipe.writePacket(Marshal(channelOpenConfirmMsg{
407+
PeersID: openMsg.PeersID,
408+
MyID: 0,
409+
MyWindow: 0,
410+
MaxPacketSize: channelMaxPacket,
411+
}))
412+
if err != nil {
413+
t.Fatalf("send: %v", err)
414+
}
415+
416+
// Close the channel.
417+
err = serverPipe.writePacket(Marshal(channelCloseMsg{
418+
PeersID: openMsg.PeersID,
419+
}))
420+
if err != nil {
421+
t.Fatalf("send: %v", err)
422+
}
423+
424+
// Send a keepalive message on the channel we just closed.
425+
err = serverPipe.writePacket(Marshal(channelRequestMsg{
426+
PeersID: openMsg.PeersID,
427+
Request: "[email protected]",
428+
WantReply: true,
429+
RequestSpecificData: []byte{},
430+
}))
431+
if err != nil {
432+
t.Fatalf("send: %v", err)
433+
}
434+
435+
// Receive the channel closed response.
436+
packet, err = serverPipe.readPacket()
437+
if err != nil {
438+
t.Fatalf("read packet: %v", err)
439+
}
440+
if packet[0] != msgChannelClose {
441+
t.Fatalf("expected channel close")
442+
}
443+
444+
// Receive the keepalive response failure.
445+
packet, err = serverPipe.readPacket()
446+
if err != nil {
447+
t.Fatalf("read packet: %v", err)
448+
}
449+
if packet[0] != msgChannelFailure {
450+
t.Fatalf("expected channel close")
451+
}
452+
kDone <- struct{}{}
453+
454+
// Receive and respond to the keepalive to confirm the mux is
455+
// still processing requests.
456+
packet, err = serverPipe.readPacket()
457+
if err != nil {
458+
t.Fatalf("read packet: %v", err)
459+
}
460+
if packet[0] != msgGlobalRequest {
461+
t.Fatalf("expected global request")
462+
}
463+
464+
err = serverPipe.writePacket(Marshal(globalRequestFailureMsg{
465+
Data: []byte{},
466+
}))
467+
if err != nil {
468+
t.Fatalf("failed to send failure msg: %v", err)
469+
}
470+
471+
close(kDone)
472+
}()
473+
474+
// Open a channel.
475+
ch, err := client.openChannel("chan", nil)
476+
if err != nil {
477+
t.Fatalf("OpenChannel: %v", err)
478+
}
479+
defer ch.Close()
480+
481+
// Wait for the server to close the channel and send the keepalive.
482+
select {
483+
case <-kDone:
484+
case <-time.After(10 * time.Second):
485+
t.Fatalf("server never received ack")
486+
}
487+
488+
// Make sure the channel closed.
489+
if _, ok := <-ch.incomingRequests; ok {
490+
t.Fatalf("channel not closed")
491+
}
492+
493+
// Confirm client hasn't closed
494+
if _, _, err := client.SendRequest("[email protected]", true, nil); err != nil {
495+
t.Fatalf("failed to send keepalive: %v", err)
496+
}
497+
498+
select {
499+
case <-kDone:
500+
case <-time.After(10 * time.Second):
501+
t.Fatalf("server never shut down")
502+
}
503+
}
504+
291505
func TestMuxGlobalRequest(t *testing.T) {
292506
clientMux, serverMux := muxPair()
293507
defer serverMux.Close()

0 commit comments

Comments
 (0)