linux/drivers/staging/erofs/unzip_lz4.c
<<
>>
Prefs
   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 */
  52static 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
 230int 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
 252