aboutsummaryrefslogtreecommitdiffstats
path: root/lib/lzo/lzo1x_decompress_safe.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lzo/lzo1x_decompress_safe.c')
-rw-r--r--lib/lzo/lzo1x_decompress_safe.c103
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
48int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, 38int 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;
86copy_literal_run: 83copy_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--;