Skip to content

Commit bbb00e3

Browse files
committed
sftpd: bound the SCP protocol record length
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
1 parent d2fc01a commit bbb00e3

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

internal/sftpd/internal_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,43 @@ func TestSCPInvalidEndDir(t *testing.T) {
891891
assert.EqualError(t, err, "unacceptable end dir command")
892892
}
893893

894+
func TestSCPMessageSizeLimit(t *testing.T) {
895+
stdErrBuf := make([]byte, 65535)
896+
connection := &Connection{
897+
BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, "", "", dataprovider.User{
898+
BaseUser: sdk.BaseUser{
899+
HomeDir: os.TempDir(),
900+
},
901+
}),
902+
}
903+
scpCommand := scpCommand{
904+
sshCommand: sshCommand{
905+
command: "scp",
906+
connection: connection,
907+
args: []string{"-t", "/tmp"},
908+
},
909+
}
910+
911+
protocolMsg := bytes.Repeat([]byte("A"), maxSCPMessageSize+1)
912+
connection.channel = &MockChannel{
913+
Buffer: bytes.NewBuffer(protocolMsg),
914+
StdErrBuffer: bytes.NewBuffer(stdErrBuf),
915+
}
916+
_, err := scpCommand.readProtocolMessage()
917+
assert.ErrorContains(t, err, "scp protocol message too long")
918+
919+
confirmationMsg := append([]byte{warnMsg[0]}, bytes.Repeat([]byte("A"), maxSCPMessageSize+1)...)
920+
connection.channel = &MockChannel{
921+
Buffer: bytes.NewBuffer(confirmationMsg),
922+
StdErrBuffer: bytes.NewBuffer(stdErrBuf),
923+
}
924+
err = scpCommand.readConfirmationMessage()
925+
assert.ErrorContains(t, err, "scp error message too long")
926+
927+
assert.Len(t, common.Connections.GetStats(""), 0)
928+
assert.Equal(t, int32(0), common.Connections.GetTotalTransfers())
929+
}
930+
894931
func TestSCPParseUploadMessage(t *testing.T) {
895932
buf := make([]byte, 65535)
896933
stdErrBuf := make([]byte, 65535)

internal/sftpd/scp.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import (
3535
"github.com/drakkan/sftpgo/v2/internal/vfs"
3636
)
3737

38+
const maxSCPMessageSize = 8192
39+
3840
var (
3941
okMsg = []byte{0x00}
4042
warnMsg = []byte{0x01} // must be followed by an optional message and a newline
@@ -635,6 +637,10 @@ func (c *scpCommand) readConfirmationMessage() error {
635637
if n > 0 {
636638
msg.Write(readed)
637639
}
640+
if msg.Len() > maxSCPMessageSize {
641+
c.connection.channel.Close()
642+
return fmt.Errorf("scp error message too long, max size %d bytes", maxSCPMessageSize)
643+
}
638644
}
639645
c.connection.Log(logger.LevelInfo, "scp error message received: %v is error: %v", msg.String(), isError)
640646
err = fmt.Errorf("%v", msg.String())
@@ -660,6 +666,10 @@ func (c *scpCommand) readProtocolMessage() (string, error) {
660666
break
661667
}
662668
command.Write(readed)
669+
if command.Len() > maxSCPMessageSize {
670+
err = fmt.Errorf("scp protocol message too long, max size %d bytes", maxSCPMessageSize)
671+
break
672+
}
663673
}
664674
}
665675
if err != nil && !errors.Is(err, io.EOF) {

0 commit comments

Comments
 (0)