1 |
From 756b671031e0f6158f82186220ebc087c44cd985 Mon Sep 17 00:00:00 2001 |
2 |
From: Tim Kientzle <kientzle@acm.org> |
3 |
Date: Sat, 10 Jan 2015 12:24:58 -0800 |
4 |
Subject: [PATCH] Fix a potential crash issue discovered by Alexander |
5 |
Cherepanov: |
6 |
|
7 |
It seems bsdtar automatically handles stacked compression. This is a |
8 |
nice feature but it could be problematic when it's completely |
9 |
unlimited. Most clearly it's illustrated with quines: |
10 |
|
11 |
$ curl -sRO http://www.maximumcompression.com/selfgz.gz |
12 |
$ (ulimit -v 10000000 && bsdtar -tvf selfgz.gz) |
13 |
bsdtar: Error opening archive: Can't allocate data for gzip decompression |
14 |
|
15 |
Without ulimit, bsdtar will eat all available memory. This could also |
16 |
be a problem for other applications using libarchive. |
17 |
--- |
18 |
Makefile.am | 2 ++ |
19 |
libarchive/archive_read.c | 7 ++-- |
20 |
libarchive/test/test_read_too_many_filters.c | 45 ++++++++++++++++++++++++ |
21 |
libarchive/test/test_read_too_many_filters.gz.uu | 15 ++++++++ |
22 |
4 files changed, 67 insertions(+), 2 deletions(-) |
23 |
create mode 100644 libarchive/test/test_read_too_many_filters.c |
24 |
create mode 100644 libarchive/test/test_read_too_many_filters.gz.uu |
25 |
|
26 |
diff --git a/Makefile.am b/Makefile.am |
27 |
index 9b0632b..5cfef49 100644 |
28 |
--- a/Makefile.am |
29 |
+++ b/Makefile.am |
30 |
@@ -294,6 +294,7 @@ libarchive_test_SOURCES= \ |
31 |
libarchive/test/test_read_large.c \ |
32 |
libarchive/test/test_read_pax_truncated.c \ |
33 |
libarchive/test/test_read_position.c \ |
34 |
+ libarchive/test/test_read_too_many_filters.c \ |
35 |
libarchive/test/test_read_truncated.c \ |
36 |
libarchive/test/test_read_uu.c \ |
37 |
libarchive/test/test_tar_filenames.c \ |
38 |
@@ -380,6 +381,7 @@ libarchive_test_EXTRA_DIST=\ |
39 |
libarchive/test/test_read_format_raw.data.uu \ |
40 |
libarchive/test/test_read_format_tar_empty_filename.tar.uu \ |
41 |
libarchive/test/test_read_format_zip.zip.uu \ |
42 |
+ libarchive/test/test_read_too_many_filters.gz.uu \ |
43 |
libarchive/test/CMakeLists.txt \ |
44 |
libarchive/test/README |
45 |
|
46 |
diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c |
47 |
index f39f5ce..92d67d9 100644 |
48 |
--- a/libarchive/archive_read.c |
49 |
+++ b/libarchive/archive_read.c |
50 |
@@ -352,13 +352,13 @@ archive_read_open2(struct archive *_a, void *client_data, |
51 |
static int |
52 |
build_stream(struct archive_read *a) |
53 |
{ |
54 |
- int number_bidders, i, bid, best_bid; |
55 |
+ int number_bidders, i, bid, best_bid, n; |
56 |
struct archive_read_filter_bidder *bidder, *best_bidder; |
57 |
struct archive_read_filter *filter; |
58 |
ssize_t avail; |
59 |
int r; |
60 |
|
61 |
- for (;;) { |
62 |
+ for (n = 0; n < 25; ++n) { |
63 |
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); |
64 |
|
65 |
best_bid = 0; |
66 |
@@ -402,6 +402,9 @@ build_stream(struct archive_read *a) |
67 |
return (ARCHIVE_FATAL); |
68 |
} |
69 |
} |
70 |
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, |
71 |
+ "Input requires too many filters for decoding"); |
72 |
+ return (ARCHIVE_FATAL); |
73 |
} |
74 |
|
75 |
/* |
76 |
diff --git a/libarchive/test/test_read_too_many_filters.c b/libarchive/test/test_read_too_many_filters.c |
77 |
new file mode 100644 |
78 |
index 0000000..37cab24 |
79 |
--- /dev/null |
80 |
+++ b/libarchive/test/test_read_too_many_filters.c |
81 |
@@ -0,0 +1,45 @@ |
82 |
+/*- |
83 |
+ * Copyright (c) 2003-2008,2015 Tim Kientzle |
84 |
+ * All rights reserved. |
85 |
+ * |
86 |
+ * Redistribution and use in source and binary forms, with or without |
87 |
+ * modification, are permitted provided that the following conditions |
88 |
+ * are met: |
89 |
+ * 1. Redistributions of source code must retain the above copyright |
90 |
+ * notice, this list of conditions and the following disclaimer. |
91 |
+ * 2. Redistributions in binary form must reproduce the above copyright |
92 |
+ * notice, this list of conditions and the following disclaimer in the |
93 |
+ * documentation and/or other materials provided with the distribution. |
94 |
+ * |
95 |
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR |
96 |
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
97 |
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
98 |
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, |
99 |
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
100 |
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
101 |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
102 |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
103 |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
104 |
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
105 |
+ */ |
106 |
+#include "test.h" |
107 |
+ |
108 |
+DEFINE_TEST(test_read_too_many_filters) |
109 |
+{ |
110 |
+ const char *name = "test_read_too_many_filters.gz"; |
111 |
+ struct archive *a; |
112 |
+ int r; |
113 |
+ |
114 |
+ assert((a = archive_read_new()) != NULL); |
115 |
+ r = archive_read_support_compression_gzip(a); |
116 |
+ if (r == ARCHIVE_WARN) { |
117 |
+ skipping("gzip reading not fully supported on this platform"); |
118 |
+ } |
119 |
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); |
120 |
+ extract_reference_file(name); |
121 |
+ assertEqualIntA(a, ARCHIVE_FATAL, |
122 |
+ archive_read_open_filename(a, name, 200)); |
123 |
+ |
124 |
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); |
125 |
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); |
126 |
+} |
127 |
diff --git a/libarchive/test/test_read_too_many_filters.gz.uu b/libarchive/test/test_read_too_many_filters.gz.uu |
128 |
new file mode 100644 |
129 |
index 0000000..6bf6614 |
130 |
--- /dev/null |
131 |
+++ b/libarchive/test/test_read_too_many_filters.gz.uu |
132 |
@@ -0,0 +1,15 @@ |
133 |
+This is a valid gzip file that decompresses to itself, from |
134 |
+ http://www.maximumcompression.com/selfgz.gz |
135 |
+ |
136 |
+This is used in test_read_too_many_filters to try to |
137 |
+crash libarchive by forcing it to spawn an unending |
138 |
+list of gunzip filters. |
139 |
+ |
140 |
+begin 644 test_read_too_many_filters.gz |
141 |
+M'XL(`````````P`/`/#_'XL(`````````P`/`/#_````__\```#__X)QH5P` |
142 |
+M`!X`X?\```#__P```/__@G&A7```'@#A_P```/__````__\```#__P```/__ |
143 |
+M````__\```#__\(FAF`!`!0`Z_\```#__P```/__PB:&8`$`%`#K_\(FAF`! |
144 |
+M`!0`Z_^9(#6-B"@Q,C,T`K/`+```%`#K_P*SP"P``!0`Z_]"B"'$`````/__ |
145 |
+>`P!#2DTAT@```$*((<0`````__\#`$-*32'2```` |
146 |
+` |
147 |
+end |
148 |
-- |
149 |
2.7.4 |
150 |
|