summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuška <martin@matuska.org>2019-05-10 21:53:27 +0200
committerGitHub <noreply@github.com>2019-05-10 21:53:27 +0200
commit6e21b64b0d1a4eabf78f161a705e5b6d45b122ac (patch)
tree7ae4ed5003c9f767f9b51fa155fe2f964fc10804
parent8fdc85b1120c0629b53f52fd5181ae18acdc54cc (diff)
parentd9a8da4d9c89d0048fd46ad62d210ec9ec6e8d9c (diff)
downloadlibarchive-6e21b64b0d1a4eabf78f161a705e5b6d45b122ac.tar.gz
Merge pull request #1196 from antekone/rar5_verify_window_size
RAR5 reader: fix a potential SIGSEGV on 32-bit builds
-rw-r--r--libarchive/archive_read_support_format_rar5.c19
-rw-r--r--libarchive/test/test_read_format_rar5.c3
2 files changed, 19 insertions, 3 deletions
diff --git a/libarchive/archive_read_support_format_rar5.c b/libarchive/archive_read_support_format_rar5.c
index 0b351124..7c24627b 100644
--- a/libarchive/archive_read_support_format_rar5.c
+++ b/libarchive/archive_read_support_format_rar5.c
@@ -1570,7 +1570,7 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
size_t compression_info = 0;
size_t host_os = 0;
size_t name_size = 0;
- uint64_t unpacked_size;
+ uint64_t unpacked_size, window_size;
uint32_t mtime = 0, crc = 0;
int c_method = 0, c_version = 0;
char name_utf8_buf[MAX_NAME_IN_BYTES];
@@ -1652,12 +1652,27 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
c_method = (int) (compression_info >> 7) & 0x7;
c_version = (int) (compression_info & 0x3f);
- rar->cstate.window_size = (rar->file.dir > 0) ?
+ /* RAR5 seems to limit the dictionary size to 64MB. */
+ window_size = (rar->file.dir > 0) ?
0 :
g_unpack_window_size << ((compression_info >> 10) & 15);
rar->cstate.method = c_method;
rar->cstate.version = c_version + 50;
+ /* Check if window_size is a sane value. Also, if the file is not
+ * declared as a directory, disallow window_size == 0. */
+ if(window_size > (64 * 1024 * 1024) ||
+ (rar->file.dir == 0 && window_size == 0))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Declared dictionary size is not supported.");
+ return ARCHIVE_FATAL;
+ }
+
+ /* Values up to 64M should fit into ssize_t on every
+ * architecture. */
+ rar->cstate.window_size = (ssize_t) window_size;
+
rar->file.solid = (compression_info & SOLID) > 0;
rar->file.service = 0;
diff --git a/libarchive/test/test_read_format_rar5.c b/libarchive/test/test_read_format_rar5.c
index d87d8d44..1408f37c 100644
--- a/libarchive/test/test_read_format_rar5.c
+++ b/libarchive/test/test_read_format_rar5.c
@@ -1039,7 +1039,8 @@ DEFINE_TEST(test_read_format_rar5_invalid_dict_reference)
PROLOGUE("test_read_format_rar5_invalid_dict_reference.rar");
- assertA(0 == archive_read_next_header(a, &ae));
+ /* This test should fail on parsing the header. */
+ assertA(archive_read_next_header(a, &ae) != ARCHIVE_OK);
/* This archive is invalid. However, processing it shouldn't cause any
* errors related to buffer underflow when using -fsanitize. */