Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/lib/lzo/lzo1x_decompress_safe.c
Line
Count
Source
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
#include <asm/unaligned.h>
15
#include <common.h>
16
#include <lzo.h>
17
#include "lzodefs.h"
18
19
60.8k
#define HAVE_IP(x)      ((size_t)(ip_end - ip) >= (size_t)(x))
20
35.4k
#define HAVE_OP(x)      ((size_t)(op_end - op) >= (size_t)(x))
21
60.8k
#define NEED_IP(x)      if (!HAVE_IP(x)) goto input_overrun
22
35.4k
#define NEED_OP(x)      if (!HAVE_OP(x)) goto output_overrun
23
17.1k
#define TEST_LB(m_pos)  if ((m_pos) < out) goto lookbehind_overrun
24
25
/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base
26
 * count without overflowing an integer. The multiply will overflow when
27
 * multiplying 255 by more than MAXINT/255. The sum will overflow earlier
28
 * depending on the base count. Since the base count is taken from a u8
29
 * and a few bits, it is safe to assume that it will always be lower than
30
 * or equal to 2*255, thus we can always prevent any overflow by accepting
31
 * two less 255 steps. See Documentation/lzo.txt for more information.
32
 */
33
#define MAX_255_COUNT      ((((size_t)~0) / 255) - 2)
34
35
int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
36
      unsigned char *out, size_t *out_len)
37
303
{
38
303
  unsigned char *op;
39
303
  const unsigned char *ip;
40
303
  size_t t, next;
41
303
  size_t state = 0;
42
303
  const unsigned char *m_pos;
43
303
  const unsigned char * const ip_end = in + in_len;
44
303
  unsigned char * const op_end = out + *out_len;
45
46
303
  op = out;
47
303
  ip = in;
48
49
303
  if (unlikely(in_len < 3))
50
19
    goto input_overrun;
51
284
  if (*ip > 17) {
52
128
    t = *ip++ - 17;
53
128
    if (t < 4) {
54
98
      next = t;
55
98
      goto match_next;
56
98
    }
57
30
    goto copy_literal_run;
58
128
  }
59
60
18.4k
  for (;;) {
61
18.4k
    t = *ip++;
62
18.4k
    if (t < 16) {
63
3.13k
      if (likely(state == 0)) {
64
1.30k
        if (unlikely(t == 0)) {
65
852
          size_t offset;
66
852
          const unsigned char *ip_last = ip;
67
68
31.9k
          while (unlikely(*ip == 0)) {
69
31.0k
            ip++;
70
31.0k
            NEED_IP(1);
71
31.0k
          }
72
848
          offset = ip - ip_last;
73
848
          if (unlikely(offset > MAX_255_COUNT))
74
0
            return LZO_E_ERROR;
75
76
848
          offset = (offset << 8) - offset;
77
848
          t += offset + 15 + *ip++;
78
848
        }
79
1.30k
        t += 3;
80
1.33k
copy_literal_run:
81
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
82
        if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
83
          const unsigned char *ie = ip + t;
84
          unsigned char *oe = op + t;
85
          do {
86
            COPY8(op, ip);
87
            op += 8;
88
            ip += 8;
89
            COPY8(op, ip);
90
            op += 8;
91
            ip += 8;
92
          } while (ip < ie);
93
          ip = ie;
94
          op = oe;
95
        } else
96
#endif
97
1.33k
        {
98
1.33k
          NEED_OP(t);
99
1.31k
          NEED_IP(t + 3);
100
321k
          do {
101
321k
            *op++ = *ip++;
102
321k
          } while (--t > 0);
103
1.26k
        }
104
0
        state = 4;
105
1.26k
        continue;
106
1.82k
      } else if (state != 4) {
107
1.01k
        next = t & 3;
108
1.01k
        m_pos = op - 1;
109
1.01k
        m_pos -= t >> 2;
110
1.01k
        m_pos -= *ip++ << 2;
111
1.01k
        TEST_LB(m_pos);
112
1.00k
        NEED_OP(2);
113
1.00k
        op[0] = m_pos[0];
114
1.00k
        op[1] = m_pos[1];
115
1.00k
        op += 2;
116
1.00k
        goto match_next;
117
1.00k
      } else {
118
815
        next = t & 3;
119
815
        m_pos = op - (1 + M2_MAX_OFFSET);
120
815
        m_pos -= t >> 2;
121
815
        m_pos -= *ip++ << 2;
122
815
        t = 3;
123
815
      }
124
15.3k
    } else if (t >= 64) {
125
8.82k
      next = t & 3;
126
8.82k
      m_pos = op - 1;
127
8.82k
      m_pos -= (t >> 2) & 7;
128
8.82k
      m_pos -= *ip++ << 3;
129
8.82k
      t = (t >> 5) - 1 + (3 - 1);
130
8.82k
    } else if (t >= 32) {
131
1.16k
      t = (t & 31) + (3 - 1);
132
1.16k
      if (unlikely(t == 2)) {
133
318
        size_t offset;
134
318
        const unsigned char *ip_last = ip;
135
136
9.85k
        while (unlikely(*ip == 0)) {
137
9.53k
          ip++;
138
9.53k
          NEED_IP(1);
139
9.53k
        }
140
316
        offset = ip - ip_last;
141
316
        if (unlikely(offset > MAX_255_COUNT))
142
0
          return LZO_E_ERROR;
143
144
316
        offset = (offset << 8) - offset;
145
316
        t += offset + 31 + *ip++;
146
316
        NEED_IP(2);
147
316
      }
148
1.15k
      m_pos = op - 1;
149
1.15k
      next = get_unaligned_le16(ip);
150
1.15k
      ip += 2;
151
1.15k
      m_pos -= next >> 2;
152
1.15k
      next &= 3;
153
5.34k
    } else {
154
5.34k
      m_pos = op;
155
5.34k
      m_pos -= (t & 8) << 11;
156
5.34k
      t = (t & 7) + (3 - 1);
157
5.34k
      if (unlikely(t == 2)) {
158
487
        size_t offset;
159
487
        const unsigned char *ip_last = ip;
160
161
1.45k
        while (unlikely(*ip == 0)) {
162
976
          ip++;
163
976
          NEED_IP(1);
164
976
        }
165
483
        offset = ip - ip_last;
166
483
        if (unlikely(offset > MAX_255_COUNT))
167
0
          return LZO_E_ERROR;
168
169
483
        offset = (offset << 8) - offset;
170
483
        t += offset + 7 + *ip++;
171
483
        NEED_IP(2);
172
483
      }
173
5.33k
      next = get_unaligned_le16(ip);
174
5.33k
      ip += 2;
175
5.33k
      m_pos -= next >> 2;
176
5.33k
      next &= 3;
177
5.33k
      if (m_pos == op)
178
33
        goto eof_found;
179
5.30k
      m_pos -= 0x4000;
180
5.30k
    }
181
16.1k
    TEST_LB(m_pos);
182
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
183
    if (op - m_pos >= 8) {
184
      unsigned char *oe = op + t;
185
      if (likely(HAVE_OP(t + 15))) {
186
        do {
187
          COPY8(op, m_pos);
188
          op += 8;
189
          m_pos += 8;
190
          COPY8(op, m_pos);
191
          op += 8;
192
          m_pos += 8;
193
        } while (op < oe);
194
        op = oe;
195
        if (HAVE_IP(6)) {
196
          state = next;
197
          COPY4(op, ip);
198
          op += next;
199
          ip += next;
200
          continue;
201
        }
202
      } else {
203
        NEED_OP(t);
204
        do {
205
          *op++ = *m_pos++;
206
        } while (op < oe);
207
      }
208
    } else
209
#endif
210
16.0k
    {
211
16.0k
      unsigned char *oe = op + t;
212
16.0k
      NEED_OP(t);
213
16.0k
      op[0] = m_pos[0];
214
16.0k
      op[1] = m_pos[1];
215
16.0k
      op += 2;
216
16.0k
      m_pos += 2;
217
772k
      do {
218
772k
        *op++ = *m_pos++;
219
772k
      } while (op < oe);
220
16.0k
    }
221
17.1k
match_next:
222
17.1k
    state = next;
223
17.1k
    t = next;
224
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
225
    if (likely(HAVE_IP(6) && HAVE_OP(4))) {
226
      COPY4(op, ip);
227
      op += t;
228
      ip += t;
229
    } else
230
#endif
231
17.1k
    {
232
17.1k
      NEED_IP(t + 3);
233
17.0k
      NEED_OP(t);
234
33.8k
      while (t > 0) {
235
16.7k
        *op++ = *ip++;
236
16.7k
        t--;
237
16.7k
      }
238
17.0k
    }
239
17.0k
  }
240
241
33
eof_found:
242
33
  *out_len = op - out;
243
33
  return (t != 3       ? LZO_E_ERROR :
244
33
    ip == ip_end ? LZO_E_OK :
245
24
    ip <  ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN);
246
247
153
input_overrun:
248
153
  *out_len = op - out;
249
153
  return LZO_E_INPUT_OVERRUN;
250
251
24
output_overrun:
252
24
  *out_len = op - out;
253
24
  return LZO_E_OUTPUT_OVERRUN;
254
255
93
lookbehind_overrun:
256
93
  *out_len = op - out;
257
93
  return LZO_E_LOOKBEHIND_OVERRUN;
258
156
}
259
260
EXPORT_SYMBOL(lzo1x_decompress_safe);