...
 
Commits (7)
libarchive (3.0.4-3+wheezy5+deb7u1) wheezy-security; urgency=high
* CVE-2017-5601: Fix a hheap buffer overflow reported in Secunia SA74169.
(Closes: #853278)
-- Chris Lamb <lamby@debian.org> Tue, 31 Jan 2017 20:38:08 +1300
libarchive (3.0.4-3+wheezy5) wheezy-security; urgency=high
* Non-maintainer upload by the LTS Team.
* Fix CVE-2016-8687: Possible buffer overflow when printing a filename
(Closes: #840936)
* Fix CVE-2016-8688: Avoid out of bounds read when parsing multiple long
lines. (Closes: #840935)
* Fix CVE-2016-8689: Possible heap overflow reading corrupted 7Zip files.
(Closes: #840934)
-- Jonas Meurer <mejo@debian.org> Mon, 17 Oct 2016 21:36:24 +0200
libarchive (3.0.4-3+wheezy4) wheezy-security; urgency=medium
* Non-maintainer upload by the LTS team.
* CVE-2016-5418: Archive Entry with type 1 (hardlink), but has a non-zero
data size file overwrite (Closes: #837714)
-- Emilio Pozuelo Monfort <pochu@debian.org> Sat, 15 Oct 2016 19:48:16 +0200
libarchive (3.0.4-3+wheezy3) wheezy-security; urgency=high
* Non-maintainer upload by the LTS Team.
* Fix CVE-2015-8915, a out of bounds read using malformed cpio archive.
* Fix CVE-2016-7166, a denial of service bug with gzip quine.
-- Jonas Meurer <mejo@debian.org> Sat, 10 Sep 2016 15:20:27 +0200
libarchive (3.0.4-3+wheezy2) wheezy-security; urgency=high
* Non-maintainer upload by the LTS team.
* Build with autoreconf to ensure that all patches and tests are applied
and executed correctly.
* Fix CVE-2015-8917, CVE-2015-8919, CVE-2015-8920, CVE-2015-8921,
CVE-2015-8922, CVE-2015-8923, CVE-2015-8924, CVE-2015-8925,
CVE-2015-8926, CVE-2015-8930, CVE-2015-8931, CVE-2015-8932,
CVE-2015-8933, CVE-2015-8934, CVE-2016-4300, CVE-2016-4302,
CVE-2016-4809, CVE-2016-5844 and one security issue without CVE yet.
(TEMP-0000000-84D11B.patch)
Several vulnerabilities were discovered in libarchive, a library for
reading and writing archives in various formats. An attacker can take
advantage of these flaws to cause a denial-of-service against an
application using the libarchive library (application crash), or
potentially execute arbitrary code with the privileges of the user running
the application.
-- Markus Koschany <apo@debian.org> Thu, 21 Jul 2016 07:23:39 +0200
libarchive (3.0.4-3+wheezy1) wheezy-security; urgency=high
* Fix directory traversal vulnerability in bsdcpio (Closes: #778266)
-- Alessandro Ghedini <ghedo@debian.org> Thu, 05 Mar 2015 11:26:19 +0100
libarchive (3.0.4-3+nmu1) unstable; urgency=medium
* Non-maintainer upload.
* Use integers instead of unsigned longs in disk read/write routines, fixing
a build failure on s390x (closes: #704769).
-- Michael Gilbert <mgilbert@debian.org> Sun, 21 Apr 2013 00:20:35 +0000
libarchive (3.0.4-3) unstable; urgency=low
* Add patch that fixes CVE-2013-0211. (Closes: #703957)
......
......@@ -3,6 +3,7 @@ Priority: optional
Maintainer: Debian Libarchive Maintainers <ah-libarchive@debian.org>
Uploaders: Andreas Henriksson <andreas@fatal.se>, Andres Mejia <amejia@debian.org>
Build-Depends: debhelper (>= 8.1.3~),
dh-autoreconf,
libbz2-dev,
liblzma-dev,
libxml2-dev,
......
From: Jonas Meurer <mejo@debian.org>
Date: Sat, 10 Sep 2016 15:15:50 +0200
Subject: [PATCH] Add a check to archive_read_filter_consume to reject any
attempts to move the file pointer by a negative amount (CVE-2015-8915)
Using a crafted tar file bsdtar can perform an out-of-bounds memory read
which will lead to a SEGFAULT. The issue exists when the executable
skips data in the archive. The amount of data to skip is defined in byte
offset [16-19] If ASLR is disabled, the issue can lead to high CPU load,
and potential CPU exhaustion in single-core hosts.
The issue turned out to be a problem with the cpio reader: Libarchive
identifies the constructed file as a big-endian binary cpio format with
a very large (>2GB) size. An overflow in parsing the size field caused
libarchive to treat this size as a negative value and lead to an attempt
to skip the file position forward by a negative number of bytes.
This patch is backported from upstream fix by Tim Kientzle in
git commit e6c9668f3202215ddb71617b41c19b6f05acf008.
diff -rNu a/libarchive/archive_read.c b/libarchive/archive_read.c
--- a/libarchive/archive_read.c 2012-03-27 04:49:00.000000000 +0200
+++ b/libarchive/archive_read.c 2016-09-10 15:13:29.277327678 +0200
@@ -1196,6 +1196,8 @@
{
int64_t skipped;
+ if (request < 0)
+ return ARCHIVE_FATAL;
if (request == 0)
return 0;
From: Markus Koschany <apo@debian.org>
Date: Sat, 2 Jul 2016 23:05:23 +0200
Subject: CVE-2015-8917
Ignore entries with empty filenames.
Bugs in the rar and cab readers lead to returning entries
with empty filenames. Make bsdtar resistant to this.
Origin: https://github.com/libarchive/libarchive/commit/b2e2abb
---
tar/read.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tar/read.c b/tar/read.c
index 676ea0a..5af3e2c 100644
--- a/tar/read.c
+++ b/tar/read.c
@@ -225,6 +225,12 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
}
if (r == ARCHIVE_FATAL)
break;
+ const char *p = archive_entry_pathname(entry);
+ if (p == NULL || p[0] == '\0') {
+ lafe_warnc(0, "Archive entry has empty or unreadable filename ... skipping.");
+ bsdtar->return_value = 1;
+ continue;
+ }
if (bsdtar->uid >= 0) {
archive_entry_set_uid(entry, bsdtar->uid);
From: Markus Koschany <apo@debian.org>
Date: Sat, 2 Jul 2016 23:20:06 +0200
Subject: CVE-2015-8919
Failed to recognize empty dir name in lha/lzh file. Could expose
invalid read access in bsdtar, heap-buffer-overflow.
Origin: https://github.com/libarchive/libarchive/commit/e8a2e4d
---
libarchive/archive_read_support_format_lha.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c
index a92b072..62f0b45 100644
--- a/libarchive/archive_read_support_format_lha.c
+++ b/libarchive/archive_read_support_format_lha.c
@@ -1229,13 +1229,15 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
archive_string_empty(&lha->filename);
break;
}
+ if (extdheader[0] == '\0')
+ goto invalid;
archive_strncpy(&lha->filename,
(const char *)extdheader, datasize);
break;
case EXT_DIRECTORY:
- if (datasize == 0)
+ if (datasize == 0 || extdheader[0] == '\0')
/* no directory name data. exit this case. */
- break;
+ goto invalid;
archive_strncpy(&lha->dirname,
(const char *)extdheader, datasize);
From: Markus Koschany <apo@debian.org>
Date: Sat, 2 Jul 2016 23:42:44 +0200
Subject: CVE-2015-8920
Buffer underflow parsing 'ar' header.
While pruning trailing text from ar filenames, we did not
check for an empty filename. This results in reading the byte
before the filename on the stack.
Origin: https://github.com/libarchive/libarchive/commit/97f964e
---
libarchive/archive_read_support_format_ar.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/libarchive/archive_read_support_format_ar.c b/libarchive/archive_read_support_format_ar.c
index 9feb547..6b31ac6 100644
--- a/libarchive/archive_read_support_format_ar.c
+++ b/libarchive/archive_read_support_format_ar.c
@@ -177,7 +177,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
archive_set_error(&a->archive, EINVAL,
"Incorrect file header signature");
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
/* Copy filename into work buffer. */
@@ -236,9 +236,15 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
* and are not terminated in '/', so we don't trim anything
* that starts with '/'.)
*/
- if (filename[0] != '/' && *p == '/')
+ if (filename[0] != '/' && p > filename && *p == '/') {
*p = '\0';
+ }
+ if (p < filename) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Found entry with empty filename");
+ return (ARCHIVE_FATAL);
+ }
/*
* '//' is the GNU filename table.
* Later entries can refer to names in this table.
@@ -259,7 +265,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
if (entry_size == 0) {
archive_set_error(&a->archive, EINVAL,
"Invalid string table");
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
if (ar->strtab != NULL) {
archive_set_error(&a->archive, EINVAL,
@@ -308,11 +314,11 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
*/
if (ar->strtab == NULL || number > ar->strtab_size) {
archive_set_error(&a->archive, EINVAL,
- "Can't find long filename for entry");
+ "Can't find long filename for GNU/SVR4 archive entry");
archive_entry_copy_pathname(entry, filename);
/* Parse the time, owner, mode, size fields. */
ar_parse_common_header(ar, entry, h);
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);
@@ -570,7 +576,7 @@ bad_string_table:
"Invalid string table");
free(ar->strtab);
ar->strtab = NULL;
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
static uint64_t
From: Markus Koschany <apo@debian.org>
Date: Sat, 2 Jul 2016 23:47:17 +0200
Subject: CVE-2015-8921
malformed mtree file causes invalid read access.
Origin: https://github.com/libarchive/libarchive/commit/1cbc76f
---
libarchive/archive_entry.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c
index b531c77..5ff2552 100644
--- a/libarchive/archive_entry.c
+++ b/libarchive/archive_entry.c
@@ -1585,19 +1585,22 @@ ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
while (*start == '\t' || *start == ' ' || *start == ',')
start++;
while (*start != '\0') {
+ size_t length;
/* Locate end of token. */
end = start;
while (*end != '\0' && *end != '\t' &&
*end != ' ' && *end != ',')
end++;
for (flag = flags; flag->name != NULL; flag++) {
- if (memcmp(start, flag->name, end - start) == 0) {
+ size_t flag_length = strlen(flag->name);
+ if (length == flag_length
+ && memcmp(start, flag->name, length) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
- } else if (memcmp(start, flag->name + 2, end - start)
- == 0) {
+ } else if (length == flag_length - 2
+ && memcmp(start, flag->name + 2, length) == 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
@@ -1649,19 +1652,22 @@ ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
while (*start == L'\t' || *start == L' ' || *start == L',')
start++;
while (*start != L'\0') {
+ size_t length;
/* Locate end of token. */
end = start;
while (*end != L'\0' && *end != L'\t' &&
*end != L' ' && *end != L',')
end++;
for (flag = flags; flag->wname != NULL; flag++) {
- if (wmemcmp(start, flag->wname, end - start) == 0) {
+ size_t flag_length = wcslen(flag->wname);
+ if (length == flag_length
+ && wmemcmp(start, flag->wname, length) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
- } else if (wmemcmp(start, flag->wname + 2, end - start)
- == 0) {
+ } else if (length == flag_length - 2
+ && wmemcmp(start, flag->wname + 2, length) == 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
From: Markus Koschany <apo@debian.org>
Date: Sun, 17 Jul 2016 20:33:53 +0200
Subject: CVE-2015-8922
Fix segfault on malformed 7z archive
Origin: https://github.com/libarchive/libarchive/commit/d094dc
---
Makefile.am | 3 +
libarchive/archive_read_support_format_7zip.c | 9 +++
libarchive/test/CMakeLists.txt | 1 +
.../test/test_read_format_7zip_malformed.7z.uu | 5 ++
libarchive/test/test_read_format_7zip_malformed.c | 67 ++++++++++++++++++++++
.../test/test_read_format_7zip_malformed2.7z.uu | 5 ++
6 files changed, 90 insertions(+)
create mode 100644 libarchive/test/test_read_format_7zip_malformed.7z.uu
create mode 100644 libarchive/test/test_read_format_7zip_malformed.c
create mode 100644 libarchive/test/test_read_format_7zip_malformed2.7z.uu
diff --git a/Makefile.am b/Makefile.am
index 6ac9a4e..9751abb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -320,6 +320,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_extract.c \
libarchive/test/test_read_file_nonexistent.c \
libarchive/test/test_read_format_7zip.c \
+ libarchive/test/test_read_format_7zip_malformed.c \
libarchive/test/test_read_format_ar.c \
libarchive/test/test_read_format_cab.c \
libarchive/test/test_read_format_cab_filename.c \
@@ -499,6 +500,8 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_7zip_lzma1_2.7z.uu \
libarchive/test/test_read_format_7zip_lzma1_lzma2.7z.uu \
libarchive/test/test_read_format_7zip_lzma2.7z.uu \
+ libarchive/test/test_read_format_7zip_malformed.7z.uu \
+ libarchive/test/test_read_format_7zip_malformed2.7z.uu \
libarchive/test/test_read_format_7zip_ppmd.7z.uu \
libarchive/test/test_read_format_7zip_symbolic_name.7z.uu \
libarchive/test/test_read_format_ar.ar.uu \
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c
index 39a46ed..f918fad 100644
--- a/libarchive/archive_read_support_format_7zip.c
+++ b/libarchive/archive_read_support_format_7zip.c
@@ -1938,7 +1938,16 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
return (-1);
if (1000000 < ci->dataStreamIndex)
return (-1);
+ if (ci->numFolders > 0) {
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ goto failed;
+ }
break;
+ default:
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ goto failed;
}
if ((p = header_bytes(a, 1)) == NULL)
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 06bbf9a..4886d90 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -73,6 +73,7 @@ IF(ENABLE_TEST)
test_read_extract.c
test_read_file_nonexistent.c
test_read_format_7zip.c
+ test_read_format_7zip_malformed.c
test_read_format_ar.c
test_read_format_cab.c
test_read_format_cab_filename.c
diff --git a/libarchive/test/test_read_format_7zip_malformed.7z.uu b/libarchive/test/test_read_format_7zip_malformed.7z.uu
new file mode 100644
index 0000000..179f633
--- /dev/null
+++ b/libarchive/test/test_read_format_7zip_malformed.7z.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_7zip_malformed.7z
+M-WJ\KR<<,#"@P/<&!P````````!(`````````&:^$Y<P,#`P,#`P`00&``$)
+'!P`'"S`P#```
+`
+end
diff --git a/libarchive/test/test_read_format_7zip_malformed.c b/libarchive/test/test_read_format_7zip_malformed.c
new file mode 100644
index 0000000..4ca6f09
--- /dev/null
+++ b/libarchive/test/test_read_format_7zip_malformed.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2011 Michihiro NAKAJIMA
+ * 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$");
+
+static void
+test_malformed1(void)
+{
+ const char *refname = "test_read_format_7zip_malformed.7z";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ extract_reference_file(refname);
+
+ 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_filename(a, refname, 10240));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_malformed2(void)
+{
+ const char *refname = "test_read_format_7zip_malformed2.7z";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ extract_reference_file(refname);
+
+ 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_filename(a, refname, 10240));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_7zip_malformed)
+{
+ test_malformed1();
+ test_malformed2();
+}
diff --git a/libarchive/test/test_read_format_7zip_malformed2.7z.uu b/libarchive/test/test_read_format_7zip_malformed2.7z.uu
new file mode 100644
index 0000000..e629a78
--- /dev/null
+++ b/libarchive/test/test_read_format_7zip_malformed2.7z.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_7zip_malformed2.7z
+M-WJ\KR<<,#"@P/<&!P````````!(`````````&:^$Y<P,#`P,#`P`00&``$)
+(!P`'"S`!#`P`
+`
+end
From: Markus Koschany <apo@debian.org>
Date: Sun, 17 Jul 2016 22:57:58 +0200
Subject: CVE-2015-8923
Fix segfault on malformed 7z archive.
Issue here was reading a size field as a signed number
and then using that as an offset. Fixed by correctly
masking the size value to an unsigned result.
Includes test based on the archive provided in the issue report.
Origin: https://github.com/libarchive/libarchive/commit/9e0689c
---
Makefile.am | 2 +
libarchive/archive_read_support_format_zip.c | 4 +-
libarchive/test/CMakeLists.txt | 1 +
libarchive/test/test_read_format_zip_malformed.c | 61 ++++++++++++++++++++++
.../test/test_read_format_zip_malformed1.zip.uu | 5 ++
5 files changed, 71 insertions(+), 2 deletions(-)
create mode 100644 libarchive/test/test_read_format_zip_malformed.c
create mode 100644 libarchive/test/test_read_format_zip_malformed1.zip.uu
diff --git a/Makefile.am b/Makefile.am
index 9751abb..d09f5e0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -373,6 +373,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_ustar_filename.c \
libarchive/test/test_read_format_xar.c \
libarchive/test/test_read_format_zip.c \
+ libarchive/test/test_read_format_zip_malformed.c \
libarchive/test/test_read_format_zip_filename.c \
libarchive/test/test_read_large.c \
libarchive/test/test_read_pax_truncated.c \
@@ -569,6 +570,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu \
libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \
libarchive/test/test_read_format_zip.zip.uu \
+ libarchive/test/test_read_format_zip_malformed1.zip.uu \
libarchive/test/test_read_format_zip_filename_cp866.zip.uu \
libarchive/test/test_read_format_zip_filename_cp932.zip.uu \
libarchive/test/test_read_format_zip_filename_koi8r.zip.uu \
diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c
index 2055313..ffd0df7 100644
--- a/libarchive/archive_read_support_format_zip.c
+++ b/libarchive/archive_read_support_format_zip.c
@@ -1316,7 +1316,7 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
if (datasize >= 1 && p[offset] == 1) {/* version=1 */
if (datasize >= 4) {
/* get a uid size. */
- uidsize = p[offset+1];
+ uidsize = 0xff & (int)p[offset+1];
if (uidsize == 2)
zip_entry->uid = archive_le16dec(
p + offset + 2);
@@ -1326,7 +1326,7 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
}
if (datasize >= (2 + uidsize + 3)) {
/* get a gid size. */
- gidsize = p[offset+2+uidsize];
+ gidsize = 0xff & (int)p[offset+2+uidsize];
if (gidsize == 2)
zip_entry->gid = archive_le16dec(
p+offset+2+uidsize+1);
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 4886d90..eb154d7 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -127,6 +127,7 @@ IF(ENABLE_TEST)
test_read_format_xar.c
test_read_format_zip.c
test_read_format_zip_filename.c
+ test_read_format_zip_malformed.c
test_read_large.c
test_read_pax_truncated.c
test_read_position.c
diff --git a/libarchive/test/test_read_format_zip_malformed.c b/libarchive/test/test_read_format_zip_malformed.c
new file mode 100644
index 0000000..2327d91
--- /dev/null
+++ b/libarchive/test/test_read_format_zip_malformed.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2011 Michihiro NAKAJIMA
+ * 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$");
+
+static void
+test_malformed1(void)
+{
+ const char *refname = "test_read_format_zip_malformed1.zip";
+ struct archive *a;
+ struct archive_entry *ae;
+ char *p;
+ size_t s;
+
+ extract_reference_file(refname);
+
+ /* Verify with seeking reader. */
+ 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_filename(a, refname, 10240));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+
+ /* Verify with streaming reader. */
+ p = slurpfile(&s, refname);
+ 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, read_open_memory(a, p, s, 31));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_zip_malformed)
+{
+ test_malformed1();
+}
diff --git a/libarchive/test/test_read_format_zip_malformed1.zip.uu b/libarchive/test/test_read_format_zip_malformed1.zip.uu
new file mode 100644
index 0000000..cbd21a8
--- /dev/null
+++ b/libarchive/test/test_read_format_zip_malformed1.zip.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_zip_malformed1.zip
+M4$L#!#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`$`!P`,#`P,#`P"0`P,#`P,#`P
+1,#!U>`L``80P,#`P,#`P,#``
+`
+end
From: Markus Koschany <apo@debian.org>
Date: Sun, 17 Jul 2016 23:27:08 +0200
Subject: CVE-2015-8924
A malformed tar file could cause a heap read overflow.
Origin: https://github.com/libarchive/libarchive/commit/bb9b157
---
libarchive/archive_read_support_format_tar.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index 4538331..1a34fcf 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -441,6 +441,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
static int default_dev;
struct tar *tar;
const char *p;
+ const wchar_t *wp;
int r;
size_t l, unconsumed = 0;
@@ -491,27 +492,22 @@ archive_read_format_tar_read_header(struct archive_read *a,
}
}
- if (r == ARCHIVE_OK) {
+ if (r == ARCHIVE_OK && archive_entry_filetype(entry) == AE_IFREG) {
/*
* "Regular" entry with trailing '/' is really
* directory: This is needed for certain old tar
* variants and even for some broken newer ones.
*/
- const wchar_t *wp;
- wp = archive_entry_pathname_w(entry);
- if (wp != NULL) {
+ if ((wp = archive_entry_pathname_w(entry)) != NULL) {
l = wcslen(wp);
- if (archive_entry_filetype(entry) == AE_IFREG
- && wp[l-1] == L'/')
+ if (l > 0 && wp[l - 1] == L'/') {
archive_entry_set_filetype(entry, AE_IFDIR);
- } else {
- p = archive_entry_pathname(entry);
- if (p == NULL)
- return (ARCHIVE_FAILED);
+ }
+ } else if ((p = archive_entry_pathname(entry)) != NULL) {
l = strlen(p);
- if (archive_entry_filetype(entry) == AE_IFREG
- && p[l-1] == '/')
+ if (l > 0 && p[l - 1] == '/') {
archive_entry_set_filetype(entry, AE_IFDIR);
+ }
}
}
return (r);
From: Markus Koschany <apo@debian.org>
Date: Sun, 17 Jul 2016 23:38:37 +0200
Subject: CVE-2015-8925
Fix invalid read access on malformed mtree file in function read_mtree
Origin: https://github.com/libarchive/libarchive/commit/1e18cbb71
---
libarchive/archive_read_support_format_mtree.c | 56 ++++++++++++-------------
libarchive/test/test_read_format_mtree.c | 6 ++-
libarchive/test/test_read_format_mtree.mtree.uu | 20 +++++----
3 files changed, 43 insertions(+), 39 deletions(-)
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 6fb5762..5d020f7 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -1535,6 +1535,10 @@ parse_escapes(char *src, struct mtree_entry *mentry)
c = '\v';
++src;
break;
+ case '\\':
+ c = '\\';
+ ++src;
+ break;
}
}
*dest++ = c;
@@ -1678,8 +1682,7 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
ssize_t total_size = 0;
ssize_t find_off = 0;
const void *t;
- const char *s;
- void *p;
+ void *nl;
char *u;
/* Accumulate line in a line buffer. */
@@ -1690,11 +1693,10 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
return (0);
if (bytes_read < 0)
return (ARCHIVE_FATAL);
- s = t; /* Start of line? */
- p = memchr(t, '\n', bytes_read);
- /* If we found '\n', trim the read. */
- if (p != NULL) {
- bytes_read = 1 + ((const char *)p) - s;
+ nl = memchr(t, '\n', bytes_read);
+ /* If we found '\n', trim the read to end exactly there. */
+ if (nl != NULL) {
+ bytes_read = ((const char *)nl) - ((const char *)t) + 1;
}
if (total_size + bytes_read + 1 > limit) {
archive_set_error(&a->archive,
@@ -1708,38 +1710,34 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
"Can't allocate working buffer");
return (ARCHIVE_FATAL);
}
+ /* Append new bytes to string. */
memcpy(mtree->line.s + total_size, t, bytes_read);
__archive_read_consume(a, bytes_read);
total_size += bytes_read;
- /* Null terminate. */
mtree->line.s[total_size] = '\0';
- /* If we found an unescaped '\n', clean up and return. */
+
for (u = mtree->line.s + find_off; *u; ++u) {
if (u[0] == '\n') {
+ /* Ends with unescaped newline. */
*start = mtree->line.s;
return total_size;
- }
- if (u[0] == '#') {
- if (p == NULL)
+ } else if (u[0] == '#') {
+ /* Ends with comment sequence #...\n */
+ if (nl == NULL) {
+ /* But we've not found the \n yet */
break;
- *start = mtree->line.s;
- return total_size;
- }
- if (u[0] != '\\')
- continue;
- if (u[1] == '\\') {
- ++u;
- continue;
- }
- if (u[1] == '\n') {
- memmove(u, u + 1,
- total_size - (u - mtree->line.s) + 1);
- --total_size;
- ++u;
- break;
+ }
+ } else if (u[0] == '\\') {
+ if (u[1] == '\n') {
+ /* Trim escaped newline. */
+ total_size -= 2;
+ mtree->line.s[total_size] = '\0';
+ break;
+ } else if (u[1] != '\0') {
+ /* Skip the two-char escape sequence */
+ ++u;
+ }
}
- if (u[1] == '\0')
- break;
}
find_off = u - mtree->line.s;
}
diff --git a/libarchive/test/test_read_format_mtree.c b/libarchive/test/test_read_format_mtree.c
index a5d7feb..ad09bf1 100644
--- a/libarchive/test/test_read_format_mtree.c
+++ b/libarchive/test/test_read_format_mtree.c
@@ -108,6 +108,10 @@ test_read_format_mtree1(void)
assertEqualString(archive_entry_pathname(ae), "dir2/dir3b/indir3b");
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "dir2/dir3b/filename\\with_esc\b\t\fapes");
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString(archive_entry_pathname(ae), "notindir");
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
@@ -149,7 +153,7 @@ test_read_format_mtree1(void)
assertEqualInt(archive_entry_mtime(ae), min_time);
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(19, archive_file_count(a));
+ assertEqualInt(20, archive_file_count(a));
assertEqualInt(ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/libarchive/test/test_read_format_mtree.mtree.uu b/libarchive/test/test_read_format_mtree.mtree.uu
index a0dff18..f1c9d60 100644
--- a/libarchive/test/test_read_format_mtree.mtree.uu
+++ b/libarchive/test/test_read_format_mtree.mtree.uu
@@ -5,14 +5,16 @@ M92!U:60],3@*("XN"F9I;&5<,#0P=VET:%PP-#!S<&%C92!T>7!E/69I;&4*
M9&ER,B!T>7!E/61I<@H@9&ER,V$@='EP93UD:7(*("!I;F1I<C-A('1Y<&4]
M9FEL90ID:7(R+V9U;&QI;F1I<C(@='EP93UF:6QE(&UO9&4],#<W-PH@("XN
M"B!I;F1I<C(@='EP93UF:6QE"B!D:7(S8B!T>7!E/61I<@H@(&EN9&ER,V(@
-M='EP93UF:6QE"B`@+BX*("XN"FYO=&EN9&ER('1Y<&4]9FEL90ID:7(R+V9U
-M;&QI;F1I<C(@;6]D93TP-C0T"F1I<C(O96UP='EF:6QE('1Y<&4]9FEL92!S
-M:7IE/3!X,`ID:7(R+W-M86QL9FEL92!T>7!E/69I;&4@<VEZ93TP,#`P,#`P
-M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#$*9&ER,B]T;V]S;6%L;&9I;&4@='EP
-M93UF:6QE('-I>F4]+3$*9&ER,B]B:6=F:6QE('1Y<&4]9FEL92!S:7IE/3DR
-M,C,S-S(P,S8X-30W-S4X,#<*9&ER,B]T;V]B:6=F:6QE('1Y<&4]9FEL92!S
-M:7IE/3DR,C,S-S(P,S8X-30W-S4X,#@*9&ER,B]V97)Y;VQD9FEL92!T>7!E
-M/69I;&4@=&EM93TM.3(R,S,W,C`S-C@U-#<W-3@P.`ID:7(R+W1O;V]L9&9I
-H;&4@='EP93UF:6QE('1I;64]+3DR,C,S-S(P,S8X-30W-S4X,#D*"@``
+M='EP93UF:6QE"B`@9FEL96YA;65<7'=I=&A<"E]E<V-<8EQT7&9A<&5S('1Y
+M<&4]9FEL92!M;V1E/3`T-#0@<VEZ93TP"B`@+BX*("XN"FYO=&EN9&ER('1Y
+M<&4]9FEL90ID:7(R+V9U;&QI;F1I<C(@;6]D93TP-C0T"F1I<C(O96UP='EF
+M:6QE('1Y<&4]9FEL92!S:7IE/3!X,`ID:7(R+W-M86QL9FEL92!T>7!E/69I
+M;&4@<VEZ93TP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#$*9&ER,B]T
+M;V]S;6%L;&9I;&4@='EP93UF:6QE('-I>F4]+3$*9&ER,B]B:6=F:6QE('1Y
+M<&4]9FEL92!S:7IE/3DR,C,S-S(P,S8X-30W-S4X,#<*9&ER,B]T;V]B:6=F
+M:6QE('1Y<&4]9FEL92!S:7IE/3DR,C,S-S(P,S8X-30W-S4X,#@*9&ER,B]V
+M97)Y;VQD9FEL92!T>7!E/69I;&4@=&EM93TM.3(R,S,W,C`S-C@U-#<W-3@P
+M.`ID:7(R+W1O;V]L9&9I;&4@='EP93UF:6QE('1I;64]+3DR,C,S-S(P,S8X
+*-30W-S4X,#D*"@``
`
end
From: Markus Koschany <apo@debian.org>
Date: Sun, 17 Jul 2016 23:43:04 +0200
Subject: CVE-2015-8926
Segfault when unpacking invalid rar archive with bsdtar.
Origin: https://github.com/libarchive/libarchive/commit/aab73938
---
libarchive/archive_read_support_format_rar.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index 1e5c5fa..ebdd6c4 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -938,8 +938,8 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
rar->bytes_unconsumed = 0;
}
+ *buff = NULL;
if (rar->entry_eof) {
- *buff = NULL;
*size = 0;
*offset = rar->offset;
return (ARCHIVE_EOF);
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 12:03:34 +0200
Subject: CVE-2015-8930
Dir loop in malformed ISO causes segfault.
Origin: https://github.com/libarchive/libarchive/commit/39fc59391b7cf2a007bffce280c1e3e66674258f
Origin: https://github.com/libarchive/libarchive/commit/01cfbca4fdae1492a8a09c001b61bbca46f869f2
---
libarchive/archive_read_support_format_iso9660.c | 43 +++++++++++++++++++-----
1 file changed, 34 insertions(+), 9 deletions(-)
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
index d38c7cf..f0cbd3f 100644
--- a/libarchive/archive_read_support_format_iso9660.c
+++ b/libarchive/archive_read_support_format_iso9660.c
@@ -385,7 +385,7 @@ static int archive_read_format_iso9660_read_data(struct archive_read *,
static int archive_read_format_iso9660_read_data_skip(struct archive_read *);
static int archive_read_format_iso9660_read_header(struct archive_read *,
struct archive_entry *);
-static const char *build_pathname(struct archive_string *, struct file_info *);
+static const char *build_pathname(struct archive_string *, struct file_info *, int);
static int build_pathname_utf16be(unsigned char *, size_t, size_t *,
struct file_info *);
#if DEBUG
@@ -1199,6 +1199,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname is too long");
+ return (ARCHIVE_FATAL);
}
r = archive_entry_copy_pathname_l(entry,
@@ -1221,9 +1222,16 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
rd_r = ARCHIVE_WARN;
}
} else {
- archive_string_empty(&iso9660->pathname);
- archive_entry_set_pathname(entry,
- build_pathname(&iso9660->pathname, file));
+ const char *path = build_pathname(&iso9660->pathname, file, 0);
+ if (path == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname is too long");
+ return (ARCHIVE_FATAL);
+ } else {
+ archive_string_empty(&iso9660->pathname);
+ archive_entry_set_pathname(entry, path);
+ }
}
iso9660->entry_bytes_remaining = file->size;
@@ -1721,12 +1729,12 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
const unsigned char *isodirrec)
{
struct iso9660 *iso9660;
- struct file_info *file;
+ struct file_info *file, *filep;
size_t name_len;
const unsigned char *rr_start, *rr_end;
const unsigned char *p;
size_t dr_len;
- uint64_t fsize;
+ uint64_t fsize, offset;
int32_t location;
int flags;
@@ -1770,6 +1778,16 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
return (NULL);
}
+ /* Sanity check that this entry does not create a cycle. */
+ offset = iso9660->logical_block_size * (uint64_t)location;
+ for (filep = parent; filep != NULL; filep = filep->parent) {
+ if (filep->offset == offset) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Directory structure contains loop");
+ return (NULL);
+ }
+ }
+
/* Create a new file entry and copy data from the ISO dir record. */
file = (struct file_info *)calloc(1, sizeof(*file));
if (file == NULL) {
@@ -1778,7 +1796,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
return (NULL);
}
file->parent = parent;
- file->offset = iso9660->logical_block_size * (uint64_t)location;
+ file->offset = offset;
file->size = fsize;
file->mtime = isodate7(isodirrec + DR_date_offset);
file->ctime = file->atime = file->mtime;
@@ -3168,10 +3186,17 @@ time_from_tm(struct tm *t)
}
static const char *
-build_pathname(struct archive_string *as, struct file_info *file)
+build_pathname(struct archive_string *as, struct file_info *file, int depth)
{
+ // Plain ISO9660 only allows 8 dir levels; if we get
+ // to 1000, then something is very, very wrong.
+ if (depth > 1000) {
+ return NULL;
+ }
if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {
- build_pathname(as, file->parent);
+ if (build_pathname(as, file->parent, depth + 1) == NULL) {
+ return NULL;
+ }
archive_strcat(as, "/");
}
if (archive_strlen(&file->name) == 0)
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 12:33:23 +0200
Subject: CVE-2015-8931
undefined behaviour in archive_read_support_format_mtree.c, signed integer
overflow.
Origin: https://github.com/libarchive/libarchive/commit/b31744df71084a8734f97199e42418f55d08c6c5
Origin: https://github.com/libarchive/libarchive/commit/c0c52e9aaafb0860c4151c5374372051e9354301
---
libarchive/archive_read_support_format_mtree.c | 47 ++++++++++++++------------
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 5d020f7..b6f3cde 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -132,16 +132,22 @@ get_time_t_max(void)
#if defined(TIME_T_MAX)
return TIME_T_MAX;
#else
- static time_t t;
- time_t a;
- if (t == 0) {
- a = 1;
- while (a > t) {
- t = a;
- a = a * 2 + 1;
+ /* ISO C allows time_t to be a floating-point type,
+ but POSIX requires an integer type. The following
+ should work on any system that follows the POSIX
+ conventions. */
+ if (((time_t)0) < ((time_t)-1)) {
+ /* Time_t is unsigned */
+ return (~(time_t)0);
+ } else {
+ /* Time_t is signed. */
+ /* Assume it's the same as int64_t or int32_t */
+ if (sizeof(time_t) == sizeof(int64_t)) {
+ return (time_t)INT64_MAX;
+ } else {
+ return (time_t)INT32_MAX;
}
}
- return t;
#endif
}
@@ -151,20 +157,17 @@ get_time_t_min(void)
#if defined(TIME_T_MIN)
return TIME_T_MIN;
#else
- /* 't' will hold the minimum value, which will be zero (if
- * time_t is unsigned) or -2^n (if time_t is signed). */
- static int computed;
- static time_t t;
- time_t a;
- if (computed == 0) {
- a = (time_t)-1;
- while (a < t) {
- t = a;
- a = a * 2;
- }
- computed = 1;
+ if (((time_t)0) < ((time_t)-1)) {
+ /* Time_t is unsigned */
+ return (time_t)0;
+ } else {
+ /* Time_t is signed. */
+ if (sizeof(time_t) == sizeof(int64_t)) {
+ return (time_t)INT64_MIN;
+ } else {
+ return (time_t)INT32_MIN;
+ }
}
- return t;
#endif
}
@@ -1329,7 +1332,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
int64_t m;
int64_t my_time_t_max = get_time_t_max();
int64_t my_time_t_min = get_time_t_min();
- long ns;
+ long ns = 0;
*parsed_kws |= MTREE_HAS_MTIME;
m = mtree_atol10(&val);
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 13:19:08 +0200
Subject: CVE-2015-8932
Undefined behaviour (invalid left shift) was discovered in libarchive,
in how Compress streams are identified. This could cause certain
files to be mistakenly identified as Compress archives and fail to read.
Origin: https://github.com/libarchive/libarchive/commit/f0b1dbbc325a2d922015eee402b72edd422cb9ea
Origin: https://github.com/libarchive/libarchive/commit/55ce98e829eda3a4356c2be64a778d8740c2cf6c
Origin: https://github.com/libarchive/libarchive/commit/618618c8a6be453f79e0bdbdeab6e1dd8bf429b3
---
Makefile.am | 1 +
libarchive/archive_read_support_filter_compress.c | 21 ++++--
libarchive/test/CMakeLists.txt | 1 +
libarchive/test/test_read_filter_compress.c | 80 +++++++++++++++++++++++
4 files changed, 97 insertions(+), 6 deletions(-)
create mode 100644 libarchive/test/test_read_filter_compress.c
diff --git a/Makefile.am b/Makefile.am
index d09f5e0..a3b0b96 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -319,6 +319,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_disk_entry_from_file.c \
libarchive/test/test_read_extract.c \
libarchive/test/test_read_file_nonexistent.c \
+ libarchive/test/test_read_filter_compress.c \
libarchive/test/test_read_format_7zip.c \
libarchive/test/test_read_format_7zip_malformed.c \
libarchive/test/test_read_format_ar.c \
diff --git a/libarchive/archive_read_support_filter_compress.c b/libarchive/archive_read_support_filter_compress.c
index 1b85300..f17af15 100644
--- a/libarchive/archive_read_support_filter_compress.c
+++ b/libarchive/archive_read_support_filter_compress.c
@@ -184,19 +184,22 @@ compress_bidder_bid(struct archive_read_filter_bidder *self,
(void)self; /* UNUSED */
- buffer = __archive_read_filter_ahead(filter, 2, &avail);
+ /* Shortest valid compress file is 3 bytes. */
+ buffer = __archive_read_filter_ahead(filter, 3, &avail);
if (buffer == NULL)
return (0);
bits_checked = 0;
+ /* First two bytes are the magic value */
if (buffer[0] != 0x1F || buffer[1] != 0x9D)
return (0);
- bits_checked += 16;
-
- /*
- * TODO: Verify more.
- */
+ /* Third byte holds compression parameters. */
+ if (buffer[2] & 0x20) /* Reserved bit, must be zero. */
+ return (0);
+ if (buffer[2] & 0x40) /* Reserved bit, must be zero. */
+ return (0);
+ bits_checked += 18;
return (bits_checked);
}
@@ -238,7 +241,13 @@ compress_bidder_init(struct archive_read_filter *self)
(void)getbits(self, 8); /* Skip first signature byte. */
(void)getbits(self, 8); /* Skip second signature byte. */
+ /* Get compression parameters. */
code = getbits(self, 8);
+ if ((code & 0x1f) > 16) {
+ archive_set_error(&self->archive->archive, -1,
+ "Invalid compressed data");
+ return (ARCHIVE_FATAL);
+ }
state->maxcode_bits = code & 0x1f;
state->maxcode = (1 << state->maxcode_bits);
state->use_reset_code = code & 0x80;
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index eb154d7..6081575 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -72,6 +72,7 @@ IF(ENABLE_TEST)
test_read_disk_entry_from_file.c
test_read_extract.c
test_read_file_nonexistent.c
+ test_read_filter_compress.c
test_read_format_7zip.c
test_read_format_7zip_malformed.c
test_read_format_ar.c
diff --git a/libarchive/test/test_read_filter_compress.c b/libarchive/test/test_read_filter_compress.c
new file mode 100644
index 0000000..03a1d5f
--- /dev/null
+++ b/libarchive/test/test_read_filter_compress.c
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2003-2008 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_compress_truncated)
+{
+ const char data[] = {0x1f, 0x9d};
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_compress(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_memory(a, data, sizeof(data)));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+
+DEFINE_TEST(test_read_filter_compress_empty2)
+{
+ const char data[] = {0x1f, 0x9d, 0x10};
+ struct archive *a;
+ struct archive_entry *ae;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_compress(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, data, sizeof(data)));
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify that the format detection worked. */
+ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
+ assertEqualString(archive_filter_name(a, 0), "compress (.Z)");
+ assertEqualInt(archive_format(a), ARCHIVE_FORMAT_EMPTY);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+
+DEFINE_TEST(test_read_filter_compress_invalid)
+{
+ const char data[] = {0x1f, 0x9d, 0x11};
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_compress(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_memory(a, data, sizeof(data)));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 20:05:18 +0200
Subject: CVE-2015-8933
Reject sparse blocks with negative size or offset.
Origin: https://github.com/libarchive/libarchive/commit/3c7a6dc6694d9b26400d2bd672e04d09ed8a4276
---
libarchive/archive_read_support_format_tar.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index 1a34fcf..b7f428d 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -2072,6 +2072,10 @@ gnu_add_sparse_entry(struct archive_read *a, struct tar *tar,
else
tar->sparse_list = p;
tar->sparse_last = p;
+ if (remaining < 0 || offset < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data");
+ return (ARCHIVE_FATAL);
+ }
p->offset = offset;
p->remaining = remaining;
return (ARCHIVE_OK);
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 20:19:56 +0200
Subject: CVE-2015-8934
Properly check reading from lzss decompression buffer.
Prior code could be tricked into trying to copy data
from beyond the end of the internal decompression buffer.
Origin: https://github.com/libarchive/libarchive/commit/603454ec03040c29bd051fcc749e3c1433c11a8e
---
Makefile.am | 1 +
libarchive/archive_read_support_format_rar.c | 12 ++++--
libarchive/test/CMakeLists.txt | 1 +
libarchive/test/test_read_format_rar_invalid1.c | 44 ++++++++++++++++++++++
.../test/test_read_format_rar_invalid1.rar.uu | 5 +++
5 files changed, 59 insertions(+), 4 deletions(-)
create mode 100644 libarchive/test/test_read_format_rar_invalid1.c
create mode 100644 libarchive/test/test_read_format_rar_invalid1.rar.uu
diff --git a/Makefile.am b/Makefile.am
index a3b0b96..19896a6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -362,6 +362,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_mtree.c \
libarchive/test/test_read_format_pax_bz2.c \
libarchive/test/test_read_format_rar.c \
+ libarchive/test/test_read_format_rar_invalid1.c \
libarchive/test/test_read_format_raw.c \
libarchive/test/test_read_format_tar.c \
libarchive/test/test_read_format_tar_empty_filename.c \
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index ebdd6c4..9d009e8 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -2559,11 +2559,10 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
}
windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
- if(windowoffs + length <= lzss_size(&rar->lzss))
+ if(windowoffs + length <= lzss_size(&rar->lzss)) {
memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
length);
- else
- {
+ } else if (length <= lzss_size(&rar->lzss)) {
firstpart = lzss_size(&rar->lzss) - windowoffs;
if (firstpart < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -2575,9 +2574,14 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
&rar->lzss.window[windowoffs], firstpart);
memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
&rar->lzss.window[0], length - firstpart);
- } else
+ } else {
memcpy(&rar->unp_buffer[rar->unp_offset],
&rar->lzss.window[windowoffs], length);
+ }
+ } else {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad RAR file data");
+ return (ARCHIVE_FATAL);
}
rar->unp_offset += length;
if (rar->unp_offset >= rar->unp_buffer_size)
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 6081575..5fec640 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -115,6 +115,7 @@ IF(ENABLE_TEST)
test_read_format_mtree.c
test_read_format_pax_bz2.c
test_read_format_rar.c
+ test_read_format_rar_invalid1.c
test_read_format_raw.c
test_read_format_tar.c
test_read_format_tar_empty_filename.c
diff --git a/libarchive/test/test_read_format_rar_invalid1.c b/libarchive/test/test_read_format_rar_invalid1.c
new file mode 100644
index 0000000..61dea16
--- /dev/null
+++ b/libarchive/test/test_read_format_rar_invalid1.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2003-2016 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"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_read_format_rar_invalid1)
+{
+ const char *refname = "test_read_format_rar_invalid1.rar";
+ struct archive *a;
+ struct archive_entry *ae;
+ char *buff[100];
+
+ extract_reference_file(refname);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, 99));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_read_format_rar_invalid1.rar.uu b/libarchive/test/test_read_format_rar_invalid1.rar.uu
new file mode 100644
index 0000000..2380399
--- /dev/null
+++ b/libarchive/test/test_read_format_rar_invalid1.rar.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_rar_invalid1.rar
+M4F%R(1H'`,^0<P``#0````````"9SG0@D"8`#`````,````#+7,'\(^>B$4=
+2,P0`I($``'1E<W0`P/\````)
+`
+end
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 20:55:21 +0200
Subject: CVE-2016-4300
If a 7-Zip archive declares a ridiculously large number of substreams,
it can overflow an internal counter, leading a subsequent memory
allocation to be too small for the substream data.
Origin: https://github.com/libarchive/libarchive/commit/e79ef306afe332faf22e9b442a2c6b59cb175573
---
libarchive/archive_read_support_format_7zip.c | 35 +++++++++++++++++----------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c
index f918fad..989def2 100644
--- a/libarchive/archive_read_support_format_7zip.c
+++ b/libarchive/archive_read_support_format_7zip.c
@@ -324,6 +324,12 @@ struct _7zip {
char format_name[64];
};
+/* Maximum entry size. This limitation prevents reading intentional
+ * corrupted 7-zip files on assuming there are not so many entries in
+ * the files. */
+#define UMAX_ENTRY ARCHIVE_LITERAL_ULL(100000000)
+
+
static int archive_read_format_7zip_bid(struct archive_read *, int);
static int archive_read_format_7zip_cleanup(struct archive_read *);
static int archive_read_format_7zip_read_data(struct archive_read *,
@@ -1668,7 +1674,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
return (-1);
if (pi->numPackStreams == 0)
return (-1);
- if (1000000 < pi->numPackStreams)
+ if (UMAX_ENTRY < pi->numPackStreams)
return (-1);
/*
@@ -1797,12 +1803,12 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
if (parse_7zip_uint64(
a, &(f->coders[i].numInStreams)) < 0)
return (-1);
- if (1000000 < f->coders[i].numInStreams)
+ if (UMAX_ENTRY < f->coders[i].numInStreams)
return (-1);
if (parse_7zip_uint64(
a, &(f->coders[i].numOutStreams)) < 0)
return (-1);
- if (1000000 < f->coders[i].numOutStreams)
+ if (UMAX_ENTRY < f->coders[i].numOutStreams)
return (-1);
}
@@ -1842,11 +1848,11 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
for (i = 0; i < f->numBindPairs; i++) {
if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
return (-1);
- if (1000000 < f->bindPairs[i].inIndex)
+ if (UMAX_ENTRY < f->bindPairs[i].inIndex)
return (-1);
if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
return (-1);
- if (1000000 < f->bindPairs[i].outIndex)
+ if (UMAX_ENTRY < f->bindPairs[i].outIndex)
return (-1);
}
@@ -1872,7 +1878,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
for (i = 0; i < f->numPackedStreams; i++) {
if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
return (-1);
- if (1000000 < f->packedStreams[i])
+ if (UMAX_ENTRY < f->packedStreams[i])
return (-1);
}
}
@@ -1914,8 +1920,8 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
*/
if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
goto failed;
- if (1000000 < ci->numFolders)
- return (-1);
+ if (UMAX_ENTRY < ci->numFolders)
+ return (-1);
/*
* Read External.
@@ -1936,7 +1942,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
case 1:
if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
return (-1);
- if (1000000 < ci->dataStreamIndex)
+ if (UMAX_ENTRY < ci->dataStreamIndex)
return (-1);
if (ci->numFolders > 0) {
archive_set_error(&a->archive, -1,
@@ -2050,8 +2056,11 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
for (i = 0; i < numFolders; i++) {
if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
return (-1);
- if (1000000 < f[i].numUnpackStreams)
+ if (UMAX_ENTRY < f[i].numUnpackStreams)
return (-1);
+ if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
+ return (-1);
+ }
unpack_streams += (size_t)f[i].numUnpackStreams;
}
if ((p = header_bytes(a, 1)) == NULL)
@@ -2299,8 +2308,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
return (-1);
- if (1000000 < zip->numFiles)
- return (-1);
+ if (UMAX_ENTRY < zip->numFiles)
+ return (-1);
zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
if (zip->entries == NULL)
@@ -2598,7 +2607,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
if (*p) {
if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
goto failed;
- if (1000000 < h->dataIndex)
+ if (UMAX_ENTRY < h->dataIndex)
goto failed;
}
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 21:08:52 +0200
Subject: CVE-2016-4302
A RAR file with an invalid zero dictionary size was not being
rejected, leading to a zero-sized allocation for the dictionary
storage which was then overwritten during the dictionary initialization.
Origin: https://github.com/libarchive/libarchive/commit/05caadc7eedbef471ac9610809ba683f0c698700
---
libarchive/archive_read_support_format_rar.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index 9d009e8..6b91ffc 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -1816,6 +1816,12 @@ parse_codes(struct archive_read *a)
rar->range_dec.Stream = &rar->bytein;
__archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
+ if (rar->dictionary_size == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid zero dictionary size");
+ return (ARCHIVE_FATAL);
+ }
+
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
rar->dictionary_size, &g_szalloc))
{
From: Markus Koschany <apo@debian.org>
Date: Wed, 20 Jul 2016 21:35:28 +0200
Subject: CVE-2016-4809
Reject cpio symlinks that exceed 1MB which could lead to memory allocate error.
Origin: https://github.com/libarchive/libarchive/commit/fd7e0c02e272913a0a8b6d492c7260dfca0b1408
---
libarchive/archive_read_support_format_cpio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c
index ff29e1f..95f0f0e 100644
--- a/libarchive/archive_read_support_format_cpio.c
+++ b/libarchive/archive_read_support_format_cpio.c
@@ -398,6 +398,11 @@ archive_read_format_cpio_read_header(struct archive_read *a,
/* If this is a symlink, read the link contents. */
if (archive_entry_filetype(entry) == AE_IFLNK) {
+ if (cpio->entry_bytes_remaining > 1024 * 1024) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Rejecting malformed cpio archive: symlink contents exceed 1 megabyte");
+ return (ARCHIVE_FATAL);
+ }
h = __archive_read_ahead(a,
(size_t)cpio->entry_bytes_remaining, NULL);
if (h == NULL)
From 50952acd22df3326c49771f5e5ba48630899468c Mon Sep 17 00:00:00 2001
From: Tim Kientzle <kientzle@acm.org>
Date: Sun, 11 Sep 2016 13:19:05 -0700
Subject: [PATCH] Fix the test cases for Issue #745 and Issue #746
Thanks to Doran Moppert for pointing out the inconsistencies here.
---
libarchive/test/test_write_disk_secure745.c | 5 ++++-
libarchive/test/test_write_disk_secure746.c | 16 ++++++++++------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/libarchive/test/test_write_disk_secure745.c b/libarchive/test/test_write_disk_secure745.c
index fa6939b..870b064 100644
--- a/libarchive/test/test_write_disk_secure745.c
+++ b/libarchive/test/test_write_disk_secure745.c
@@ -58,7 +58,7 @@ DEFINE_TEST(test_write_disk_secure745)
/* Create a symlink pointing to the target directory */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "sym");
- archive_entry_set_mode(ae, S_IFREG | 0777);
+ archive_entry_set_mode(ae, AE_IFLNK | 0777);
archive_entry_copy_symlink(ae, "../target");
assert(0 == archive_write_header(a, ae));
archive_entry_free(ae);
@@ -72,5 +72,8 @@ DEFINE_TEST(test_write_disk_secure745)
/* Permission of target dir should not have changed. */
assertFileMode("../target", 0700);
+
+ assert(0 == archive_write_close(a));
+ archive_write_free(a);
#endif
}
diff --git a/libarchive/test/test_write_disk_secure746.c b/libarchive/test/test_write_disk_secure746.c
index 0daf1b0..460aafe 100644
--- a/libarchive/test/test_write_disk_secure746.c
+++ b/libarchive/test/test_write_disk_secure746.c
@@ -63,11 +63,11 @@ DEFINE_TEST(test_write_disk_secure746a)
/* Attempt to hardlink to the target directory. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "bar");
- archive_entry_set_mode(ae, S_IFREG | 0777);
+ archive_entry_set_mode(ae, AE_IFREG | 0777);
archive_entry_set_size(ae, 8);
archive_entry_copy_hardlink(ae, "../target/foo");
assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
- assertEqualInt(ARCHIVE_FAILED, archive_write_data(a, "modified", 8));
+ assertEqualInt(ARCHIVE_FATAL, archive_write_data(a, "modified", 8));
archive_entry_free(ae);
/* Verify that target file contents are unchanged. */
@@ -105,21 +105,25 @@ DEFINE_TEST(test_write_disk_secure746b)
/* Create a symlink to the target directory. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "symlink");
+ archive_entry_set_mode(ae, AE_IFLNK | 0777);
archive_entry_copy_symlink(ae, "../target");
- assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);
/* Attempt to hardlink to the target directory via the symlink. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "bar");
- archive_entry_set_mode(ae, S_IFREG | 0777);
+ archive_entry_set_mode(ae, AE_IFREG | 0777);
archive_entry_set_size(ae, 8);
archive_entry_copy_hardlink(ae, "symlink/foo");
- assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
- assertEqualInt(ARCHIVE_FAILED, archive_write_data(a, "modified", 8));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_write_data(a, "modified", 8));
archive_entry_free(ae);
/* Verify that target file contents are unchanged. */
assertTextFileContents("unmodified", "../target/foo");
+
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a));
+ archive_write_free(a);
#endif
}
--
2.9.3