Skip to content

Commit e0ac989

Browse files
committed
archive/tar: detect out of bounds accesses in PAX records resulting from 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]>
1 parent c9d6f45 commit e0ac989

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

src/archive/tar/strconv.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,27 @@ func parsePAXRecord(s string) (k, v, r string, err error) {
265265
return "", "", s, ErrHeader
266266
}
267267

268+
afterSpace := int64(sp + 1)
269+
beforeLastNewLine := n - 1
270+
// In some cases, "length" was perhaps padded/malformed, and
271+
// trying to index past where the space supposedly is goes past
272+
// the end of the actual record.
273+
// For example:
274+
// "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319"
275+
// ^ ^
276+
// | |
277+
// | afterSpace=35
278+
// |
279+
// beforeLastNewLine=29
280+
// yet indexOf(firstSpace) MUST BE before endOfRecord.
281+
//
282+
// See https://golang.org/issues/40196.
283+
if afterSpace >= beforeLastNewLine {
284+
return "", "", s, ErrHeader
285+
}
286+
268287
// Extract everything between the space and the final newline.
269-
rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
288+
rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:]
270289
if nl != "\n" {
271290
return "", "", s, ErrHeader
272291
}

src/archive/tar/strconv_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,13 @@ func TestParsePAXRecord(t *testing.T) {
368368
{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
369369
{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
370370
{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
371+
{"0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "mtime", "1432668921.098285006", false},
372+
{"06 k=v\n", "06 k=v\n", "", "", false},
373+
{"00006 k=v\n", "00006 k=v\n", "", "", false},
374+
{"000006 k=v\n", "000006 k=v\n", "", "", false},
375+
{"000000 k=v\n", "000000 k=v\n", "", "", false},
376+
{"0 k=v\n", "0 k=v\n", "", "", false},
377+
{"+0000005 x=\n", "+0000005 x=\n", "", "", false},
371378
}
372379

373380
for _, v := range vectors {

0 commit comments

Comments
 (0)