Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions fuzz/oss-fuzz-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ prepare_teleport_api() {

build_teleport_fuzzers() {

compile_native_go_fuzzer $TELEPORT_PREFIX/lib/srv/desktop/tdp \
FuzzDecode fuzz_decode

compile_native_go_fuzzer $TELEPORT_PREFIX/lib/services \
FuzzParserEvalBoolPredicate fuzz_parser_eval_bool_predicate

Expand Down
17 changes: 11 additions & 6 deletions lib/srv/desktop/tdp/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ func readRawPNG2Frame(firstByte byte, in byteReader) ([]byte, error) {
return nil, trace.Wrap(err)
}

// prevent allocation of giant buffers.
// this also avoids panic for due to overflow.
if pngLength > maxPNGFrameDataLength {
return nil, trace.BadParameter("pngLength too big: %v", pngLength)
}

b := make([]byte, 1+4+pngLength+16)
b[0] = firstByte

Expand Down Expand Up @@ -675,12 +681,8 @@ func (s SharedDirectoryAnnounce) Encode() ([]byte, error) {
}

func decodeSharedDirectoryAnnounce(in io.Reader) (SharedDirectoryAnnounce, error) {
var completionID, directoryID uint32
err := binary.Read(in, binary.BigEndian, &completionID)
if err != nil {
return SharedDirectoryAnnounce{}, trace.Wrap(err)
}
err = binary.Read(in, binary.BigEndian, &directoryID)
var directoryID uint32
err := binary.Read(in, binary.BigEndian, &directoryID)
if err != nil {
return SharedDirectoryAnnounce{}, trace.Wrap(err)
}
Expand Down Expand Up @@ -1418,6 +1420,9 @@ func writeUint64(b *bytes.Buffer, v uint64) {
b.WriteByte(byte(v))
}

// maxPNGFrameDataLength is maximum data length for PNG2Frame
const maxPNGFrameDataLength = 10 * 1024 * 1024 // 10MB

// These correspond to TdpErrCode enum in the rust RDP client.
const (
ErrCodeNil uint32 = 0
Expand Down
44 changes: 44 additions & 0 deletions lib/srv/desktop/tdp/proto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,50 @@ func TestEncodeDecode(t *testing.T) {
}
}

func FuzzDecode(f *testing.F) {
var corpus = []string{
"0",
"\x02",
"\x1b\xff\xff\x800",
"\x1b\xff\xff\xff\xeb",
"\nn\x00\x00\x00\x04 {}",
"\v00000000\x00\x00\x00\x00",
"\nn\x00\x00\x00\x04 { }000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
}

for _, s := range corpus {
f.Add([]byte(s))
}

f.Fuzz(func(t *testing.T, buf []byte) {
require.NotPanics(t, func() {
// decode random buffer
msg, err := Decode(buf)
if err != nil {
return
}

// test that we can encode the message back:
buf2, err := msg.Encode()
require.NoError(t, err)
require.NotNil(t, buf2)

// decode the new buffer. it must be equal to the original msg.
msg2, err := Decode(buf2)
require.NoError(t, err)
require.Equalf(t, msg, msg2, "mismatch for message %v", buf)

// encode another time.
// after encoding, it must match the second buffer identically.
// this isn't the case for the first buffer, as there can be trailing bytes after the message.
buf3, err := msg2.Encode()
require.NoError(t, err)
require.NotNil(t, buf3)
require.Equal(t, buf2, buf3)
})
})
}

func TestBadDecode(t *testing.T) {
// 254 is an unknown message type.
_, err := Decode([]byte{254})
Expand Down