]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
mtree: Fix time value parser truncation 2930/head
authorTobias Stoeckmann <tobias@stoeckmann.org>
Wed, 18 Mar 2026 17:28:40 +0000 (18:28 +0100)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Sat, 9 May 2026 10:21:12 +0000 (12:21 +0200)
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 <tobias@stoeckmann.org>
libarchive/archive_read_support_format_mtree.c
libarchive/test/test_read_format_mtree.c

index 4a5a49ca813635c7113a30595838a4487ebff473..f9a33878be147bb3589163399b2a1eaef9944bbc 100644 (file)
@@ -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;
index b4463298dde289f379e6cf5c35b41758517cd93b..dc5b5f1fc7ac807c2d0d7a359b3ad99584e59272 100644 (file)
@@ -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));
+}