Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/lzo.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  lzo.c -- LZO1X Compressor 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
 *  Adapted for Xen (files combined and syntactic/header changes) by:
10
 *  Dan Magenheimer <dan.magenheimer@oracle.com>
11
 *
12
 */
13
14
/*
15
 *  lzodefs.h -- architecture, OS and compiler specific defines
16
 *
17
 *  Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
18
 *
19
 *  The full LZO package can be found at:
20
 *  http://www.oberhumer.com/opensource/lzo/
21
 *
22
 *  Changed for Linux kernel use by:
23
 *  Nitin Gupta <nitingupta910@gmail.com>
24
 *  Richard Purdie <rpurdie@openedhand.com>
25
 */
26
27
28
#define COPY4(dst, src)    \
29
0
        put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst))
30
#if defined(__x86_64__)
31
#define COPY8(dst, src)    \
32
0
        put_unaligned(get_unaligned((const u64 *)(src)), (u64 *)(dst))
33
#else
34
#define COPY8(dst, src)    \
35
        COPY4(dst, src); COPY4((dst) + 4, (src) + 4)
36
#endif
37
38
#ifdef __MINIOS__
39
# include <lib.h>
40
# if __BYTE_ORDER == __LITTLE_ENDIAN
41
#  undef __BIG_ENDIAN
42
# endif
43
# if __BYTE_ORDER == __BIG_ENDIAN
44
#  undef __LITTLE_ENDIAN
45
# endif
46
#endif
47
48
#if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)
49
#error "conflicting endian definitions"
50
#elif defined(__x86_64__)
51
#define LZO_USE_CTZ64    1
52
#define LZO_USE_CTZ32    1
53
#elif defined(__i386__) || defined(__powerpc__)
54
#define LZO_USE_CTZ32    1
55
#elif defined(__arm__) && (__LINUX_ARM_ARCH__ >= 5)
56
#define LZO_USE_CTZ32    1
57
#endif
58
59
#define M1_MAX_OFFSET 0x0400
60
0
#define M2_MAX_OFFSET 0x0800
61
0
#define M3_MAX_OFFSET 0x4000
62
0
#define M4_MAX_OFFSET 0xbfff
63
64
#define M1_MIN_LEN 2
65
#define M1_MAX_LEN 2
66
#define M2_MIN_LEN 3
67
0
#define M2_MAX_LEN 8
68
#define M3_MIN_LEN 3
69
0
#define M3_MAX_LEN 33
70
#define M4_MIN_LEN 3
71
0
#define M4_MAX_LEN 9
72
73
#define M1_MARKER 0
74
#define M2_MARKER 64
75
0
#define M3_MARKER 32
76
0
#define M4_MARKER 16
77
78
0
#define lzo_dict_t unsigned short
79
0
#define D_BITS  13
80
0
#define D_SIZE  (1u << D_BITS)
81
0
#define D_MASK  (D_SIZE - 1)
82
#define D_HIGH  ((D_MASK >> 1) + 1)
83
84
/*
85
 *  LZO1X Compressor from LZO
86
 *
87
 *  Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
88
 *
89
 *  The full LZO package can be found at:
90
 *  http://www.oberhumer.com/opensource/lzo/
91
 *
92
 *  Changed for Linux kernel use by:
93
 *  Nitin Gupta <nitingupta910@gmail.com>
94
 *  Richard Purdie <rpurdie@openedhand.com>
95
 */
96
97
#ifdef __XEN__
98
#include <xen/lib.h>
99
#include <asm/byteorder.h>
100
#endif
101
102
#include <xen/lzo.h>
103
0
#define get_unaligned(_p) (*(_p))
104
0
#define put_unaligned(_val,_p) (*(_p)=_val)
105
0
#define get_unaligned_le16(_p) (*(u16 *)(_p))
106
0
#define get_unaligned_le32(_p) (*(u32 *)(_p))
107
108
static noinline size_t
109
lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
110
                    unsigned char *out, size_t *out_len,
111
                    size_t ti, void *wrkmem)
112
0
{
113
0
    const unsigned char *ip;
114
0
    unsigned char *op;
115
0
    const unsigned char * const in_end = in + in_len;
116
0
    const unsigned char * const ip_end = in + in_len - 20;
117
0
    const unsigned char *ii;
118
0
    lzo_dict_t * const dict = (lzo_dict_t *) wrkmem;
119
0
120
0
    op = out;
121
0
    ip = in;
122
0
    ii = ip;
123
0
    ip += ti < 4 ? 4 - ti : 0;
124
0
125
0
    for (;;) {
126
0
        const unsigned char *m_pos;
127
0
        size_t t, m_len, m_off;
128
0
        u32 dv;
129
0
    literal:
130
0
        ip += 1 + ((ip - ii) >> 5);
131
0
    next:
132
0
        if (unlikely(ip >= ip_end))
133
0
            break;
134
0
        dv = get_unaligned_le32(ip);
135
0
        t = ((dv * 0x1824429d) >> (32 - D_BITS)) & D_MASK;
136
0
        m_pos = in + dict[t];
137
0
        dict[t] = (lzo_dict_t) (ip - in);
138
0
        if (unlikely(dv != get_unaligned_le32(m_pos)))
139
0
            goto literal;
140
0
141
0
        ii -= ti;
142
0
        ti = 0;
143
0
        t = ip - ii;
144
0
        if (t != 0) {
145
0
            if (t <= 3) {
146
0
                op[-2] |= t;
147
0
                COPY4(op, ii);
148
0
                op += t;
149
0
            } else if (t <= 16) {
150
0
                *op++ = (t - 3);
151
0
                COPY8(op, ii);
152
0
                COPY8(op + 8, ii + 8);
153
0
                op += t;
154
0
            } else {
155
0
                if (t <= 18) {
156
0
                    *op++ = (t - 3);
157
0
                } else {
158
0
                    size_t tt = t - 18;
159
0
                    *op++ = 0;
160
0
                    while (unlikely(tt > 255)) {
161
0
                        tt -= 255;
162
0
                        *op++ = 0;
163
0
                    }
164
0
                    *op++ = tt;
165
0
                }
166
0
                do {
167
0
                    COPY8(op, ii);
168
0
                    COPY8(op + 8, ii + 8);
169
0
                    op += 16;
170
0
                    ii += 16;
171
0
                    t -= 16;
172
0
                } while (t >= 16);
173
0
                if (t > 0) do {
174
0
                    *op++ = *ii++;
175
0
                } while (--t > 0);
176
0
            }
177
0
        }
178
0
179
0
        m_len = 4;
180
0
        {
181
0
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64)
182
0
        u64 v;
183
0
        v = get_unaligned((const u64 *) (ip + m_len)) ^
184
0
            get_unaligned((const u64 *) (m_pos + m_len));
185
0
        if (unlikely(v == 0)) {
186
0
            do {
187
0
                m_len += 8;
188
0
                v = get_unaligned((const u64 *) (ip + m_len)) ^
189
0
                    get_unaligned((const u64 *) (m_pos + m_len));
190
0
                if (unlikely(ip + m_len >= ip_end))
191
0
                    goto m_len_done;
192
0
            } while (v == 0);
193
0
        }
194
0
#  if defined(__LITTLE_ENDIAN)
195
0
        m_len += (unsigned) __builtin_ctzll(v) / 8;
196
0
#  elif defined(__BIG_ENDIAN)
197
        m_len += (unsigned) __builtin_clzll(v) / 8;
198
#  else
199
#    error "missing endian definition"
200
#  endif
201
0
#elif defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ32)
202
        u32 v;
203
        v = get_unaligned((const u32 *) (ip + m_len)) ^
204
            get_unaligned((const u32 *) (m_pos + m_len));
205
        if (unlikely(v == 0)) {
206
            do {
207
                m_len += 4;
208
                v = get_unaligned((const u32 *) (ip + m_len)) ^
209
                    get_unaligned((const u32 *) (m_pos + m_len));
210
                if (v != 0)
211
                    break;
212
                m_len += 4;
213
                v = get_unaligned((const u32 *) (ip + m_len)) ^
214
                    get_unaligned((const u32 *) (m_pos + m_len));
215
                if (unlikely(ip + m_len >= ip_end))
216
                    goto m_len_done;
217
            } while (v == 0);
218
        }
219
#  if defined(__LITTLE_ENDIAN)
220
        m_len += (unsigned) __builtin_ctz(v) / 8;
221
#  elif defined(__BIG_ENDIAN)
222
        m_len += (unsigned) __builtin_clz(v) / 8;
223
#  else
224
#    error "missing endian definition"
225
#  endif
226
#else
227
        if (unlikely(ip[m_len] == m_pos[m_len])) {
228
            do {
229
                m_len += 1;
230
                if (ip[m_len] != m_pos[m_len])
231
                    break;
232
                m_len += 1;
233
                if (ip[m_len] != m_pos[m_len])
234
                    break;
235
                m_len += 1;
236
                if (ip[m_len] != m_pos[m_len])
237
                    break;
238
                m_len += 1;
239
                if (ip[m_len] != m_pos[m_len])
240
                    break;
241
                m_len += 1;
242
                if (ip[m_len] != m_pos[m_len])
243
                    break;
244
                m_len += 1;
245
                if (ip[m_len] != m_pos[m_len])
246
                    break;
247
                m_len += 1;
248
                if (ip[m_len] != m_pos[m_len])
249
                    break;
250
                m_len += 1;
251
                if (unlikely(ip + m_len >= ip_end))
252
                    goto m_len_done;
253
            } while (ip[m_len] == m_pos[m_len]);
254
        }
255
#endif
256
0
        }
257
0
 m_len_done:
258
0
259
0
        m_off = ip - m_pos;
260
0
        ip += m_len;
261
0
        ii = ip;
262
0
        if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
263
0
            m_off -= 1;
264
0
            *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));
265
0
            *op++ = (m_off >> 3);
266
0
        } else if (m_off <= M3_MAX_OFFSET) {
267
0
            m_off -= 1;
268
0
            if (m_len <= M3_MAX_LEN)
269
0
                *op++ = (M3_MARKER | (m_len - 2));
270
0
            else {
271
0
                m_len -= M3_MAX_LEN;
272
0
                *op++ = M3_MARKER | 0;
273
0
                while (unlikely(m_len > 255)) {
274
0
                    m_len -= 255;
275
0
                    *op++ = 0;
276
0
                }
277
0
                *op++ = (m_len);
278
0
            }
279
0
            *op++ = (m_off << 2);
280
0
            *op++ = (m_off >> 6);
281
0
        } else {
282
0
            m_off -= 0x4000;
283
0
            if (m_len <= M4_MAX_LEN)
284
0
                *op++ = (M4_MARKER | ((m_off >> 11) & 8)
285
0
                             | (m_len - 2));
286
0
            else {
287
0
                m_len -= M4_MAX_LEN;
288
0
                *op++ = (M4_MARKER | ((m_off >> 11) & 8));
289
0
                while (unlikely(m_len > 255)) {
290
0
                    m_len -= 255;
291
0
                    *op++ = 0;
292
0
                }
293
0
                *op++ = (m_len);
294
0
            }
295
0
            *op++ = (m_off << 2);
296
0
            *op++ = (m_off >> 6);
297
0
        }
298
0
        goto next;
299
0
    }
300
0
    *out_len = op - out;
301
0
    return in_end - (ii - ti);
302
0
}
303
304
int lzo1x_1_compress(const unsigned char *in, size_t in_len,
305
                     unsigned char *out, size_t *out_len,
306
                     void *wrkmem)
307
0
{
308
0
    const unsigned char *ip = in;
309
0
    unsigned char *op = out;
310
0
    size_t l = in_len;
311
0
    size_t t = 0;
312
0
313
0
    while (l > 20) {
314
0
        size_t ll = l <= (M4_MAX_OFFSET + 1) ? l : (M4_MAX_OFFSET + 1);
315
0
        uintptr_t ll_end = (uintptr_t) ip + ll;
316
0
        if ((ll_end + ((t + ll) >> 5)) <= ll_end)
317
0
            break;
318
0
        BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);
319
0
        memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t));
320
0
        t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem);
321
0
        ip += ll;
322
0
        op += *out_len;
323
0
        l  -= ll;
324
0
    }
325
0
    t += l;
326
0
327
0
    if (t > 0) {
328
0
        const unsigned char *ii = in + in_len - t;
329
0
330
0
        if (op == out && t <= 238) {
331
0
            *op++ = (17 + t);
332
0
        } else if (t <= 3) {
333
0
            op[-2] |= t;
334
0
        } else if (t <= 18) {
335
0
            *op++ = (t - 3);
336
0
        } else {
337
0
            size_t tt = t - 18;
338
0
            *op++ = 0;
339
0
            while (tt > 255) {
340
0
                tt -= 255;
341
0
                *op++ = 0;
342
0
            }
343
0
            *op++ = tt;
344
0
        }
345
0
        if (t >= 16) do {
346
0
            COPY8(op, ii);
347
0
            COPY8(op + 8, ii + 8);
348
0
            op += 16;
349
0
            ii += 16;
350
0
            t -= 16;
351
0
        } while (t >= 16);
352
0
        if (t > 0) do {
353
0
            *op++ = *ii++;
354
0
        } while (--t > 0);
355
0
    }
356
0
357
0
    *op++ = M4_MARKER | 1;
358
0
    *op++ = 0;
359
0
    *op++ = 0;
360
0
361
0
    *out_len = op - out;
362
0
    return LZO_E_OK;
363
0
}
364
365
/*
366
 *  LZO1X Decompressor from LZO
367
 *
368
 *  Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
369
 *
370
 *  The full LZO package can be found at:
371
 *  http://www.oberhumer.com/opensource/lzo/
372
 *
373
 *  Changed for Linux kernel use by:
374
 *  Nitin Gupta <nitingupta910@gmail.com>
375
 *  Richard Purdie <rpurdie@openedhand.com>
376
 */
377
378
0
#define HAVE_IP(x)     ((size_t)(ip_end - ip) >= (size_t)(x))
379
0
#define HAVE_OP(x)     ((size_t)(op_end - op) >= (size_t)(x))
380
0
#define NEED_IP(x)     if (!HAVE_IP(x)) goto input_overrun
381
0
#define NEED_OP(x)     if (!HAVE_OP(x)) goto output_overrun
382
0
#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
383
384
/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base
385
 * count without overflowing an integer. The multiply will overflow when
386
 * multiplying 255 by more than MAXINT/255. The sum will overflow earlier
387
 * depending on the base count. Since the base count is taken from a u8
388
 * and a few bits, it is safe to assume that it will always be lower than
389
 * or equal to 2*255, thus we can always prevent any overflow by accepting
390
 * two less 255 steps. See Documentation/lzo.txt for more information.
391
 */
392
#define MAX_255_COUNT      ((((size_t)~0) / 255) - 2)
393
394
int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
395
                          unsigned char *out, size_t *out_len)
396
0
{
397
0
    unsigned char *op;
398
0
    const unsigned char *ip;
399
0
    size_t t, next;
400
0
    size_t state = 0;
401
0
    const unsigned char *m_pos;
402
0
    const unsigned char * const ip_end = in + in_len;
403
0
    unsigned char * const op_end = out + *out_len;
404
0
405
0
    op = out;
406
0
    ip = in;
407
0
408
0
    if (unlikely(in_len < 3))
409
0
        goto input_overrun;
410
0
    if (*ip > 17) {
411
0
        t = *ip++ - 17;
412
0
        if (t < 4) {
413
0
            next = t;
414
0
            goto match_next;
415
0
        }
416
0
        goto copy_literal_run;
417
0
    }
418
0
419
0
    for (;;) {
420
0
        t = *ip++;
421
0
        if (t < 16) {
422
0
            if (likely(state == 0)) {
423
0
                if (unlikely(t == 0)) {
424
0
                    size_t offset;
425
0
                    const unsigned char *ip_last = ip;
426
0
427
0
                    while (unlikely(*ip == 0)) {
428
0
                        ip++;
429
0
                        NEED_IP(1);
430
0
                    }
431
0
                    offset = ip - ip_last;
432
0
                    if (unlikely(offset > MAX_255_COUNT))
433
0
                        return LZO_E_ERROR;
434
0
435
0
                    offset = (offset << 8) - offset;
436
0
                    t += offset + 15 + *ip++;
437
0
                }
438
0
                t += 3;
439
0
 copy_literal_run:
440
0
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
441
0
                if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
442
0
                    const unsigned char *ie = ip + t;
443
0
                    unsigned char *oe = op + t;
444
0
                    do {
445
0
                        COPY8(op, ip);
446
0
                        op += 8;
447
0
                        ip += 8;
448
0
                        COPY8(op, ip);
449
0
                        op += 8;
450
0
                        ip += 8;
451
0
                    } while (ip < ie);
452
0
                    ip = ie;
453
0
                    op = oe;
454
0
                } else
455
0
#endif
456
0
                {
457
0
                    NEED_OP(t);
458
0
                    NEED_IP(t + 3);
459
0
                    do {
460
0
                        *op++ = *ip++;
461
0
                    } while (--t > 0);
462
0
                }
463
0
                state = 4;
464
0
                continue;
465
0
            } else if (state != 4) {
466
0
                next = t & 3;
467
0
                m_pos = op - 1;
468
0
                m_pos -= t >> 2;
469
0
                m_pos -= *ip++ << 2;
470
0
                TEST_LB(m_pos);
471
0
                NEED_OP(2);
472
0
                op[0] = m_pos[0];
473
0
                op[1] = m_pos[1];
474
0
                op += 2;
475
0
                goto match_next;
476
0
            } else {
477
0
                next = t & 3;
478
0
                m_pos = op - (1 + M2_MAX_OFFSET);
479
0
                m_pos -= t >> 2;
480
0
                m_pos -= *ip++ << 2;
481
0
                t = 3;
482
0
            }
483
0
        } else if (t >= 64) {
484
0
            next = t & 3;
485
0
            m_pos = op - 1;
486
0
            m_pos -= (t >> 2) & 7;
487
0
            m_pos -= *ip++ << 3;
488
0
            t = (t >> 5) - 1 + (3 - 1);
489
0
        } else if (t >= 32) {
490
0
            t = (t & 31) + (3 - 1);
491
0
            if (unlikely(t == 2)) {
492
0
                size_t offset;
493
0
                const unsigned char *ip_last = ip;
494
0
495
0
                while (unlikely(*ip == 0)) {
496
0
                    ip++;
497
0
                    NEED_IP(1);
498
0
                }
499
0
                offset = ip - ip_last;
500
0
                if (unlikely(offset > MAX_255_COUNT))
501
0
                    return LZO_E_ERROR;
502
0
503
0
                offset = (offset << 8) - offset;
504
0
                t += offset + 31 + *ip++;
505
0
                NEED_IP(2);
506
0
            }
507
0
            m_pos = op - 1;
508
0
            next = get_unaligned_le16(ip);
509
0
            ip += 2;
510
0
            m_pos -= next >> 2;
511
0
            next &= 3;
512
0
        } else {
513
0
            m_pos = op;
514
0
            m_pos -= (t & 8) << 11;
515
0
            t = (t & 7) + (3 - 1);
516
0
            if (unlikely(t == 2)) {
517
0
                size_t offset;
518
0
                const unsigned char *ip_last = ip;
519
0
520
0
                while (unlikely(*ip == 0)) {
521
0
                    ip++;
522
0
                    NEED_IP(1);
523
0
                }
524
0
                offset = ip - ip_last;
525
0
                if (unlikely(offset > MAX_255_COUNT))
526
0
                    return LZO_E_ERROR;
527
0
528
0
                offset = (offset << 8) - offset;
529
0
                t += offset + 7 + *ip++;
530
0
                NEED_IP(2);
531
0
            }
532
0
            next = get_unaligned_le16(ip);
533
0
            ip += 2;
534
0
            m_pos -= next >> 2;
535
0
            next &= 3;
536
0
            if (m_pos == op)
537
0
                goto eof_found;
538
0
            m_pos -= 0x4000;
539
0
        }
540
0
        TEST_LB(m_pos);
541
0
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
542
0
        if (op - m_pos >= 8) {
543
0
            unsigned char *oe = op + t;
544
0
            if (likely(HAVE_OP(t + 15))) {
545
0
                do {
546
0
                    COPY8(op, m_pos);
547
0
                    op += 8;
548
0
                    m_pos += 8;
549
0
                    COPY8(op, m_pos);
550
0
                    op += 8;
551
0
                    m_pos += 8;
552
0
                } while (op < oe);
553
0
                op = oe;
554
0
                if (HAVE_IP(6)) {
555
0
                    state = next;
556
0
                    COPY4(op, ip);
557
0
                    op += next;
558
0
                    ip += next;
559
0
                    continue;
560
0
                }
561
0
            } else {
562
0
                NEED_OP(t);
563
0
                do {
564
0
                    *op++ = *m_pos++;
565
0
                } while (op < oe);
566
0
            }
567
0
        } else
568
0
#endif
569
0
        {
570
0
            unsigned char *oe = op + t;
571
0
            NEED_OP(t);
572
0
            op[0] = m_pos[0];
573
0
            op[1] = m_pos[1];
574
0
            op += 2;
575
0
            m_pos += 2;
576
0
            do {
577
0
                *op++ = *m_pos++;
578
0
            } while (op < oe);
579
0
        }
580
0
        match_next:
581
0
        state = next;
582
0
        t = next;
583
0
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
584
0
        if (likely(HAVE_IP(6) && HAVE_OP(4))) {
585
0
            COPY4(op, ip);
586
0
            op += t;
587
0
            ip += t;
588
0
        } else
589
0
#endif
590
0
        {
591
0
            NEED_IP(t + 3);
592
0
            NEED_OP(t);
593
0
            while (t > 0) {
594
0
                *op++ = *ip++;
595
0
                t--;
596
0
            }
597
0
        }
598
0
    }
599
0
600
0
 eof_found:
601
0
    *out_len = op - out;
602
0
    return (t != 3       ? LZO_E_ERROR :
603
0
            ip == ip_end ? LZO_E_OK :
604
0
            ip <  ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN);
605
0
606
0
 input_overrun:
607
0
    *out_len = op - out;
608
0
    return LZO_E_INPUT_OVERRUN;
609
0
610
0
 output_overrun:
611
0
    *out_len = op - out;
612
0
    return LZO_E_OUTPUT_OVERRUN;
613
0
614
0
 lookbehind_overrun:
615
0
    *out_len = op - out;
616
0
    return LZO_E_LOOKBEHIND_OVERRUN;
617
0
}