]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Validate entry_bytes_remaining in pax_attribute 1753/head
authorBen Wagner <bungeman@chromium.org>
Tue, 19 Jul 2022 17:02:40 +0000 (13:02 -0400)
committerBen Wagner <bungeman@chromium.org>
Sun, 24 Jul 2022 21:02:03 +0000 (17:02 -0400)
The `size` attribute may contain a negative or too large value. Check
the range of the `entry_bytes_remaining` in `pax_attribute` the same way
as `header_common`. The test which is added passes both with and without
this change in a normal debug build. It is necessary to run with
`-fsanitize=undefined` to see that the undefined behavior is avoided.

Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=48467

Makefile.am
libarchive/archive_read_support_format_tar.c
libarchive/test/CMakeLists.txt
libarchive/test/test_read_format_tar_invalid_pax_size.c [new file with mode: 0644]
libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu [new file with mode: 0644]

index 743aaa0db05c5b5a526e05b95d11003d6acc1037..3fd2fdbf6c084678501c19a085d95ca3e8955ba3 100644 (file)
@@ -513,6 +513,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_read_format_tar_empty_filename.c \
        libarchive/test/test_read_format_tar_empty_with_gnulabel.c \
        libarchive/test/test_read_format_tar_filename.c \
+       libarchive/test/test_read_format_tar_invalid_pax_size.c \
        libarchive/test/test_read_format_tbz.c \
        libarchive/test/test_read_format_tgz.c \
        libarchive/test/test_read_format_tlz.c \
@@ -905,6 +906,7 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_read_format_tar_empty_with_gnulabel.tar.uu \
        libarchive/test/test_read_format_tar_empty_pax.tar.Z.uu \
        libarchive/test/test_read_format_tar_filename_koi8r.tar.Z.uu \
+       libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu \
        libarchive/test/test_read_format_ustar_filename_cp866.tar.Z.uu \
        libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu \
        libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \
index bfdad7f873047fab124e8d4e90fae880541b62ac..e31f1cc441451111411870f39e727f0aec9c84a2 100644 (file)
@@ -2108,6 +2108,21 @@ pax_attribute(struct archive_read *a, struct tar *tar,
                        /* "size" is the size of the data in the entry. */
                        tar->entry_bytes_remaining
                            = tar_atol10(value, strlen(value));
+                       if (tar->entry_bytes_remaining < 0) {
+                               tar->entry_bytes_remaining = 0;
+                               archive_set_error(&a->archive,
+                                   ARCHIVE_ERRNO_MISC,
+                                   "Tar size attribute is negative");
+                               return (ARCHIVE_FATAL);
+                       }
+                       if (tar->entry_bytes_remaining == INT64_MAX) {
+                               /* Note: tar_atol returns INT64_MAX on overflow */
+                               tar->entry_bytes_remaining = 0;
+                               archive_set_error(&a->archive,
+                                   ARCHIVE_ERRNO_MISC,
+                                   "Tar size attribute overflow");
+                               return (ARCHIVE_FATAL);
+                       }
                        /*
                         * The "size" pax header keyword always overrides the
                         * "size" field in the tar header.
index 23bcc5bbd1738dfcfa1a320ddadca24a6a53b3f7..bbbff2231afe3973f765a051b61096e5b3e5962b 100644 (file)
@@ -162,6 +162,7 @@ IF(ENABLE_TEST)
     test_read_format_tar_empty_with_gnulabel.c
     test_read_format_tar_empty_pax.c
     test_read_format_tar_filename.c
+    test_read_format_tar_invalid_pax_size.c
     test_read_format_tbz.c
     test_read_format_tgz.c
     test_read_format_tlz.c
diff --git a/libarchive/test/test_read_format_tar_invalid_pax_size.c b/libarchive/test/test_read_format_tar_invalid_pax_size.c
new file mode 100644 (file)
index 0000000..0a03cb6
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2020 Ben Wagner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * The pax size attribute can be used to override the size.
+ * It should be validated the same way the normal size is validated.
+ * The test data is fuzzer output from
+ * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=48467 .
+ */
+DEFINE_TEST(test_read_format_tar_invalid_pax_size)
+{
+       /*
+        * An archive that contains a PAX 'size' record with a large negative value.
+        */
+       struct archive_entry *ae;
+       struct archive *a;
+       const char *refname = "test_read_format_tar_invalid_pax_size.tar";
+
+       extract_reference_file(refname);
+       assert((a = archive_read_new()) != NULL);
+       assertEqualInt(ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
+       /* This assert will pass a normal debug build without the pax size check. */
+       /* Run this test with `-fsanitize=undefined` to verify.                   */
+       assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu b/libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu
new file mode 100644 (file)
index 0000000..71309ea
--- /dev/null
@@ -0,0 +1,38 @@
+begin 644 test_read_format_tar_invalid_pax_size.tar.uu
+M+B]087A(96%D97)S+C$T-#8S+V%A80``````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#`V-#0`,#`P,#`P,``P,#`P,#`P`#`P,#`P,#`P,S$R
+M`#$R-3,Q,30U,S<Q`"`Q,30R,"`@>```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U='-A<@`P,```````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````S,"`@("`@(#T@("`@("`@("`@("`@("`@("`@
+M(`HS,"`@("`@(#T@("`@("`@("`@("`@("`@("`@(`HS,"`@("`@("`]("`@
+M("`@("`@("`@("`@("`@(`HS,"!S:7IE/2TQ.3<V.30Q,3$Q,S8U.3<R-S0S
+M-@H@("`@("`@("`@_R`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@____("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(&%A80``````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#,P.#$V`#`S-S0U,S0`,#`Q,38Q,``P,#`P,#`P,#`P-P`Q,C4S,3$T-3,W
+M,``@,3(P-S$@(#$`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````=7-T87(`,#!D=GEU:V]V````````````````````````````````96YG
+M`````````````````````````/\!````````````````,#`Q`#`P,#`P,#`P
+M,#`P````````````````````````````````````````````````````]P``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+&````````
+`
+end