diff options
Diffstat (limited to 'lib/lzo/lzo1x_decompress_safe.c')
-rw-r--r-- | lib/lzo/lzo1x_decompress_safe.c | 103 |
1 files changed, 57 insertions, 46 deletions
diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 8563081e8da3..a1c387f6afba 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c | |||
@@ -19,31 +19,21 @@ | |||
19 | #include <linux/lzo.h> | 19 | #include <linux/lzo.h> |
20 | #include "lzodefs.h" | 20 | #include "lzodefs.h" |
21 | 21 | ||
22 | #define HAVE_IP(t, x) \ | 22 | #define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) |
23 | (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ | 23 | #define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) |
24 | (((t + x) >= t) && ((t + x) >= 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 | ||
25 | 27 | ||
26 | #define HAVE_OP(t, x) \ | 28 | /* This MAX_255_COUNT is the maximum number of times we can add 255 to a base |
27 | (((size_t)(op_end - op) >= (size_t)(t + x)) && \ | 29 | * count without overflowing an integer. The multiply will overflow when |
28 | (((t + x) >= t) && ((t + x) >= x))) | 30 | * multiplying 255 by more than MAXINT/255. The sum will overflow earlier |
29 | 31 | * depending on the base count. Since the base count is taken from a u8 | |
30 | #define NEED_IP(t, x) \ | 32 | * and a few bits, it is safe to assume that it will always be lower than |
31 | do { \ | 33 | * or equal to 2*255, thus we can always prevent any overflow by accepting |
32 | if (!HAVE_IP(t, x)) \ | 34 | * two less 255 steps. See Documentation/lzo.txt for more information. |
33 | goto input_overrun; \ | 35 | */ |
34 | } while (0) | 36 | #define MAX_255_COUNT ((((size_t)~0) / 255) - 2) |
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) | ||
47 | 37 | ||
48 | int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | 38 | int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, |
49 | unsigned char *out, size_t *out_len) | 39 | unsigned char *out, size_t *out_len) |
@@ -75,17 +65,24 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | |||
75 | if (t < 16) { | 65 | if (t < 16) { |
76 | if (likely(state == 0)) { | 66 | if (likely(state == 0)) { |
77 | if (unlikely(t == 0)) { | 67 | if (unlikely(t == 0)) { |
68 | size_t offset; | ||
69 | const unsigned char *ip_last = ip; | ||
70 | |||
78 | while (unlikely(*ip == 0)) { | 71 | while (unlikely(*ip == 0)) { |
79 | t += 255; | ||
80 | ip++; | 72 | ip++; |
81 | NEED_IP(1, 0); | 73 | NEED_IP(1); |
82 | } | 74 | } |
83 | t += 15 + *ip++; | 75 | offset = ip - ip_last; |
76 | if (unlikely(offset > MAX_255_COUNT)) | ||
77 | return LZO_E_ERROR; | ||
78 | |||
79 | offset = (offset << 8) - offset; | ||
80 | t += offset + 15 + *ip++; | ||
84 | } | 81 | } |
85 | t += 3; | 82 | t += 3; |
86 | copy_literal_run: | 83 | copy_literal_run: |
87 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | 84 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
88 | if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { | 85 | if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { |
89 | const unsigned char *ie = ip + t; | 86 | const unsigned char *ie = ip + t; |
90 | unsigned char *oe = op + t; | 87 | unsigned char *oe = op + t; |
91 | do { | 88 | do { |
@@ -101,8 +98,8 @@ copy_literal_run: | |||
101 | } else | 98 | } else |
102 | #endif | 99 | #endif |
103 | { | 100 | { |
104 | NEED_OP(t, 0); | 101 | NEED_OP(t); |
105 | NEED_IP(t, 3); | 102 | NEED_IP(t + 3); |
106 | do { | 103 | do { |
107 | *op++ = *ip++; | 104 | *op++ = *ip++; |
108 | } while (--t > 0); | 105 | } while (--t > 0); |
@@ -115,7 +112,7 @@ copy_literal_run: | |||
115 | m_pos -= t >> 2; | 112 | m_pos -= t >> 2; |
116 | m_pos -= *ip++ << 2; | 113 | m_pos -= *ip++ << 2; |
117 | TEST_LB(m_pos); | 114 | TEST_LB(m_pos); |
118 | NEED_OP(2, 0); | 115 | NEED_OP(2); |
119 | op[0] = m_pos[0]; | 116 | op[0] = m_pos[0]; |
120 | op[1] = m_pos[1]; | 117 | op[1] = m_pos[1]; |
121 | op += 2; | 118 | op += 2; |
@@ -136,13 +133,20 @@ copy_literal_run: | |||
136 | } else if (t >= 32) { | 133 | } else if (t >= 32) { |
137 | t = (t & 31) + (3 - 1); | 134 | t = (t & 31) + (3 - 1); |
138 | if (unlikely(t == 2)) { | 135 | if (unlikely(t == 2)) { |
136 | size_t offset; | ||
137 | const unsigned char *ip_last = ip; | ||
138 | |||
139 | while (unlikely(*ip == 0)) { | 139 | while (unlikely(*ip == 0)) { |
140 | t += 255; | ||
141 | ip++; | 140 | ip++; |
142 | NEED_IP(1, 0); | 141 | NEED_IP(1); |
143 | } | 142 | } |
144 | t += 31 + *ip++; | 143 | offset = ip - ip_last; |
145 | NEED_IP(2, 0); | 144 | if (unlikely(offset > MAX_255_COUNT)) |
145 | return LZO_E_ERROR; | ||
146 | |||
147 | offset = (offset << 8) - offset; | ||
148 | t += offset + 31 + *ip++; | ||
149 | NEED_IP(2); | ||
146 | } | 150 | } |
147 | m_pos = op - 1; | 151 | m_pos = op - 1; |
148 | next = get_unaligned_le16(ip); | 152 | next = get_unaligned_le16(ip); |
@@ -154,13 +158,20 @@ copy_literal_run: | |||
154 | m_pos -= (t & 8) << 11; | 158 | m_pos -= (t & 8) << 11; |
155 | t = (t & 7) + (3 - 1); | 159 | t = (t & 7) + (3 - 1); |
156 | if (unlikely(t == 2)) { | 160 | if (unlikely(t == 2)) { |
161 | size_t offset; | ||
162 | const unsigned char *ip_last = ip; | ||
163 | |||
157 | while (unlikely(*ip == 0)) { | 164 | while (unlikely(*ip == 0)) { |
158 | t += 255; | ||
159 | ip++; | 165 | ip++; |
160 | NEED_IP(1, 0); | 166 | NEED_IP(1); |
161 | } | 167 | } |
162 | t += 7 + *ip++; | 168 | offset = ip - ip_last; |
163 | NEED_IP(2, 0); | 169 | if (unlikely(offset > MAX_255_COUNT)) |
170 | return LZO_E_ERROR; | ||
171 | |||
172 | offset = (offset << 8) - offset; | ||
173 | t += offset + 7 + *ip++; | ||
174 | NEED_IP(2); | ||
164 | } | 175 | } |
165 | next = get_unaligned_le16(ip); | 176 | next = get_unaligned_le16(ip); |
166 | ip += 2; | 177 | ip += 2; |
@@ -174,7 +185,7 @@ copy_literal_run: | |||
174 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | 185 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
175 | if (op - m_pos >= 8) { | 186 | if (op - m_pos >= 8) { |
176 | unsigned char *oe = op + t; | 187 | unsigned char *oe = op + t; |
177 | if (likely(HAVE_OP(t, 15))) { | 188 | if (likely(HAVE_OP(t + 15))) { |
178 | do { | 189 | do { |
179 | COPY8(op, m_pos); | 190 | COPY8(op, m_pos); |
180 | op += 8; | 191 | op += 8; |
@@ -184,7 +195,7 @@ copy_literal_run: | |||
184 | m_pos += 8; | 195 | m_pos += 8; |
185 | } while (op < oe); | 196 | } while (op < oe); |
186 | op = oe; | 197 | op = oe; |
187 | if (HAVE_IP(6, 0)) { | 198 | if (HAVE_IP(6)) { |
188 | state = next; | 199 | state = next; |
189 | COPY4(op, ip); | 200 | COPY4(op, ip); |
190 | op += next; | 201 | op += next; |
@@ -192,7 +203,7 @@ copy_literal_run: | |||
192 | continue; | 203 | continue; |
193 | } | 204 | } |
194 | } else { | 205 | } else { |
195 | NEED_OP(t, 0); | 206 | NEED_OP(t); |
196 | do { | 207 | do { |
197 | *op++ = *m_pos++; | 208 | *op++ = *m_pos++; |
198 | } while (op < oe); | 209 | } while (op < oe); |
@@ -201,7 +212,7 @@ copy_literal_run: | |||
201 | #endif | 212 | #endif |
202 | { | 213 | { |
203 | unsigned char *oe = op + t; | 214 | unsigned char *oe = op + t; |
204 | NEED_OP(t, 0); | 215 | NEED_OP(t); |
205 | op[0] = m_pos[0]; | 216 | op[0] = m_pos[0]; |
206 | op[1] = m_pos[1]; | 217 | op[1] = m_pos[1]; |
207 | op += 2; | 218 | op += 2; |
@@ -214,15 +225,15 @@ match_next: | |||
214 | state = next; | 225 | state = next; |
215 | t = next; | 226 | t = next; |
216 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | 227 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
217 | if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { | 228 | if (likely(HAVE_IP(6) && HAVE_OP(4))) { |
218 | COPY4(op, ip); | 229 | COPY4(op, ip); |
219 | op += t; | 230 | op += t; |
220 | ip += t; | 231 | ip += t; |
221 | } else | 232 | } else |
222 | #endif | 233 | #endif |
223 | { | 234 | { |
224 | NEED_IP(t, 3); | 235 | NEED_IP(t + 3); |
225 | NEED_OP(t, 0); | 236 | NEED_OP(t); |
226 | while (t > 0) { | 237 | while (t > 0) { |
227 | *op++ = *ip++; | 238 | *op++ = *ip++; |
228 | t--; | 239 | t--; |