GNU Linux-libre 4.19.207-gnu1
[releases.git] / drivers / staging / erofs / unzip_lz4.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
2 /*
3  * linux/drivers/staging/erofs/unzip_lz4.c
4  *
5  * Copyright (C) 2018 HUAWEI, Inc.
6  *             http://www.huawei.com/
7  * Created by Gao Xiang <gaoxiang25@huawei.com>
8  *
9  * Original code taken from 'linux/lib/lz4/lz4_decompress.c'
10  */
11
12 /*
13  * LZ4 - Fast LZ compression algorithm
14  * Copyright (C) 2011 - 2016, Yann Collet.
15  * BSD 2 - Clause License (http://www.opensource.org/licenses/bsd - license.php)
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions are
18  * met:
19  *      * Redistributions of source code must retain the above copyright
20  *        notice, this list of conditions and the following disclaimer.
21  *      * Redistributions in binary form must reproduce the above
22  * copyright notice, this list of conditions and the following disclaimer
23  * in the documentation and/or other materials provided with the
24  * distribution.
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  * You can contact the author at :
37  *      - LZ4 homepage : http://www.lz4.org
38  *      - LZ4 source repository : https://github.com/lz4/lz4
39  *
40  *      Changed for kernel usage by:
41  *      Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
42  */
43 #include "internal.h"
44 #include <asm/unaligned.h>
45 #include "lz4defs.h"
46
47 /*
48  * no public solution to solve our requirement yet.
49  * see: <required buffer size for LZ4_decompress_safe_partial>
50  *      https://groups.google.com/forum/#!topic/lz4c/_3kkz5N6n00
51  */
52 static FORCE_INLINE int customized_lz4_decompress_safe_partial(
53         const void * const source,
54         void * const dest,
55         int inputSize,
56         int outputSize)
57 {
58         /* Local Variables */
59         const BYTE *ip = (const BYTE *) source;
60         const BYTE * const iend = ip + inputSize;
61
62         BYTE *op = (BYTE *) dest;
63         BYTE * const oend = op + outputSize;
64         BYTE *cpy;
65
66         static const unsigned int dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };
67         static const int dec64table[] = { 0, 0, 0, -1, 0, 1, 2, 3 };
68
69         /* Empty output buffer */
70         if (unlikely(outputSize == 0))
71                 return ((inputSize == 1) && (*ip == 0)) ? 0 : -1;
72
73         /* Main Loop : decode sequences */
74         while (1) {
75                 size_t length;
76                 const BYTE *match;
77                 size_t offset;
78
79                 /* get literal length */
80                 unsigned int const token = *ip++;
81
82                 length = token>>ML_BITS;
83
84                 if (length == RUN_MASK) {
85                         unsigned int s;
86
87                         do {
88                                 s = *ip++;
89                                 length += s;
90                         } while ((ip < iend - RUN_MASK) & (s == 255));
91
92                         if (unlikely((size_t)(op + length) < (size_t)(op))) {
93                                 /* overflow detection */
94                                 goto _output_error;
95                         }
96                         if (unlikely((size_t)(ip + length) < (size_t)(ip))) {
97                                 /* overflow detection */
98                                 goto _output_error;
99                         }
100                 }
101
102                 /* copy literals */
103                 cpy = op + length;
104                 if ((cpy > oend - WILDCOPYLENGTH) ||
105                         (ip + length > iend - (2 + 1 + LASTLITERALS))) {
106                         if (cpy > oend) {
107                                 memcpy(op, ip, length = oend - op);
108                                 op += length;
109                                 break;
110                         }
111
112                         if (unlikely(ip + length > iend)) {
113                                 /*
114                                  * Error :
115                                  * read attempt beyond
116                                  * end of input buffer
117                                  */
118                                 goto _output_error;
119                         }
120
121                         memcpy(op, ip, length);
122                         ip += length;
123                         op += length;
124
125                         if (ip > iend - 2)
126                                 break;
127                         /* Necessarily EOF, due to parsing restrictions */
128                         /* break; */
129                 } else {
130                         LZ4_wildCopy(op, ip, cpy);
131                         ip += length;
132                         op = cpy;
133                 }
134
135                 /* get offset */
136                 offset = LZ4_readLE16(ip);
137                 ip += 2;
138                 match = op - offset;
139
140                 if (unlikely(match < (const BYTE *)dest)) {
141                         /* Error : offset outside buffers */
142                         goto _output_error;
143                 }
144
145                 /* get matchlength */
146                 length = token & ML_MASK;
147                 if (length == ML_MASK) {
148                         unsigned int s;
149
150                         do {
151                                 s = *ip++;
152
153                                 if (ip > iend - LASTLITERALS)
154                                         goto _output_error;
155
156                                 length += s;
157                         } while (s == 255);
158
159                         if (unlikely((size_t)(op + length) < (size_t)op)) {
160                                 /* overflow detection */
161                                 goto _output_error;
162                         }
163                 }
164
165                 length += MINMATCH;
166
167                 /* copy match within block */
168                 cpy = op + length;
169
170                 if (unlikely(cpy >= oend - WILDCOPYLENGTH)) {
171                         if (cpy >= oend) {
172                                 while (op < oend)
173                                         *op++ = *match++;
174                                 break;
175                         }
176                         goto __match;
177                 }
178
179                 /* costs ~1%; silence an msan warning when offset == 0 */
180                 LZ4_write32(op, (U32)offset);
181
182                 if (unlikely(offset < 8)) {
183                         const int dec64 = dec64table[offset];
184
185                         op[0] = match[0];
186                         op[1] = match[1];
187                         op[2] = match[2];
188                         op[3] = match[3];
189                         match += dec32table[offset];
190                         memcpy(op + 4, match, 4);
191                         match -= dec64;
192                 } else {
193                         LZ4_copy8(op, match);
194                         match += 8;
195                 }
196
197                 op += 8;
198
199                 if (unlikely(cpy > oend - 12)) {
200                         BYTE * const oCopyLimit = oend - (WILDCOPYLENGTH - 1);
201
202                         if (op < oCopyLimit) {
203                                 LZ4_wildCopy(op, match, oCopyLimit);
204                                 match += oCopyLimit - op;
205                                 op = oCopyLimit;
206                         }
207 __match:
208                         while (op < cpy)
209                                 *op++ = *match++;
210                 } else {
211                         LZ4_copy8(op, match);
212
213                         if (length > 16)
214                                 LZ4_wildCopy(op + 8, match + 8, cpy);
215                 }
216
217                 op = cpy; /* correction */
218         }
219         DBG_BUGON((void *)ip - source > inputSize);
220         DBG_BUGON((void *)op - dest > outputSize);
221
222         /* Nb of output bytes decoded */
223         return (int) ((void *)op - dest);
224
225         /* Overflow error detected */
226 _output_error:
227         return -ERANGE;
228 }
229
230 int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen)
231 {
232         int ret = customized_lz4_decompress_safe_partial(in,
233                 out, inlen, outlen);
234
235         if (ret >= 0)
236                 return ret;
237
238         /*
239          * LZ4_decompress_safe will return an error code
240          * (< 0) if decompression failed
241          */
242         errln("%s, failed to decompress, in[%p, %zu] outlen[%p, %zu]",
243               __func__, in, inlen, out, outlen);
244         WARN_ON(1);
245         print_hex_dump(KERN_DEBUG, "raw data [in]: ", DUMP_PREFIX_OFFSET,
246                 16, 1, in, inlen, true);
247         print_hex_dump(KERN_DEBUG, "raw data [out]: ", DUMP_PREFIX_OFFSET,
248                 16, 1, out, outlen, true);
249         return -EIO;
250 }
251