Make SSH_FXP_STATUS error message optional (#109)

Some SSH implementations do not include an error message in the
SSH_FXP_STATUS response causing an "index out of range" panic.
This commit is contained in:
akupas 2016-06-13 19:24:38 -07:00 committed by Dave Cheney
parent 530345cb99
commit f4e06643a3
2 changed files with 58 additions and 9 deletions

View File

@ -1165,7 +1165,10 @@ func unmarshalStatus(id uint32, data []byte) error {
return &unexpectedIDErr{id, sid} return &unexpectedIDErr{id, sid}
} }
code, data := unmarshalUint32(data) code, data := unmarshalUint32(data)
msg, data := unmarshalString(data) msg, data, err := unmarshalStringSafe(data)
if err != nil {
return err
}
lang, _, _ := unmarshalStringSafe(data) lang, _, _ := unmarshalStringSafe(data)
return &StatusError{ return &StatusError{
Code: code, Code: code,

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"io" "io"
"os" "os"
"reflect"
"testing" "testing"
"github.com/kr/fs" "github.com/kr/fs"
@ -87,13 +88,58 @@ func TestFlags(t *testing.T) {
} }
} }
func TestMissingLangTag(t *testing.T) { func TestUnmarshalStatus(t *testing.T) {
defer func() { requestID := uint32(1)
if r := recover(); r != nil {
t.Fail() id := marshalUint32([]byte{}, requestID)
idCode := marshalUint32(id, ssh_FX_FAILURE)
idCodeMsg := marshalString(idCode, "err msg")
idCodeMsgLang := marshalString(idCodeMsg, "lang tag")
var tests = []struct {
desc string
reqID uint32
status []byte
want error
}{
{
desc: "well-formed status",
reqID: 1,
status: idCodeMsgLang,
want: &StatusError{
Code: ssh_FX_FAILURE,
msg: "err msg",
lang: "lang tag",
},
},
{
desc: "missing error message and language tag",
reqID: 1,
status: idCode,
want: errShortPacket,
},
{
desc: "missing language tag",
reqID: 1,
status: idCodeMsg,
want: &StatusError{
Code: ssh_FX_FAILURE,
msg: "err msg",
},
},
{
desc: "request identifier mismatch",
reqID: 2,
status: idCodeMsgLang,
want: &unexpectedIDErr{2, requestID},
},
}
for _, tt := range tests {
got := unmarshalStatus(tt.reqID, tt.status)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("unmarshalStatus(%v, %v), test %q\n- want: %#v\n- got: %#v",
requestID, tt.status, tt.desc, tt.want, got)
} }
}() }
buf := marshalUint32([]byte{}, 0)
buf = marshalStatus(buf, StatusError{})
_ = unmarshalStatus(0, buf[:len(buf)-4])
} }