libarchive/test/test_read_file_nonexistent.c \
libarchive/test/test_read_filter_compress.c \
libarchive/test/test_read_filter_grzip.c \
+ libarchive/test/test_read_filter_gzip_recursive.c \
libarchive/test/test_read_filter_lrzip.c \
libarchive/test/test_read_filter_lzop.c \
libarchive/test/test_read_filter_lzop_multiple_parts.c \
libarchive/test/test_rar_multivolume_uncompressed_files.part09.rar.uu \
libarchive/test/test_rar_multivolume_uncompressed_files.part10.rar.uu \
libarchive/test/test_read_filter_grzip.tar.grz.uu \
+ libarchive/test/test_read_filter_gzip_recursive.gz.uu \
libarchive/test/test_read_filter_lrzip.tar.lrz.uu \
libarchive/test/test_read_filter_lzop.tar.lzo.uu \
libarchive/test/test_read_filter_lzop_multiple_parts.tar.lzo.uu \
* number of bytes in header. If pbits is non-NULL, it receives a
* count of bits verified, suitable for use by bidder.
*/
+#define MAX_FILENAME_LENGTH (1024 * 1024L)
+#define MAX_COMMENT_LENGTH (1024 * 1024L)
static ssize_t
peek_at_header(struct archive_read_filter *filter, int *pbits,
#ifdef HAVE_ZLIB_H
#endif
do {
++len;
- if (avail < len)
+ if (avail < len) {
+ if (avail > MAX_FILENAME_LENGTH) {
+ return (0);
+ }
p = __archive_read_filter_ahead(filter,
len, &avail);
+ }
if (p == NULL)
return (0);
} while (p[len - 1] != 0);
if (header_flags & 16) {
do {
++len;
- if (avail < len)
+ if (avail < len) {
+ if (avail > MAX_COMMENT_LENGTH) {
+ return (0);
+ }
p = __archive_read_filter_ahead(filter,
len, &avail);
+ }
if (p == NULL)
return (0);
} while (p[len - 1] != 0);
--- /dev/null
+/*-
+ * Copyright (c) 2003-2024 Tim Kientzle
+ * 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"
+
+DEFINE_TEST(test_read_filter_gzip_recursive)
+{
+ const char *name = "test_read_filter_gzip_recursive.gz";
+ struct archive *a;
+
+ if (!canGzip()) {
+ skipping("gzip not available");
+ return;
+ }
+
+ 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));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_filename(a, name, 200));
+
+ /* Verify that the filter detection worked. */
+ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_GZIP);
+ assertEqualString(archive_filter_name(a, 0), "gzip");
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
--- /dev/null
+From oss-fuzz:
+
+clusterfuzz-testcase-minimized-libarchive_fuzzer-5138261947580416
+
+This is a gzip input that expands to a gzip, etc, in such a way that
+the "filename" field in the nested gzip header ends up being extremely
+large (> 500 MiB). This caused headaches for the gzip filter before I
+implemented a sanity limit on filename and comment sizes.
+
+begin 644 test_read_filter_gzip_recursive.gz
+M'XL(`5`M[_<\`'#_``#_'XL("0!D0`GK_W,)&P!P_P``_Q^+"`@(`%$`"0D<
+M`'#_``#_'XL($?\'_^_W/`!P_P``_Q^+"`D`9$`)Z_]S[AL`</\``/\?BP@(
+M"`!1``D)'`!P_P``_Q^+"!'_!___ZP$)=Q'_!___<PD;`'#_``#_'XL("`@`
+M40`)"1P`</\``/\?BP@1_P?_[_<\`'#_``#_'XL("0!D0`GK_SP`</\``/\?
+MBP@)`&1`">O_<^YC:&$!"7<1_P?__W,)&P!P_P``_Q^+"`@(`%$`"0D<`'#_
+M``#_'XL($?\'_^_W/`!P_P``_Q^+"`D`9$`)Z_\\@</"P\/#P\/#P\/!P\/#
+7P\/#P\/#P\/EP\/#B`$`PT.?"`M=P\,`
+`
+end