浏览代码

go.crypto/ssh: allow zero sized window adjustments

The RFC doesn't prohibit zero sized window adjustments and
there is evidence of well known clients using them in the
wild.

R=agl, kardianos, gustav.paul
CC=golang-dev
https://golang.org/cl/6209082
Dave Cheney 13 年之前
父节点
当前提交
55aa08130e
共有 2 个文件被更改,包括 55 次插入1 次删除
  1. 2 1
      ssh/common.go
  2. 53 0
      ssh/session_test.go

+ 2 - 1
ssh/common.go

@@ -300,8 +300,9 @@ type window struct {
 // add adds win to the amount of window available
 // for consumers.
 func (w *window) add(win uint32) bool {
+	// a zero sized window adjust is a noop.
 	if win == 0 {
-		return false
+		return true
 	}
 	w.L.Lock()
 	if w.win+win < win {

+ 53 - 0
ssh/session_test.go

@@ -294,6 +294,50 @@ func TestInvalidServerMessage(t *testing.T) {
 	defer session.Close()
 }
 
+// In the wild some clients (and servers) send zero sized window updates. 
+// Test that the client can continue after receiving a zero sized update.
+func TestClientZeroWindowAdjust(t *testing.T) {
+	conn := dial(sendZeroWindowAdjust, t)
+	defer conn.Close()
+	session, err := conn.NewSession()
+	if err != nil {
+		t.Fatalf("Unable to request new session: %s", err)
+	}
+	defer session.Close()
+
+	if err := session.Shell(); err != nil {
+		t.Fatalf("Unable to execute command: %s", err)
+	}
+	err = session.Wait()
+	if err != nil {
+		t.Fatalf("expected nil but got %s", err)
+	}
+}
+
+// In the wild some clients (and servers) send zero sized window updates. 
+// Test that the server can continue after receiving a zero size update.
+func TestServerZeroWindowAdjust(t *testing.T) {
+	conn := dial(exitStatusZeroHandler, t)
+	defer conn.Close()
+	session, err := conn.NewSession()
+	if err != nil {
+		t.Fatalf("Unable to request new session: %s", err)
+	}
+	defer session.Close()
+
+	if err := session.Shell(); err != nil {
+		t.Fatalf("Unable to execute command: %s", err)
+	}
+
+	// send a bogus zero sized window update
+	session.clientChan.sendWindowAdj(0)
+
+	err = session.Wait()
+	if err != nil {
+		t.Fatalf("expected nil but got %s", err)
+	}
+}
+
 type exitStatusMsg struct {
 	PeersId   uint32
 	Request   string
@@ -403,3 +447,12 @@ func sendInvalidRecord(ch *serverChan) {
 
 	ch.serverConn.writePacket(packet)
 }
+
+func sendZeroWindowAdjust(ch *serverChan) {
+	defer ch.Close()
+	// send a bogus zero sized window update
+	ch.sendWindowAdj(0)
+	shell := newServerShell(ch, "> ")
+	shell.ReadLine()
+	sendStatus(0, ch)
+}