1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * LZO decompressor for the Linux kernel. Code borrowed from the lzo 4 * implementation by Markus Franz Xaver Johannes Oberhumer. 5 * 6 * Linux kernel adaptation: 7 * Copyright (C) 2009 8 * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com> 9 * 10 * Original code: 11 * Copyright (C) 1996-2005 Markus Franz Xaver Johannes Oberhumer 12 * All Rights Reserved. 13 * 14 * Markus F.X.J. Oberhumer 15 * <markus@oberhumer.com> 16 * http://www.oberhumer.com/opensource/lzop/ 17 */ 18 19 #ifdef STATIC 20 #define PREBOOT 21 #include "lzo/lzo1x_decompress_safe.c" 22 #else 23 #include <linux/decompress/unlzo.h> 24 #endif 25 26 #include <linux/types.h> 27 #include <linux/lzo.h> 28 #include <linux/decompress/mm.h> 29 30 #include <linux/compiler.h> 31 #include <asm/unaligned.h> 32 33 static const unsigned char lzop_magic[] = { 34 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a }; 35 36 #define LZO_BLOCK_SIZE (256*1024l) 37 #define HEADER_HAS_FILTER 0x00000800L 38 #define HEADER_SIZE_MIN (9 + 7 + 4 + 8 + 1 + 4) 39 #define HEADER_SIZE_MAX (9 + 7 + 1 + 8 + 8 + 4 + 1 + 255 + 4) 40 41 STATIC inline long INIT parse_header(u8 *input, long *skip, long in_len) 42 { 43 int l; 44 u8 *parse = input; 45 u8 *end = input + in_len; 46 u8 level = 0; 47 u16 version; 48 49 /* 50 * Check that there's enough input to possibly have a valid header. 51 * Then it is possible to parse several fields until the minimum 52 * size may have been used. 53 */ 54 if (in_len < HEADER_SIZE_MIN) 55 return 0; 56 57 /* read magic: 9 first bits */ 58 for (l = 0; l < 9; l++) { 59 if (*parse++ != lzop_magic[l]) 60 return 0; 61 } 62 /* get version (2bytes), skip library version (2), 63 * 'need to be extracted' version (2) and 64 * method (1) */ 65 version = get_unaligned_be16(parse); 66 parse += 7; 67 if (version >= 0x0940) 68 level = *parse++; 69 if (get_unaligned_be32(parse) & HEADER_HAS_FILTER) 70 parse += 8; /* flags + filter info */ 71 else 72 parse += 4; /* flags */ 73 74 /* 75 * At least mode, mtime_low, filename length, and checksum must 76 * be left to be parsed. If also mtime_high is present, it's OK 77 * because the next input buffer check is after reading the 78 * filename length. 79 */ 80 if (end - parse < 8 + 1 + 4) 81 return 0; 82 83 /* skip mode and mtime_low */ 84 parse += 8; 85 if (version >= 0x0940) 86 parse += 4; /* skip mtime_high */ 87 88 l = *parse++; 89 /* don't care about the file name, and skip checksum */ 90 if (end - parse < l + 4) 91 return 0; 92 parse += l + 4; 93 94 *skip = parse - input; 95 return 1; 96 } 97 98 STATIC int INIT unlzo(u8 *input, long in_len, 99 long (*fill)(void *, unsigned long), 100 long (*flush)(void *, unsigned long), 101 u8 *output, long *posp, 102 void (*error) (char *x)) 103 { 104 u8 r = 0; 105 long skip = 0; 106 u32 src_len, dst_len; 107 size_t tmp; 108 u8 *in_buf, *in_buf_save, *out_buf; 109 int ret = -1; 110 111 if (output) { 112 out_buf = output; 113 } else if (!flush) { 114 error("NULL output pointer and no flush function provided"); 115 goto exit; 116 } else { 117 out_buf = malloc(LZO_BLOCK_SIZE); 118 if (!out_buf) { 119 error("Could not allocate output buffer"); 120 goto exit; 121 } 122 } 123 124 if (input && fill) { 125 error("Both input pointer and fill function provided, don't know what to do"); 126 goto exit_1; 127 } else if (input) { 128 in_buf = input; 129 } else if (!fill) { 130 error("NULL input pointer and missing fill function"); 131 goto exit_1; 132 } else { 133 in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE)); 134 if (!in_buf) { 135 error("Could not allocate input buffer"); 136 goto exit_1; 137 } 138 } 139 in_buf_save = in_buf; 140 141 if (posp) 142 *posp = 0; 143 144 if (fill) { 145 /* 146 * Start from in_buf + HEADER_SIZE_MAX to make it possible 147 * to use memcpy() to copy the unused data to the beginning 148 * of the buffer. This way memmove() isn't needed which 149 * is missing from pre-boot environments of most archs. 150 */ 151 in_buf += HEADER_SIZE_MAX; 152 in_len = fill(in_buf, HEADER_SIZE_MAX); 153 } 154 155 if (!parse_header(in_buf, &skip, in_len)) { 156 error("invalid header"); 157 goto exit_2; 158 } 159 in_buf += skip; 160 in_len -= skip; 161 162 if (fill) { 163 /* Move the unused data to the beginning of the buffer. */ 164 memcpy(in_buf_save, in_buf, in_len); 165 in_buf = in_buf_save; 166 } 167 168 if (posp) 169 *posp = skip; 170 171 for (;;) { 172 /* read uncompressed block size */ 173 if (fill && in_len < 4) { 174 skip = fill(in_buf + in_len, 4 - in_len); 175 if (skip > 0) 176 in_len += skip; 177 } 178 if (in_len < 4) { 179 error("file corrupted"); 180 goto exit_2; 181 } 182 dst_len = get_unaligned_be32(in_buf); 183 in_buf += 4; 184 in_len -= 4; 185 186 /* exit if last block */ 187 if (dst_len == 0) { 188 if (posp) 189 *posp += 4; 190 break; 191 } 192 193 if (dst_len > LZO_BLOCK_SIZE) { 194 error("dest len longer than block size"); 195 goto exit_2; 196 } 197 198 /* read compressed block size, and skip block checksum info */ 199 if (fill && in_len < 8) { 200 skip = fill(in_buf + in_len, 8 - in_len); 201 if (skip > 0) 202 in_len += skip; 203 } 204 if (in_len < 8) { 205 error("file corrupted"); 206 goto exit_2; 207 } 208 src_len = get_unaligned_be32(in_buf); 209 in_buf += 8; 210 in_len -= 8; 211 212 if (src_len <= 0 || src_len > dst_len) { 213 error("file corrupted"); 214 goto exit_2; 215 } 216 217 /* decompress */ 218 if (fill && in_len < src_len) { 219 skip = fill(in_buf + in_len, src_len - in_len); 220 if (skip > 0) 221 in_len += skip; 222 } 223 if (in_len < src_len) { 224 error("file corrupted"); 225 goto exit_2; 226 } 227 tmp = dst_len; 228 229 /* When the input data is not compressed at all, 230 * lzo1x_decompress_safe will fail, so call memcpy() 231 * instead */ 232 if (unlikely(dst_len == src_len)) 233 memcpy(out_buf, in_buf, src_len); 234 else { 235 r = lzo1x_decompress_safe((u8 *) in_buf, src_len, 236 out_buf, &tmp); 237 238 if (r != LZO_E_OK || dst_len != tmp) { 239 error("Compressed data violation"); 240 goto exit_2; 241 } 242 } 243 244 if (flush && flush(out_buf, dst_len) != dst_len) 245 goto exit_2; 246 if (output) 247 out_buf += dst_len; 248 if (posp) 249 *posp += src_len + 12; 250 251 in_buf += src_len; 252 in_len -= src_len; 253 if (fill) { 254 /* 255 * If there happens to still be unused data left in 256 * in_buf, move it to the beginning of the buffer. 257 * Use a loop to avoid memmove() dependency. 258 */ 259 if (in_len > 0) 260 for (skip = 0; skip < in_len; ++skip) 261 in_buf_save[skip] = in_buf[skip]; 262 in_buf = in_buf_save; 263 } 264 } 265 266 ret = 0; 267 exit_2: 268 if (!input) 269 free(in_buf_save); 270 exit_1: 271 if (!output) 272 free(out_buf); 273 exit: 274 return ret; 275 } 276 277 #ifdef PREBOOT 278 STATIC int INIT __decompress(unsigned char *buf, long len, 279 long (*fill)(void*, unsigned long), 280 long (*flush)(void*, unsigned long), 281 unsigned char *out_buf, long olen, 282 long *pos, 283 void (*error)(char *x)) 284 { 285 return unlzo(buf, len, fill, flush, out_buf, pos, error); 286 } 287 #endif 288