diff --git a/ssh/session.go b/ssh/session.go index acef622..ac62955 100644 --- a/ssh/session.go +++ b/ssh/session.go @@ -423,6 +423,9 @@ func (s *Session) wait(reqs <-chan *Request) error { for msg := range reqs { switch msg.Type { case "exit-status": + if len(msg.Payload) < 4 { + return errors.New("ssh: malformed exit-status request") + } wm.status = int(binary.BigEndian.Uint32(msg.Payload)) case "exit-signal": var sigval struct { diff --git a/ssh/session_test.go b/ssh/session_test.go index 807a913..a6815bc 100644 --- a/ssh/session_test.go +++ b/ssh/session_test.go @@ -334,6 +334,25 @@ func TestExitWithoutStatusOrSignal(t *testing.T) { } } +func TestExitStatusShortPayload(t *testing.T) { + for _, payload := range [][]byte{nil, {0}, {0, 0}, {0, 0, 0}} { + conn := dial(exitStatusShortPayloadHandler(payload), t) + session, err := conn.NewSession() + if err != nil { + t.Fatalf("unable to request new session: %v", err) + } + if err := session.Shell(); err != nil { + t.Fatalf("unable to execute command: %v", err) + } + err = session.Wait() + if err == nil { + t.Fatalf("expected error for payload length %d", len(payload)) + } + session.Close() + conn.Close() + } +} + // windowTestBytes is the number of bytes that we'll send to the SSH server. const windowTestBytes = 16000 * 200 @@ -482,6 +501,17 @@ func exitWithoutSignalOrStatus(ch Channel, in <-chan *Request, t *testing.T) { readLine(shell, t) } +func exitStatusShortPayloadHandler(payload []byte) serverType { + return func(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + if _, err := ch.SendRequest("exit-status", false, payload); err != nil { + t.Errorf("unable to send status: %v", err) + } + } +} + func shellHandler(ch Channel, in <-chan *Request, t *testing.T) { defer ch.Close() // this string is returned to stdout