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
|
From 17f4e83c0f0fc3bacf4b2bbacb01f987bb5aff5f Mon Sep 17 00:00:00 2001
From: Grzegorz Antoniak <ga@anadoxin.org>
Date: Fri, 12 Feb 2021 20:18:31 +0100
Subject: [PATCH] RAR5 reader: fix invalid memory access in some files
RAR5 reader uses several variables to manage the window buffer during
extraction: the buffer itself (`window_buf`), the current size of the
window buffer (`window_size`), and a helper variable (`window_mask`)
that is used to constrain read and write offsets to the window buffer.
Some specially crafted files can force the unpacker to update the
`window_mask` variable to a value that is out of sync with current
buffer size. If the `window_mask` will be bigger than the actual buffer
size, then an invalid access operation can happen (SIGSEGV).
This commit ensures that if the `window_size` and `window_mask` will be
changed, the window buffer will be reallocated to the proper size, so no
invalid memory operation should be possible.
This commit contains a test file from OSSFuzz #30442.
Upstream-Status: Backport [https://git.launchpad.net/ubuntu/+source/libarchive/plain/debian/patches/CVE-2021-36976-2.patch?h=applied/3.4.3-2ubuntu0.1]
CVE: CVE-2021-36976
Signed-off-by: Virendra Thakur <virendra.thakur@kpit.com>
---
Makefile.am | 1 +
libarchive/archive_read_support_format_rar5.c | 27 ++++++++++++++-----
libarchive/test/test_read_format_rar5.c | 17 ++++++++++++
...mat_rar5_window_buf_and_size_desync.rar.uu | 11 ++++++++
4 files changed, 50 insertions(+), 6 deletions(-)
create mode 100644 libarchive/test/test_read_format_rar5_window_buf_and_size_desync.rar.uu
--- a/Makefile.am
+++ b/Makefile.am
@@ -884,6 +884,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_rar5_different_winsize_on_merge.rar.uu \
libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu \
libarchive/test/test_read_format_rar5_decode_number_out_of_bounds_read.rar.uu \
+ libarchive/test/test_read_format_rar5_window_buf_and_size_desync.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 \
--- a/libarchive/archive_read_support_format_rar5.c
+++ b/libarchive/archive_read_support_format_rar5.c
@@ -1730,14 +1730,29 @@ static int process_head_file(struct arch
}
}
- /* If we're currently switching volumes, ignore the new definition of
- * window_size. */
- if(rar->cstate.switch_multivolume == 0) {
- /* Values up to 64M should fit into ssize_t on every
- * architecture. */
- rar->cstate.window_size = (ssize_t) window_size;
+ if(rar->cstate.window_size < (ssize_t) window_size &&
+ rar->cstate.window_buf)
+ {
+ /* If window_buf has been allocated before, reallocate it, so
+ * that its size will match new window_size. */
+
+ uint8_t* new_window_buf =
+ realloc(rar->cstate.window_buf, window_size);
+
+ if(!new_window_buf) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "Not enough memory when trying to realloc the window "
+ "buffer.");
+ return ARCHIVE_FATAL;
+ }
+
+ rar->cstate.window_buf = new_window_buf;
}
+ /* Values up to 64M should fit into ssize_t on every
+ * architecture. */
+ rar->cstate.window_size = (ssize_t) window_size;
+
if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
/* Solid files have to have the same window_size across
whole archive. Remember the window_size parameter
--- a/libarchive/test/test_read_format_rar5.c
+++ b/libarchive/test/test_read_format_rar5.c
@@ -1206,6 +1206,23 @@ DEFINE_TEST(test_read_format_rar5_differ
EPILOGUE();
}
+DEFINE_TEST(test_read_format_rar5_window_buf_and_size_desync)
+{
+ /* oss fuzz 30442 */
+
+ char buf[4096];
+ PROLOGUE("test_read_format_rar5_window_buf_and_size_desync.rar");
+
+ /* Return codes of those calls are ignored, because this sample file
+ * is invalid. However, the unpacker shouldn't produce any SIGSEGV
+ * errors during processing. */
+
+ (void) archive_read_next_header(a, &ae);
+ while(0 < archive_read_data(a, buf, 46)) {}
+
+ EPILOGUE();
+}
+
DEFINE_TEST(test_read_format_rar5_arm_filter_on_window_boundary)
{
char buf[4096];
--- /dev/null
+++ b/libarchive/test/test_read_format_rar5_window_buf_and_size_desync.rar.uu
@@ -0,0 +1,11 @@
+begin 644 test_read_format_rar5_window_buf_and_size_desync.rar
+M4F%R(1H'`0`]/-[E`@$`_P$`1#[Z5P("`PL``BXB"?\`!(@B@0`)6.-AF?_1
+M^0DI&0GG(F%R(0<:)`!3@"KT`P+G(@O_X[\``#&``(?!!0$$[:L``$.M*E)A
+M<B$`O<\>P0";/P1%``A*2DI*2DYQ<6TN9'%*2DI*2DI*``!D<F--``````"Z
+MNC*ZNKJZNFYO=&%I;+JZNKJZNKJZOKJZ.KJZNKJZNKKZU@4%````0$!`0$!`
+M0$!`0$!`0$!`0$#_________/T#`0$!`0$!`-UM`0$!`0$!`0$!`0$!`0$!`
+M0$!`0'!,J+:O!IZ-WN4'@`!3*F0`````````````````````````````````
+M``````````````#T`P)287(A&@<!`%.`*O0#`N<B`_,F@`'[__\``(`4`01S
+J'`/H/O\H@?\D`#O9GIZ>GN<B"_]%``(``&1RGIZ>GIZ>8_^>GE/_``!.
+`
+end
|