Merge pull request #3181 from uchiha-bug-hunter/xar-atou64-overread
(cherry picked from commit 1a778f9c10)
This commit is contained in:
1 parent
5b98234fa4
commit
cc711d6a7f
4 files changed
+52
-9
No files matched your search
@@ -1082,6 +1082,7 @@ libarchive_test_EXTRA_DIST=\
|
||||
libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \
|
||||
libarchive/test/test_read_format_warc.warc.uu \
|
||||
libarchive/test/test_read_format_warc_incomplete.warc.uu \
|
||||
libarchive/test/test_read_format_xar_atou64_overread.xar.uu \
|
||||
libarchive/test/test_read_format_xar_base64_oob.xar.uu \
|
||||
libarchive/test/test_read_format_xar_doublelink.xar.uu \
|
||||
libarchive/test/test_read_format_xar_duplicate_filename_node.xar.uu \
|
||||
|
||||
@@ -1077,16 +1077,14 @@ atou64(const char *p, size_t char_cnt, int base, uint64_t *val)
|
||||
uint64_t l;
|
||||
|
||||
l = 0;
|
||||
if (char_cnt > 0) {
|
||||
int digit;
|
||||
while (char_cnt-- > 0) {
|
||||
int digit = *p++ - '0';
|
||||
|
||||
digit = *p - '0';
|
||||
while (digit >= 0 && digit < base && char_cnt-- > 0) {
|
||||
if (archive_ckd_mul_u64(&l, l, base) ||
|
||||
archive_ckd_add_u64(&l, l, digit))
|
||||
return (ARCHIVE_FATAL);
|
||||
digit = *++p - '0';
|
||||
}
|
||||
if (digit < 0 || digit >= base)
|
||||
break;
|
||||
if (archive_ckd_mul_u64(&l, l, base) ||
|
||||
archive_ckd_add_u64(&l, l, digit))
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
*val = l;
|
||||
|
||||
@@ -1003,3 +1003,40 @@ DEFINE_TEST(test_read_format_xar_base64_oob)
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
||||
|
||||
/*
|
||||
* A numeric TOC field (here <inode>) is parsed by atou64(). Under the
|
||||
* expat backend that function is handed the raw, non-NUL-terminated
|
||||
* character-data buffer (libxml2 masks this by passing a strlen'd copy).
|
||||
* The loop fetched the next digit with *++p before checking the remaining
|
||||
* count, so an all-digit field whose content ends at the parser buffer
|
||||
* read one byte past the supplied range. The parsed value is unchanged;
|
||||
* only the stray read is gone. Build with ASan to catch the over-read.
|
||||
*/
|
||||
DEFINE_TEST(test_read_format_xar_atou64_overread)
|
||||
{
|
||||
const char *reffile = "test_read_format_xar_atou64_overread.xar";
|
||||
struct archive_entry *ae;
|
||||
struct archive *a;
|
||||
int r;
|
||||
|
||||
extract_reference_file(reffile);
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
assertA(0 == archive_read_support_filter_all(a));
|
||||
|
||||
r = archive_read_support_format_xar(a);
|
||||
if (r == ARCHIVE_WARN) {
|
||||
skipping("xar reading not fully supported on this platform");
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
return;
|
||||
}
|
||||
|
||||
assertA(0 == archive_read_open_filename(a, reffile, 10240));
|
||||
|
||||
assertA(0 == archive_read_next_header(a, &ae));
|
||||
assertEqualString("num", archive_entry_pathname(ae));
|
||||
assertEqualInt(1234567890, archive_entry_ino64(ae));
|
||||
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
begin 644 test_read_format_xar_atou64_overread.xar
|
||||
M>&%R(0`<``$`````````AP````````"R`````'C:-8Y+#H,P#$3WG"+RGAKH
|
||||
MCTHF['J"]@"(N%4DXE245O3VS4>L_/0THS'UJYO4E^>W]=)!O:M`L8S>6'EV
|
||||
M<+]=RQ9Z7=`ZS+I0BA8_QAOH82=6UH0.9!.<#(ZU?!QAHDTOOQ?KF"=,N'DK
|
||||
<WK"NF_WA>#JWEXHPFSR`L9%&,:T2IB?^<Y@PE```
|
||||
`
|
||||
end
|
||||
Reference in new issue
Block a user