aboutsummaryrefslogtreecommitdiffstats
path: root/lib/decompress_unlzo.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/decompress_unlzo.c')
-rw-r--r--lib/decompress_unlzo.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c
index 855d9d30ec45..7eb3b80bf022 100644
--- a/lib/decompress_unlzo.c
+++ b/lib/decompress_unlzo.c
@@ -48,14 +48,25 @@ static const unsigned char lzop_magic[] = {
48 48
49#define LZO_BLOCK_SIZE (256*1024l) 49#define LZO_BLOCK_SIZE (256*1024l)
50#define HEADER_HAS_FILTER 0x00000800L 50#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)
51 53
52STATIC inline int INIT parse_header(u8 *input, u8 *skip) 54STATIC inline int INIT parse_header(u8 *input, int *skip, int in_len)
53{ 55{
54 int l; 56 int l;
55 u8 *parse = input; 57 u8 *parse = input;
58 u8 *end = input + in_len;
56 u8 level = 0; 59 u8 level = 0;
57 u16 version; 60 u16 version;
58 61
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
59 /* read magic: 9 first bits */ 70 /* read magic: 9 first bits */
60 for (l = 0; l < 9; l++) { 71 for (l = 0; l < 9; l++) {
61 if (*parse++ != lzop_magic[l]) 72 if (*parse++ != lzop_magic[l])
@@ -73,6 +84,15 @@ STATIC inline int INIT parse_header(u8 *input, u8 *skip)
73 else 84 else
74 parse += 4; /* flags */ 85 parse += 4; /* flags */
75 86
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
76 /* skip mode and mtime_low */ 96 /* skip mode and mtime_low */
77 parse += 8; 97 parse += 8;
78 if (version >= 0x0940) 98 if (version >= 0x0940)
@@ -80,6 +100,8 @@ STATIC inline int INIT parse_header(u8 *input, u8 *skip)
80 100
81 l = *parse++; 101 l = *parse++;
82 /* don't care about the file name, and skip checksum */ 102 /* don't care about the file name, and skip checksum */
103 if (end - parse < l + 4)
104 return 0;
83 parse += l + 4; 105 parse += l + 4;
84 106
85 *skip = parse - input; 107 *skip = parse - input;
@@ -92,7 +114,8 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
92 u8 *output, int *posp, 114 u8 *output, int *posp,
93 void (*error) (char *x)) 115 void (*error) (char *x))
94{ 116{
95 u8 skip = 0, r = 0; 117 u8 r = 0;
118 int skip = 0;
96 u32 src_len, dst_len; 119 u32 src_len, dst_len;
97 size_t tmp; 120 size_t tmp;
98 u8 *in_buf, *in_buf_save, *out_buf; 121 u8 *in_buf, *in_buf_save, *out_buf;
@@ -134,19 +157,25 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
134 if (fill) 157 if (fill)
135 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE)); 158 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
136 159
137 if (!parse_header(input, &skip)) { 160 if (!parse_header(input, &skip, in_len)) {
138 error("invalid header"); 161 error("invalid header");
139 goto exit_2; 162 goto exit_2;
140 } 163 }
141 in_buf += skip; 164 in_buf += skip;
165 in_len -= skip;
142 166
143 if (posp) 167 if (posp)
144 *posp = skip; 168 *posp = skip;
145 169
146 for (;;) { 170 for (;;) {
147 /* read uncompressed block size */ 171 /* read uncompressed block size */
172 if (in_len < 4) {
173 error("file corrupted");
174 goto exit_2;
175 }
148 dst_len = get_unaligned_be32(in_buf); 176 dst_len = get_unaligned_be32(in_buf);
149 in_buf += 4; 177 in_buf += 4;
178 in_len -= 4;
150 179
151 /* exit if last block */ 180 /* exit if last block */
152 if (dst_len == 0) { 181 if (dst_len == 0) {
@@ -161,10 +190,15 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
161 } 190 }
162 191
163 /* read compressed block size, and skip block checksum info */ 192 /* read compressed block size, and skip block checksum info */
193 if (in_len < 8) {
194 error("file corrupted");
195 goto exit_2;
196 }
164 src_len = get_unaligned_be32(in_buf); 197 src_len = get_unaligned_be32(in_buf);
165 in_buf += 8; 198 in_buf += 8;
199 in_len -= 8;
166 200
167 if (src_len <= 0 || src_len > dst_len) { 201 if (src_len <= 0 || src_len > dst_len || src_len > in_len) {
168 error("file corrupted"); 202 error("file corrupted");
169 goto exit_2; 203 goto exit_2;
170 } 204 }
@@ -196,8 +230,10 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
196 if (fill) { 230 if (fill) {
197 in_buf = in_buf_save; 231 in_buf = in_buf_save;
198 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE)); 232 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
199 } else 233 } else {
200 in_buf += src_len; 234 in_buf += src_len;
235 in_len -= src_len;
236 }
201 } 237 }
202 238
203 ret = 0; 239 ret = 0;