]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/alone_decoder.c
Make Uncompresed Size validation more strict
[icculus/xz.git] / src / liblzma / common / alone_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       alone_decoder.c
4 /// \brief      Decoder for LZMA_Alone files
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "alone_decoder.h"
21 #include "lzma_decoder.h"
22
23
24 struct lzma_coder_s {
25         lzma_next_coder next;
26
27         enum {
28                 SEQ_PROPERTIES,
29                 SEQ_DICTIONARY_SIZE,
30                 SEQ_UNCOMPRESSED_SIZE,
31                 SEQ_CODER_INIT,
32                 SEQ_CODE,
33         } sequence;
34
35         size_t pos;
36
37         lzma_options_alone options;
38 };
39
40
41 static lzma_ret
42 alone_decode(lzma_coder *coder,
43                 lzma_allocator *allocator lzma_attribute((unused)),
44                 const uint8_t *restrict in, size_t *restrict in_pos,
45                 size_t in_size, uint8_t *restrict out,
46                 size_t *restrict out_pos, size_t out_size,
47                 lzma_action action)
48 {
49         while (*out_pos < out_size
50                         && (coder->sequence == SEQ_CODE || *in_pos < in_size))
51         switch (coder->sequence) {
52         case SEQ_PROPERTIES:
53                 if (lzma_lzma_decode_properties(
54                                 &coder->options.lzma, in[*in_pos]))
55                         return LZMA_DATA_ERROR;
56
57                 coder->sequence = SEQ_DICTIONARY_SIZE;
58                 ++*in_pos;
59                 break;
60
61         case SEQ_DICTIONARY_SIZE:
62                 coder->options.lzma.dictionary_size
63                                 |= (size_t)(in[*in_pos]) << (coder->pos * 8);
64
65                 if (++coder->pos == 4) {
66                         // A hack to ditch tons of false positives: We allow
67                         // only dictionary sizes that are a power of two.
68                         // LZMA_Alone didn't create other kinds of files,
69                         // although it's not impossible that files with
70                         // other dictionary sizes exist. Well, if someone
71                         // complains, this will be reconsidered.
72                         size_t count = 0;
73                         for (size_t i = 0; i < 32; ++i)
74                                 if (coder->options.lzma.dictionary_size
75                                                 & (UINT32_C(1) << i))
76                                         ++count;
77
78                         if (count != 1 || coder->options.lzma.dictionary_size
79                                         > LZMA_DICTIONARY_SIZE_MAX)
80                                 return LZMA_DATA_ERROR;
81
82                         coder->pos = 0;
83                         coder->sequence = SEQ_UNCOMPRESSED_SIZE;
84                 }
85
86                 ++*in_pos;
87                 break;
88
89         case SEQ_UNCOMPRESSED_SIZE:
90                 coder->options.uncompressed_size
91                                 |= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
92
93                 if (++coder->pos == 8) {
94                         // Another hack to ditch false positives: Assume that
95                         // if the uncompressed size is known, it must be less
96                         // than 256 GiB. Again, if someone complains, this
97                         // will be reconsidered.
98                         if (coder->options.uncompressed_size
99                                                 != LZMA_VLI_VALUE_UNKNOWN
100                                         && coder->options.uncompressed_size
101                                                 >= (LZMA_VLI_C(1) << 38))
102                                 return LZMA_DATA_ERROR;
103
104                         coder->pos = 0;
105                         coder->sequence = SEQ_CODER_INIT;
106                 }
107
108                 ++*in_pos;
109                 break;
110
111         case SEQ_CODER_INIT: {
112                 // Two is enough because there won't be implicit filters.
113                 lzma_filter_info filters[2] = {
114                         {
115                                 .init = &lzma_lzma_decoder_init,
116                                 .options = &coder->options.lzma,
117                                 .uncompressed_size = coder->options
118                                                 .uncompressed_size,
119                         }, {
120                                 .init = NULL,
121                         }
122                 };
123
124                 const lzma_ret ret = lzma_next_filter_init(&coder->next,
125                                 allocator, filters);
126                 if (ret != LZMA_OK)
127                         return ret;
128
129                 coder->sequence = SEQ_CODE;
130         }
131
132         // Fall through
133
134         case SEQ_CODE: {
135                 return coder->next.code(coder->next.coder,
136                                 allocator, in, in_pos, in_size,
137                                 out, out_pos, out_size, action);
138         }
139
140         default:
141                 return LZMA_PROG_ERROR;
142         }
143
144         return LZMA_OK;
145 }
146
147
148 static void
149 alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
150 {
151         lzma_next_coder_end(&coder->next, allocator);
152         lzma_free(coder, allocator);
153         return;
154 }
155
156
157 static lzma_ret
158 alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
159 {
160         if (next->coder == NULL) {
161                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
162                 if (next->coder == NULL)
163                         return LZMA_MEM_ERROR;
164
165                 next->code = &alone_decode;
166                 next->end = &alone_decoder_end;
167                 next->coder->next = LZMA_NEXT_CODER_INIT;
168         }
169
170         next->coder->sequence = SEQ_PROPERTIES;
171         next->coder->pos = 0;
172         next->coder->options.lzma.dictionary_size = 0;
173         next->coder->options.uncompressed_size = 0;
174
175         return LZMA_OK;
176 }
177
178
179 extern lzma_ret
180 lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
181 {
182         // We need to use _init2 because we don't pass any varadic args.
183         lzma_next_coder_init2(next, allocator, alone_decoder_init,
184                         alone_decoder_init, allocator);
185 }
186
187
188 extern LZMA_API lzma_ret
189 lzma_alone_decoder(lzma_stream *strm)
190 {
191         lzma_next_strm_init2(strm, alone_decoder_init,
192                         alone_decoder_init, strm->allocator);
193
194         strm->internal->supported_actions[LZMA_RUN] = true;
195         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
196
197         return LZMA_OK;
198 }