Skip to content

Commit 5a3f81a

Browse files
Larhzutorvalds
authored andcommitted
Decompressors: check input size in decompress_unlzo.c
The code assumes that the input is valid and not truncated. Add checks to avoid reading past the end of the input buffer. Change the type of "skip" from u8 to int to fix a possible integer overflow. Signed-off-by: Lasse Collin <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Alain Knaff <[email protected]> Cc: Albin Tonnerre <[email protected]> Cc: Phillip Lougher <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 8f9b54a commit 5a3f81a

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

lib/decompress_unlzo.c

+41-5
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,25 @@ static const unsigned char lzop_magic[] = {
4848

4949
#define LZO_BLOCK_SIZE (256*1024l)
5050
#define HEADER_HAS_FILTER 0x00000800L
51+
#define HEADER_SIZE_MIN (9 + 7 + 4 + 8 + 1 + 4)
52+
#define HEADER_SIZE_MAX (9 + 7 + 1 + 8 + 8 + 4 + 1 + 255 + 4)
5153

52-
STATIC inline int INIT parse_header(u8 *input, u8 *skip)
54+
STATIC inline int INIT parse_header(u8 *input, int *skip, int in_len)
5355
{
5456
int l;
5557
u8 *parse = input;
58+
u8 *end = input + in_len;
5659
u8 level = 0;
5760
u16 version;
5861

62+
/*
63+
* Check that there's enough input to possibly have a valid header.
64+
* Then it is possible to parse several fields until the minimum
65+
* size may have been used.
66+
*/
67+
if (in_len < HEADER_SIZE_MIN)
68+
return 0;
69+
5970
/* read magic: 9 first bits */
6071
for (l = 0; l < 9; l++) {
6172
if (*parse++ != lzop_magic[l])
@@ -73,13 +84,24 @@ STATIC inline int INIT parse_header(u8 *input, u8 *skip)
7384
else
7485
parse += 4; /* flags */
7586

87+
/*
88+
* At least mode, mtime_low, filename length, and checksum must
89+
* be left to be parsed. If also mtime_high is present, it's OK
90+
* because the next input buffer check is after reading the
91+
* filename length.
92+
*/
93+
if (end - parse < 8 + 1 + 4)
94+
return 0;
95+
7696
/* skip mode and mtime_low */
7797
parse += 8;
7898
if (version >= 0x0940)
7999
parse += 4; /* skip mtime_high */
80100

81101
l = *parse++;
82102
/* don't care about the file name, and skip checksum */
103+
if (end - parse < l + 4)
104+
return 0;
83105
parse += l + 4;
84106

85107
*skip = parse - input;
@@ -92,7 +114,8 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
92114
u8 *output, int *posp,
93115
void (*error) (char *x))
94116
{
95-
u8 skip = 0, r = 0;
117+
u8 r = 0;
118+
int skip = 0;
96119
u32 src_len, dst_len;
97120
size_t tmp;
98121
u8 *in_buf, *in_buf_save, *out_buf;
@@ -134,19 +157,25 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
134157
if (fill)
135158
fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
136159

137-
if (!parse_header(input, &skip)) {
160+
if (!parse_header(input, &skip, in_len)) {
138161
error("invalid header");
139162
goto exit_2;
140163
}
141164
in_buf += skip;
165+
in_len -= skip;
142166

143167
if (posp)
144168
*posp = skip;
145169

146170
for (;;) {
147171
/* read uncompressed block size */
172+
if (in_len < 4) {
173+
error("file corrupted");
174+
goto exit_2;
175+
}
148176
dst_len = get_unaligned_be32(in_buf);
149177
in_buf += 4;
178+
in_len -= 4;
150179

151180
/* exit if last block */
152181
if (dst_len == 0) {
@@ -161,10 +190,15 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
161190
}
162191

163192
/* read compressed block size, and skip block checksum info */
193+
if (in_len < 8) {
194+
error("file corrupted");
195+
goto exit_2;
196+
}
164197
src_len = get_unaligned_be32(in_buf);
165198
in_buf += 8;
199+
in_len -= 8;
166200

167-
if (src_len <= 0 || src_len > dst_len) {
201+
if (src_len <= 0 || src_len > dst_len || src_len > in_len) {
168202
error("file corrupted");
169203
goto exit_2;
170204
}
@@ -196,8 +230,10 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
196230
if (fill) {
197231
in_buf = in_buf_save;
198232
fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
199-
} else
233+
} else {
200234
in_buf += src_len;
235+
in_len -= src_len;
236+
}
201237
}
202238

203239
ret = 0;

0 commit comments

Comments
 (0)