summaryrefslogtreecommitdiffstats
path: root/meta/recipes-extended/libarchive/libarchive/0001-RAR5-reader-reject-files-that-declare-invalid-header.patch
blob: a84c1f1f76f8ec32a5b38bf7b88824bd73fc350b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
From c1fe0a8cc8dde8ba3eae3d17e34060d2d6e4eb96 Mon Sep 17 00:00:00 2001
From: Grzegorz Antoniak <ga@anadoxin.org>
Date: Sun, 2 Feb 2020 08:04:41 +0100
Subject: [PATCH] RAR5 reader: reject files that declare invalid header flags

One of the fields in RAR5's base block structure is the size of the
header. Some invalid files declare a 0 header size setting, which can
confuse the unpacker. Minimum header size for RAR5 base blocks is 7
bytes (4 bytes for CRC, and 3 bytes for the rest), so block size of 0
bytes should be rejected at header parsing stage.

The fix adds an error condition if header size of 0 bytes is detected.
In this case, the unpacker will not attempt to unpack the file, as the
header is corrupted.

The commit also adds OSSFuzz #20459 sample to test further regressions
in this area.

Upstream-Status: Backport[https://github.com/libarchive/libarchive/commit/94821008d6eea81e315c5881cdf739202961040a]
CVE: CVE-2020-9308

Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
---
 Makefile.am                                     |  1 +
 libarchive/archive_read_support_format_rar5.c   | 17 +++++++++++++++--
 libarchive/test/test_read_format_rar5.c         | 15 +++++++++++++++
 ...d_format_rar5_block_size_is_too_small.rar.uu |  8 ++++++++
 4 files changed, 39 insertions(+), 2 deletions(-)
 create mode 100644 libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu

diff --git a/Makefile.am b/Makefile.am
index da78b24..01abf20 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -863,6 +863,7 @@ libarchive_test_EXTRA_DIST=\
 	libarchive/test/test_read_format_rar5_symlink.rar.uu \
 	libarchive/test/test_read_format_rar5_truncated_huff.rar.uu \
 	libarchive/test/test_read_format_rar5_win32.rar.uu \
+	libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu \
 	libarchive/test/test_read_format_raw.bufr.uu \
 	libarchive/test/test_read_format_raw.data.gz.uu \
 	libarchive/test/test_read_format_raw.data.Z.uu \
diff --git a/libarchive/archive_read_support_format_rar5.c b/libarchive/archive_read_support_format_rar5.c
index 7c24627..f73393c 100644
--- a/libarchive/archive_read_support_format_rar5.c
+++ b/libarchive/archive_read_support_format_rar5.c
@@ -2034,6 +2034,8 @@ static int scan_for_signature(struct archive_read* a);
 static int process_base_block(struct archive_read* a,
     struct archive_entry* entry)
 {
+	const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;
+
 	struct rar5* rar = get_context(a);
 	uint32_t hdr_crc, computed_crc;
 	size_t raw_hdr_size = 0, hdr_size_len, hdr_size;
@@ -2057,15 +2059,26 @@ static int process_base_block(struct archive_read* a,
 		return ARCHIVE_EOF;
 	}
 
+	hdr_size = raw_hdr_size + hdr_size_len;
+
 	/* Sanity check, maximum header size for RAR5 is 2MB. */
-	if(raw_hdr_size > (2 * 1024 * 1024)) {
+	if(hdr_size > (2 * 1024 * 1024)) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Base block header is too large");
 
 		return ARCHIVE_FATAL;
 	}
 
-	hdr_size = raw_hdr_size + hdr_size_len;
+	/* Additional sanity checks to weed out invalid files. */
+	if(raw_hdr_size == 0 || hdr_size_len == 0 ||
+		hdr_size < SMALLEST_RAR5_BLOCK_SIZE)
+	{
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			"Too small block encountered (%ld bytes)",
+			raw_hdr_size);
+
+		return ARCHIVE_FATAL;
+	}
 
 	/* Read the whole header data into memory, maximum memory use here is
 	 * 2MB. */
diff --git a/libarchive/test/test_read_format_rar5.c b/libarchive/test/test_read_format_rar5.c
index 1408f37..32e7ed8 100644
--- a/libarchive/test/test_read_format_rar5.c
+++ b/libarchive/test/test_read_format_rar5.c
@@ -1194,3 +1194,18 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
 
 	EPILOGUE();
 }
+
+DEFINE_TEST(test_read_format_rar5_block_size_is_too_small)
+{
+	char buf[4096];
+	PROLOGUE("test_read_format_rar5_block_size_is_too_small.rar");
+
+	/* This file is damaged, so those functions should return failure.
+	 * Additionally, SIGSEGV shouldn't be raised during execution
+	 * of those functions. */
+
+	assertA(archive_read_next_header(a, &ae) != ARCHIVE_OK);
+	assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+	EPILOGUE();
+}
diff --git a/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu b/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu
new file mode 100644
index 0000000..5cad219
--- /dev/null
+++ b/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu
@@ -0,0 +1,8 @@
+begin 644 test_read_format_rar5_block_size_is_too_small.rar
+M4F%R(1H'`0"-[P+2``+'(!P,("`@N`,!`B`@("`@("`@("`@("`@("#_("`@
+M("`@("`@("`@((:Q;2!4-'-^4B`!((WO`M(``O\@$/\@-R`@("`@("`@("`@
+M``X@("`@("`@____("`@("`@(/\@("`@("`@("`@("#_(+6U,2"UM;6UM[CU
+M)B`@*(0G(`!.`#D\3R``(/__(,+_````-0#_($&%*/HE=C+N`"```"```"`D
+J`)$#("#_("#__P`@__\@_R#_("`@("`@("#_("#__R`@(/__("#__R`"
+`
+end
-- 
2.23.0