Commit afca294289949b118a192b77be947379734ea620

Authored by Kees Cook
Committed by Simon Glass
1 parent b75650d84d

lzma: correctly bounds-check output buffer

The output buffer size must be correctly passed to the lzma decoder or
there is a risk of overflowing memory during decompression. Switching
to the LZMA_FINISH_END mode means nothing is left in an unknown state
once the buffer becomes full.

Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: Simon Glass <sjg@chromium.org>

Showing 1 changed file with 6 additions and 2 deletions Inline Diff

lib/lzma/LzmaTools.c
1 /* 1 /*
2 * Usefuls routines based on the LzmaTest.c file from LZMA SDK 4.65 2 * Usefuls routines based on the LzmaTest.c file from LZMA SDK 4.65
3 * 3 *
4 * Copyright (C) 2007-2009 Industrie Dial Face S.p.A. 4 * Copyright (C) 2007-2009 Industrie Dial Face S.p.A.
5 * Luigi 'Comio' Mantellini (luigi.mantellini@idf-hit.com) 5 * Luigi 'Comio' Mantellini (luigi.mantellini@idf-hit.com)
6 * 6 *
7 * Copyright (C) 1999-2005 Igor Pavlov 7 * Copyright (C) 1999-2005 Igor Pavlov
8 * 8 *
9 * SPDX-License-Identifier: GPL-2.0+ 9 * SPDX-License-Identifier: GPL-2.0+
10 */ 10 */
11 11
12 /* 12 /*
13 * LZMA_Alone stream format: 13 * LZMA_Alone stream format:
14 * 14 *
15 * uchar Properties[5] 15 * uchar Properties[5]
16 * uint64 Uncompressed size 16 * uint64 Uncompressed size
17 * uchar data[*] 17 * uchar data[*]
18 * 18 *
19 */ 19 */
20 20
21 #include <config.h> 21 #include <config.h>
22 #include <common.h> 22 #include <common.h>
23 #include <watchdog.h> 23 #include <watchdog.h>
24 24
25 #ifdef CONFIG_LZMA 25 #ifdef CONFIG_LZMA
26 26
27 #define LZMA_PROPERTIES_OFFSET 0 27 #define LZMA_PROPERTIES_OFFSET 0
28 #define LZMA_SIZE_OFFSET LZMA_PROPS_SIZE 28 #define LZMA_SIZE_OFFSET LZMA_PROPS_SIZE
29 #define LZMA_DATA_OFFSET LZMA_SIZE_OFFSET+sizeof(uint64_t) 29 #define LZMA_DATA_OFFSET LZMA_SIZE_OFFSET+sizeof(uint64_t)
30 30
31 #include "LzmaTools.h" 31 #include "LzmaTools.h"
32 #include "LzmaDec.h" 32 #include "LzmaDec.h"
33 33
34 #include <linux/string.h> 34 #include <linux/string.h>
35 #include <malloc.h> 35 #include <malloc.h>
36 36
37 static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } 37 static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
38 static void SzFree(void *p, void *address) { p = p; free(address); } 38 static void SzFree(void *p, void *address) { p = p; free(address); }
39 39
40 int lzmaBuffToBuffDecompress (unsigned char *outStream, SizeT *uncompressedSize, 40 int lzmaBuffToBuffDecompress (unsigned char *outStream, SizeT *uncompressedSize,
41 unsigned char *inStream, SizeT length) 41 unsigned char *inStream, SizeT length)
42 { 42 {
43 int res = SZ_ERROR_DATA; 43 int res = SZ_ERROR_DATA;
44 int i; 44 int i;
45 ISzAlloc g_Alloc; 45 ISzAlloc g_Alloc;
46 46
47 SizeT outSizeFull = 0xFFFFFFFF; /* 4GBytes limit */ 47 SizeT outSizeFull = 0xFFFFFFFF; /* 4GBytes limit */
48 SizeT outProcessed; 48 SizeT outProcessed;
49 SizeT outSize; 49 SizeT outSize;
50 SizeT outSizeHigh; 50 SizeT outSizeHigh;
51 ELzmaStatus state; 51 ELzmaStatus state;
52 SizeT compressedSize = (SizeT)(length - LZMA_PROPS_SIZE); 52 SizeT compressedSize = (SizeT)(length - LZMA_PROPS_SIZE);
53 53
54 debug ("LZMA: Image address............... 0x%p\n", inStream); 54 debug ("LZMA: Image address............... 0x%p\n", inStream);
55 debug ("LZMA: Properties address.......... 0x%p\n", inStream + LZMA_PROPERTIES_OFFSET); 55 debug ("LZMA: Properties address.......... 0x%p\n", inStream + LZMA_PROPERTIES_OFFSET);
56 debug ("LZMA: Uncompressed size address... 0x%p\n", inStream + LZMA_SIZE_OFFSET); 56 debug ("LZMA: Uncompressed size address... 0x%p\n", inStream + LZMA_SIZE_OFFSET);
57 debug ("LZMA: Compressed data address..... 0x%p\n", inStream + LZMA_DATA_OFFSET); 57 debug ("LZMA: Compressed data address..... 0x%p\n", inStream + LZMA_DATA_OFFSET);
58 debug ("LZMA: Destination address......... 0x%p\n", outStream); 58 debug ("LZMA: Destination address......... 0x%p\n", outStream);
59 59
60 memset(&state, 0, sizeof(state)); 60 memset(&state, 0, sizeof(state));
61 61
62 outSize = 0; 62 outSize = 0;
63 outSizeHigh = 0; 63 outSizeHigh = 0;
64 /* Read the uncompressed size */ 64 /* Read the uncompressed size */
65 for (i = 0; i < 8; i++) { 65 for (i = 0; i < 8; i++) {
66 unsigned char b = inStream[LZMA_SIZE_OFFSET + i]; 66 unsigned char b = inStream[LZMA_SIZE_OFFSET + i];
67 if (i < 4) { 67 if (i < 4) {
68 outSize += (UInt32)(b) << (i * 8); 68 outSize += (UInt32)(b) << (i * 8);
69 } else { 69 } else {
70 outSizeHigh += (UInt32)(b) << ((i - 4) * 8); 70 outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
71 } 71 }
72 } 72 }
73 73
74 outSizeFull = (SizeT)outSize; 74 outSizeFull = (SizeT)outSize;
75 if (sizeof(SizeT) >= 8) { 75 if (sizeof(SizeT) >= 8) {
76 /* 76 /*
77 * SizeT is a 64 bit uint => We can manage files larger than 4GB! 77 * SizeT is a 64 bit uint => We can manage files larger than 4GB!
78 * 78 *
79 */ 79 */
80 outSizeFull |= (((SizeT)outSizeHigh << 16) << 16); 80 outSizeFull |= (((SizeT)outSizeHigh << 16) << 16);
81 } else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) { 81 } else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) {
82 /* 82 /*
83 * SizeT is a 32 bit uint => We cannot manage files larger than 83 * SizeT is a 32 bit uint => We cannot manage files larger than
84 * 4GB! Assume however that all 0xf values is "unknown size" and 84 * 4GB! Assume however that all 0xf values is "unknown size" and
85 * not actually a file of 2^64 bits. 85 * not actually a file of 2^64 bits.
86 * 86 *
87 */ 87 */
88 if (outSizeHigh != (SizeT)-1 || outSize != (SizeT)-1) { 88 if (outSizeHigh != (SizeT)-1 || outSize != (SizeT)-1) {
89 debug ("LZMA: 64bit support not enabled.\n"); 89 debug ("LZMA: 64bit support not enabled.\n");
90 return SZ_ERROR_DATA; 90 return SZ_ERROR_DATA;
91 } 91 }
92 } 92 }
93 93
94 debug("LZMA: Uncompresed size............ 0x%zx\n", outSizeFull); 94 debug("LZMA: Uncompresed size............ 0x%zx\n", outSizeFull);
95 debug("LZMA: Compresed size.............. 0x%zx\n", compressedSize); 95 debug("LZMA: Compresed size.............. 0x%zx\n", compressedSize);
96 96
97 g_Alloc.Alloc = SzAlloc; 97 g_Alloc.Alloc = SzAlloc;
98 g_Alloc.Free = SzFree; 98 g_Alloc.Free = SzFree;
99 99
100 /* Short-circuit early if we know the buffer can't hold the results. */
101 if (outSizeFull != (SizeT)-1 && *uncompressedSize < outSizeFull)
102 return SZ_ERROR_OUTPUT_EOF;
103
100 /* Decompress */ 104 /* Decompress */
101 outProcessed = outSizeFull; 105 outProcessed = *uncompressedSize;
102 106
103 WATCHDOG_RESET(); 107 WATCHDOG_RESET();
104 108
105 res = LzmaDecode( 109 res = LzmaDecode(
106 outStream, &outProcessed, 110 outStream, &outProcessed,
107 inStream + LZMA_DATA_OFFSET, &compressedSize, 111 inStream + LZMA_DATA_OFFSET, &compressedSize,
108 inStream, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &state, &g_Alloc); 112 inStream, LZMA_PROPS_SIZE, LZMA_FINISH_END, &state, &g_Alloc);
109 *uncompressedSize = outProcessed; 113 *uncompressedSize = outProcessed;
110 if (res != SZ_OK) { 114 if (res != SZ_OK) {
111 return res; 115 return res;
112 } 116 }
113 117
114 return res; 118 return res;
115 } 119 }
116 120
117 #endif 121 #endif
118 122