Skip to content

Commit 206a81c

Browse files
committed
lzo: properly check for overruns
The lzo decompressor can, if given some really crazy data, possibly overrun some variable types. Modify the checking logic to properly detect overruns before they happen. Reported-by: "Don A. Bailey" <donb@securitymouse.com> Tested-by: "Don A. Bailey" <donb@securitymouse.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7171511 commit 206a81c

File tree

1 file changed

+41
-21
lines changed

1 file changed

+41
-21
lines changed

Diff for: lib/lzo/lzo1x_decompress_safe.c

+41-21
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,31 @@
1919
#include <linux/lzo.h>
2020
#include "lzodefs.h"
2121

22-
#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x))
23-
#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
24-
#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun
25-
#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
26-
#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
22+
#define HAVE_IP(t, x) \
23+
(((size_t)(ip_end - ip) >= (size_t)(t + x)) && \
24+
(((t + x) >= t) && ((t + x) >= x)))
25+
26+
#define HAVE_OP(t, x) \
27+
(((size_t)(op_end - op) >= (size_t)(t + x)) && \
28+
(((t + x) >= t) && ((t + x) >= x)))
29+
30+
#define NEED_IP(t, x) \
31+
do { \
32+
if (!HAVE_IP(t, x)) \
33+
goto input_overrun; \
34+
} while (0)
35+
36+
#define NEED_OP(t, x) \
37+
do { \
38+
if (!HAVE_OP(t, x)) \
39+
goto output_overrun; \
40+
} while (0)
41+
42+
#define TEST_LB(m_pos) \
43+
do { \
44+
if ((m_pos) < out) \
45+
goto lookbehind_overrun; \
46+
} while (0)
2747

2848
int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
2949
unsigned char *out, size_t *out_len)
@@ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
5878
while (unlikely(*ip == 0)) {
5979
t += 255;
6080
ip++;
61-
NEED_IP(1);
81+
NEED_IP(1, 0);
6282
}
6383
t += 15 + *ip++;
6484
}
6585
t += 3;
6686
copy_literal_run:
6787
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
68-
if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
88+
if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) {
6989
const unsigned char *ie = ip + t;
7090
unsigned char *oe = op + t;
7191
do {
@@ -81,8 +101,8 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
81101
} else
82102
#endif
83103
{
84-
NEED_OP(t);
85-
NEED_IP(t + 3);
104+
NEED_OP(t, 0);
105+
NEED_IP(t, 3);
86106
do {
87107
*op++ = *ip++;
88108
} while (--t > 0);
@@ -95,7 +115,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
95115
m_pos -= t >> 2;
96116
m_pos -= *ip++ << 2;
97117
TEST_LB(m_pos);
98-
NEED_OP(2);
118+
NEED_OP(2, 0);
99119
op[0] = m_pos[0];
100120
op[1] = m_pos[1];
101121
op += 2;
@@ -119,10 +139,10 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
119139
while (unlikely(*ip == 0)) {
120140
t += 255;
121141
ip++;
122-
NEED_IP(1);
142+
NEED_IP(1, 0);
123143
}
124144
t += 31 + *ip++;
125-
NEED_IP(2);
145+
NEED_IP(2, 0);
126146
}
127147
m_pos = op - 1;
128148
next = get_unaligned_le16(ip);
@@ -137,10 +157,10 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
137157
while (unlikely(*ip == 0)) {
138158
t += 255;
139159
ip++;
140-
NEED_IP(1);
160+
NEED_IP(1, 0);
141161
}
142162
t += 7 + *ip++;
143-
NEED_IP(2);
163+
NEED_IP(2, 0);
144164
}
145165
next = get_unaligned_le16(ip);
146166
ip += 2;
@@ -154,7 +174,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
154174
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
155175
if (op - m_pos >= 8) {
156176
unsigned char *oe = op + t;
157-
if (likely(HAVE_OP(t + 15))) {
177+
if (likely(HAVE_OP(t, 15))) {
158178
do {
159179
COPY8(op, m_pos);
160180
op += 8;
@@ -164,15 +184,15 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
164184
m_pos += 8;
165185
} while (op < oe);
166186
op = oe;
167-
if (HAVE_IP(6)) {
187+
if (HAVE_IP(6, 0)) {
168188
state = next;
169189
COPY4(op, ip);
170190
op += next;
171191
ip += next;
172192
continue;
173193
}
174194
} else {
175-
NEED_OP(t);
195+
NEED_OP(t, 0);
176196
do {
177197
*op++ = *m_pos++;
178198
} while (op < oe);
@@ -181,7 +201,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
181201
#endif
182202
{
183203
unsigned char *oe = op + t;
184-
NEED_OP(t);
204+
NEED_OP(t, 0);
185205
op[0] = m_pos[0];
186206
op[1] = m_pos[1];
187207
op += 2;
@@ -194,15 +214,15 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
194214
state = next;
195215
t = next;
196216
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
197-
if (likely(HAVE_IP(6) && HAVE_OP(4))) {
217+
if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) {
198218
COPY4(op, ip);
199219
op += t;
200220
ip += t;
201221
} else
202222
#endif
203223
{
204-
NEED_IP(t + 3);
205-
NEED_OP(t);
224+
NEED_IP(t, 3);
225+
NEED_OP(t, 0);
206226
while (t > 0) {
207227
*op++ = *ip++;
208228
t--;

0 commit comments

Comments
 (0)