1 /* 2 * LZO1X Decompressor from LZO 3 * 4 * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> 5 * 6 * The full LZO package can be found at: 7 * http://www.oberhumer.com/opensource/lzo/ 8 * 9 * Changed for Linux kernel use by: 10 * Nitin Gupta <nitingupta910@gmail.com> 11 * Richard Purdie <rpurdie@openedhand.com> 12 */ 13 14 #ifndef STATIC 15 #include <linux/module.h> 16 #include <linux/kernel.h> 17 #endif 18 #include <asm/unaligned.h> 19 #include <linux/lzo.h> 20 #include "lzodefs.h" 21 22 #define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) 23 #define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(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 27 28 /* This MAX_255_COUNT is the maximum number of times we can add 255 to a base 29 * count without overflowing an integer. The multiply will overflow when 30 * multiplying 255 by more than MAXINT/255. The sum will overflow earlier 31 * depending on the base count. Since the base count is taken from a u8 32 * and a few bits, it is safe to assume that it will always be lower than 33 * or equal to 2*255, thus we can always prevent any overflow by accepting 34 * two less 255 steps. See Documentation/lzo.txt for more information. 35 */ 36 #define MAX_255_COUNT ((((size_t)~0) / 255) - 2) 37 38 int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, 39 unsigned char *out, size_t *out_len) 40 { 41 unsigned char *op; 42 const unsigned char *ip; 43 size_t t, next; 44 size_t state = 0; 45 const unsigned char *m_pos; 46 const unsigned char * const ip_end = in + in_len; 47 unsigned char * const op_end = out + *out_len; 48 49 unsigned char bitstream_version; 50 51 op = out; 52 ip = in; 53 54 if (unlikely(in_len < 3)) 55 goto input_overrun; 56 57 if (likely(*ip == 17)) { 58 bitstream_version = ip[1]; 59 ip += 2; 60 if (unlikely(in_len < 5)) 61 goto input_overrun; 62 } else { 63 bitstream_version = 0; 64 } 65 66 if (*ip > 17) { 67 t = *ip++ - 17; 68 if (t < 4) { 69 next = t; 70 goto match_next; 71 } 72 goto copy_literal_run; 73 } 74 75 for (;;) { 76 t = *ip++; 77 if (t < 16) { 78 if (likely(state == 0)) { 79 if (unlikely(t == 0)) { 80 size_t offset; 81 const unsigned char *ip_last = ip; 82 83 while (unlikely(*ip == 0)) { 84 ip++; 85 NEED_IP(1); 86 } 87 offset = ip - ip_last; 88 if (unlikely(offset > MAX_255_COUNT)) 89 return LZO_E_ERROR; 90 91 offset = (offset << 8) - offset; 92 t += offset + 15 + *ip++; 93 } 94 t += 3; 95 copy_literal_run: 96 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 97 if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { 98 const unsigned char *ie = ip + t; 99 unsigned char *oe = op + t; 100 do { 101 COPY8(op, ip); 102 op += 8; 103 ip += 8; 104 COPY8(op, ip); 105 op += 8; 106 ip += 8; 107 } while (ip < ie); 108 ip = ie; 109 op = oe; 110 } else 111 #endif 112 { 113 NEED_OP(t); 114 NEED_IP(t + 3); 115 do { 116 *op++ = *ip++; 117 } while (--t > 0); 118 } 119 state = 4; 120 continue; 121 } else if (state != 4) { 122 next = t & 3; 123 m_pos = op - 1; 124 m_pos -= t >> 2; 125 m_pos -= *ip++ << 2; 126 TEST_LB(m_pos); 127 NEED_OP(2); 128 op[0] = m_pos[0]; 129 op[1] = m_pos[1]; 130 op += 2; 131 goto match_next; 132 } else { 133 next = t & 3; 134 m_pos = op - (1 + M2_MAX_OFFSET); 135 m_pos -= t >> 2; 136 m_pos -= *ip++ << 2; 137 t = 3; 138 } 139 } else if (t >= 64) { 140 next = t & 3; 141 m_pos = op - 1; 142 m_pos -= (t >> 2) & 7; 143 m_pos -= *ip++ << 3; 144 t = (t >> 5) - 1 + (3 - 1); 145 } else if (t >= 32) { 146 t = (t & 31) + (3 - 1); 147 if (unlikely(t == 2)) { 148 size_t offset; 149 const unsigned char *ip_last = ip; 150 151 while (unlikely(*ip == 0)) { 152 ip++; 153 NEED_IP(1); 154 } 155 offset = ip - ip_last; 156 if (unlikely(offset > MAX_255_COUNT)) 157 return LZO_E_ERROR; 158 159 offset = (offset << 8) - offset; 160 t += offset + 31 + *ip++; 161 NEED_IP(2); 162 } 163 m_pos = op - 1; 164 next = get_unaligned_le16(ip); 165 ip += 2; 166 m_pos -= next >> 2; 167 next &= 3; 168 } else { 169 NEED_IP(2); 170 next = get_unaligned_le16(ip); 171 if (((next & 0xfffc) == 0xfffc) && 172 ((t & 0xf8) == 0x18) && 173 likely(bitstream_version)) { 174 NEED_IP(3); 175 t &= 7; 176 t |= ip[2] << 3; 177 t += MIN_ZERO_RUN_LENGTH; 178 NEED_OP(t); 179 memset(op, 0, t); 180 op += t; 181 next &= 3; 182 ip += 3; 183 goto match_next; 184 } else { 185 m_pos = op; 186 m_pos -= (t & 8) << 11; 187 t = (t & 7) + (3 - 1); 188 if (unlikely(t == 2)) { 189 size_t offset; 190 const unsigned char *ip_last = ip; 191 192 while (unlikely(*ip == 0)) { 193 ip++; 194 NEED_IP(1); 195 } 196 offset = ip - ip_last; 197 if (unlikely(offset > MAX_255_COUNT)) 198 return LZO_E_ERROR; 199 200 offset = (offset << 8) - offset; 201 t += offset + 7 + *ip++; 202 NEED_IP(2); 203 next = get_unaligned_le16(ip); 204 } 205 ip += 2; 206 m_pos -= next >> 2; 207 next &= 3; 208 if (m_pos == op) 209 goto eof_found; 210 m_pos -= 0x4000; 211 } 212 } 213 TEST_LB(m_pos); 214 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 215 if (op - m_pos >= 8) { 216 unsigned char *oe = op + t; 217 if (likely(HAVE_OP(t + 15))) { 218 do { 219 COPY8(op, m_pos); 220 op += 8; 221 m_pos += 8; 222 COPY8(op, m_pos); 223 op += 8; 224 m_pos += 8; 225 } while (op < oe); 226 op = oe; 227 if (HAVE_IP(6)) { 228 state = next; 229 COPY4(op, ip); 230 op += next; 231 ip += next; 232 continue; 233 } 234 } else { 235 NEED_OP(t); 236 do { 237 *op++ = *m_pos++; 238 } while (op < oe); 239 } 240 } else 241 #endif 242 { 243 unsigned char *oe = op + t; 244 NEED_OP(t); 245 op[0] = m_pos[0]; 246 op[1] = m_pos[1]; 247 op += 2; 248 m_pos += 2; 249 do { 250 *op++ = *m_pos++; 251 } while (op < oe); 252 } 253 match_next: 254 state = next; 255 t = next; 256 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 257 if (likely(HAVE_IP(6) && HAVE_OP(4))) { 258 COPY4(op, ip); 259 op += t; 260 ip += t; 261 } else 262 #endif 263 { 264 NEED_IP(t + 3); 265 NEED_OP(t); 266 while (t > 0) { 267 *op++ = *ip++; 268 t--; 269 } 270 } 271 } 272 273 eof_found: 274 *out_len = op - out; 275 return (t != 3 ? LZO_E_ERROR : 276 ip == ip_end ? LZO_E_OK : 277 ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN); 278 279 input_overrun: 280 *out_len = op - out; 281 return LZO_E_INPUT_OVERRUN; 282 283 output_overrun: 284 *out_len = op - out; 285 return LZO_E_OUTPUT_OVERRUN; 286 287 lookbehind_overrun: 288 *out_len = op - out; 289 return LZO_E_LOOKBEHIND_OVERRUN; 290 } 291 #ifndef STATIC 292 EXPORT_SYMBOL_GPL(lzo1x_decompress_safe); 293 294 MODULE_LICENSE("GPL"); 295 MODULE_DESCRIPTION("LZO1X Decompressor"); 296 297 #endif 298