Skip to content

Commit

Permalink
archive/tar: detect out of bounds accesses in PAX records resulting f…
Browse files Browse the repository at this point in the history
…rom padded lengths

Handles the case in which padding of a PAX record's length field
violates invariants about the formatting of record, whereby it no
longer matches the prescribed format:

    "%d %s=%s\n", <length>, <keyword>, <value>

as per:

    https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_03

0-padding, and paddings of other sorts weren't handled and we assumed
that only non-padded decimal lengths would be passed in.
Added test cases to ensure that the parsing still proceeds as expected.

The prior crashing repro:

    0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319

exposed the fallacy in the code, that assumed that the length would ALWAYS be a
non-padded decimal length string.

This bug has existed since Go1.1 as per CL 6700047.

Thanks to Josh Bleecher Snyder for fuzzing this package, and thanks to Tom
Thorogood for advocacy, raising parity with GNU Tar, but for providing more test cases.

Fixes #40196

Change-Id: I32e0af4887bc9221481bd9e8a5120a79f177f08c
Reviewed-on: https://go-review.googlesource.com/c/go/+/289629
Trust: Emmanuel Odeke <[email protected]>
Trust: Joe Tsai <[email protected]>
Run-TryBot: Emmanuel Odeke <[email protected]>
TryBot-Result: Go Bot <[email protected]>
Reviewed-by: Joe Tsai <[email protected]>
  • Loading branch information
odeke-em committed Feb 9, 2021
1 parent c9d6f45 commit e0ac989
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 1 deletion.
21 changes: 20 additions & 1 deletion src/archive/tar/strconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,27 @@ func parsePAXRecord(s string) (k, v, r string, err error) {
return "", "", s, ErrHeader
}

afterSpace := int64(sp + 1)
beforeLastNewLine := n - 1
// In some cases, "length" was perhaps padded/malformed, and
// trying to index past where the space supposedly is goes past
// the end of the actual record.
// For example:
// "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319"
// ^ ^
// | |
// | afterSpace=35
// |
// beforeLastNewLine=29
// yet indexOf(firstSpace) MUST BE before endOfRecord.
//
// See https://golang.org/issues/40196.
if afterSpace >= beforeLastNewLine {
return "", "", s, ErrHeader
}

// Extract everything between the space and the final newline.
rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:]
if nl != "\n" {
return "", "", s, ErrHeader
}
Expand Down
7 changes: 7 additions & 0 deletions src/archive/tar/strconv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,13 @@ func TestParsePAXRecord(t *testing.T) {
{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
{"0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "mtime", "1432668921.098285006", false},
{"06 k=v\n", "06 k=v\n", "", "", false},
{"00006 k=v\n", "00006 k=v\n", "", "", false},
{"000006 k=v\n", "000006 k=v\n", "", "", false},
{"000000 k=v\n", "000000 k=v\n", "", "", false},
{"0 k=v\n", "0 k=v\n", "", "", false},
{"+0000005 x=\n", "+0000005 x=\n", "", "", false},
}

for _, v := range vectors {
Expand Down

0 comments on commit e0ac989

Please sign in to comment.