@@ -48,14 +48,25 @@ static const unsigned char lzop_magic[] = {
48
48
49
49
#define LZO_BLOCK_SIZE (256*1024l)
50
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
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 )
53
55
{
54
56
int l ;
55
57
u8 * parse = input ;
58
+ u8 * end = input + in_len ;
56
59
u8 level = 0 ;
57
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
70
/* read magic: 9 first bits */
60
71
for (l = 0 ; l < 9 ; l ++ ) {
61
72
if (* parse ++ != lzop_magic [l ])
@@ -73,13 +84,24 @@ STATIC inline int INIT parse_header(u8 *input, u8 *skip)
73
84
else
74
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
96
/* skip mode and mtime_low */
77
97
parse += 8 ;
78
98
if (version >= 0x0940 )
79
99
parse += 4 ; /* skip mtime_high */
80
100
81
101
l = * parse ++ ;
82
102
/* don't care about the file name, and skip checksum */
103
+ if (end - parse < l + 4 )
104
+ return 0 ;
83
105
parse += l + 4 ;
84
106
85
107
* skip = parse - input ;
@@ -92,7 +114,8 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
92
114
u8 * output , int * posp ,
93
115
void (* error ) (char * x ))
94
116
{
95
- u8 skip = 0 , r = 0 ;
117
+ u8 r = 0 ;
118
+ int skip = 0 ;
96
119
u32 src_len , dst_len ;
97
120
size_t tmp ;
98
121
u8 * in_buf , * in_buf_save , * out_buf ;
@@ -134,19 +157,25 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
134
157
if (fill )
135
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
161
error ("invalid header" );
139
162
goto exit_2 ;
140
163
}
141
164
in_buf += skip ;
165
+ in_len -= skip ;
142
166
143
167
if (posp )
144
168
* posp = skip ;
145
169
146
170
for (;;) {
147
171
/* read uncompressed block size */
172
+ if (in_len < 4 ) {
173
+ error ("file corrupted" );
174
+ goto exit_2 ;
175
+ }
148
176
dst_len = get_unaligned_be32 (in_buf );
149
177
in_buf += 4 ;
178
+ in_len -= 4 ;
150
179
151
180
/* exit if last block */
152
181
if (dst_len == 0 ) {
@@ -161,10 +190,15 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
161
190
}
162
191
163
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
197
src_len = get_unaligned_be32 (in_buf );
165
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
202
error ("file corrupted" );
169
203
goto exit_2 ;
170
204
}
@@ -196,8 +230,10 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
196
230
if (fill ) {
197
231
in_buf = in_buf_save ;
198
232
fill (in_buf , lzo1x_worst_compress (LZO_BLOCK_SIZE ));
199
- } else
233
+ } else {
200
234
in_buf += src_len ;
235
+ in_len -= src_len ;
236
+ }
201
237
}
202
238
203
239
ret = 0 ;
0 commit comments