Merge pull request #3181 from uchiha-bug-hunter/xar-atou64-overread

(cherry picked from commit 1a778f9c10)
This commit is contained in:
Dustin L. Howett authored and Martin Matuska committed 2026-07-26 20:10:15 +02:00
1 parent 5b98234fa4
commit cc711d6a7f
4 files changed
+52 -9

No files matched your search

+1
View File
@@ -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 \
+7 -9
View File
@@ -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;
+37
View File
@@ -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