From: Tobias Stoeckmann Date: Wed, 18 Mar 2026 17:28:40 +0000 (+0100) Subject: mtree: Fix time value parser truncation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a6f7f1ca0fbff1ccd82c519217a5b313f754f4f;p=thirdparty%2Flibarchive.git mtree: Fix time value parser truncation The supplied nanoseconds of time keyword could be truncated due to casting from int64_t to long (relevant for Windows and x86), resulting in an incorrect value. Since the implementation already caps the value at specific limits for bug compatibility, just use the correct data type for parsing to not make things worse. Signed-off-by: Tobias Stoeckmann --- diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index 4a5a49ca8..f9a33878b 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -1790,12 +1790,16 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, * 123456789.1 represents 123456789 * seconds and 1 nanosecond. */ if (*val == '.') { + int64_t v; + ++val; - ns = (long)mtree_atol(&val, 10); - if (ns < 0) + v = mtree_atol(&val, 10); + if (v < 0) ns = 0; - else if (ns > 999999999) + else if (v > 999999999) ns = 999999999; + else + ns = (long)v; } if (m > my_time_t_max) m = my_time_t_max; diff --git a/libarchive/test/test_read_format_mtree.c b/libarchive/test/test_read_format_mtree.c index b4463298d..dc5b5f1fc 100644 --- a/libarchive/test/test_read_format_mtree.c +++ b/libarchive/test/test_read_format_mtree.c @@ -843,3 +843,38 @@ DEFINE_TEST(test_read_format_mtree_tab) assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } + +DEFINE_TEST(test_read_format_mtree_nano) +{ + static char archive[] = + "#mtree\n" + "a type=file time=1234567890.1000000000000 contents=nonexistent_file\n" + "b type=file time=1234567899.-1000000000000 contents=nonexistent_file\n"; + struct archive_entry *ae; + struct archive *a; + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "a"); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualIntA(a, archive_entry_mtime(ae), 1234567890); + assertEqualIntA(a, archive_entry_mtime_nsec(ae), 999999999); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "b"); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualIntA(a, archive_entry_mtime(ae), 1234567899); + assertEqualIntA(a, archive_entry_mtime_nsec(ae), 0); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(2, archive_file_count(a)); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +}