1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2013 Sourcefire, Inc.
4 *
5 * Authors: David Raynor <draynor@sourcefire.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #if HAVE_CONFIG_H
23 #include "clamav-config.h"
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #if HAVE_STRING_H
29 #include <string.h>
30 #endif
31
32 #include "clamav.h"
33 #include "others.h"
34 #include "adc.h"
35
36 /* #define DEBUG_ADC */
37
38 #ifdef DEBUG_ADC
39 #define adc_dbgmsg(...) cli_dbgmsg(__VA_ARGS__)
40 #else
41 #define adc_dbgmsg(...) ;
42 #endif
43
44 /* Initialize values and collect buffer
45 * NOTE: buffer size must be larger than largest lookback offset */
adc_decompressInit(adc_stream * strm)46 int adc_decompressInit(adc_stream *strm)
47 {
48 if (strm == NULL) {
49 return ADC_IO_ERROR;
50 }
51 if (strm->state != ADC_STATE_UNINIT) {
52 return ADC_DATA_ERROR;
53 }
54
55 /* Have to buffer maximum backward lookup */
56 strm->buffer = (uint8_t *)calloc(ADC_BUFF_SIZE, 1);
57 if (strm->buffer == NULL) {
58 return ADC_MEM_ERROR;
59 }
60 strm->buffered = 0;
61 strm->state = ADC_STATE_GETTYPE;
62 strm->length = 0;
63 strm->offset = 0;
64 strm->curr = strm->buffer;
65
66 return ADC_OK;
67 }
68
69 /* Decompress routine
70 * NOTE: Reaching end of input buffer does not mean end of output.
71 * It may fill the output buffer but have more to output.
72 * It will only return ADC_STREAM_END if output buffer is not full.
73 * It will return ADC_DATA_ERROR if it ends in the middle of a phrase
74 * (i.e. in the middle of a lookback code or data run)
75 */
adc_decompress(adc_stream * strm)76 int adc_decompress(adc_stream *strm)
77 {
78 uint8_t bData;
79 uint8_t didNothing = 1;
80
81 /* first, the error returns based on strm */
82 if ((strm == NULL) || (strm->next_in == NULL) || (strm->next_out == NULL)) {
83 return ADC_IO_ERROR;
84 }
85 if (strm->state == ADC_STATE_UNINIT) {
86 return ADC_DATA_ERROR;
87 }
88
89 cli_dbgmsg("adc_decompress: avail_in %llu avail_out %llu state %u\n",
90 (long long unsigned)strm->avail_in, (long long unsigned)strm->avail_out, strm->state);
91
92 while (strm->avail_out) {
93 /* Exit if needs more in bytes and none available */
94 int needsInput;
95 switch (strm->state) {
96 case ADC_STATE_SHORTLOOK:
97 case ADC_STATE_LONGLOOK:
98 needsInput = 0;
99 break;
100 default:
101 needsInput = 1;
102 break;
103 }
104 if (needsInput && (strm->avail_in == 0)) {
105 break;
106 } else {
107 didNothing = 0;
108 }
109
110 /* Find or execute statecode */
111 switch (strm->state) {
112 case ADC_STATE_GETTYPE: {
113 /* Grab action code */
114 bData = *(strm->next_in);
115 strm->next_in++;
116 strm->avail_in--;
117 if (bData & 0x80) {
118 strm->state = ADC_STATE_RAWDATA;
119 strm->offset = 0;
120 strm->length = (bData & 0x7F) + 1;
121 } else if (bData & 0x40) {
122 strm->state = ADC_STATE_LONGOP2;
123 strm->offset = 0;
124 strm->length = (bData & 0x3F) + 4;
125 } else {
126 strm->state = ADC_STATE_SHORTOP;
127 strm->offset = (bData & 0x3) * 0x100;
128 strm->length = ((bData & 0x3C) >> 2) + 3;
129 }
130 adc_dbgmsg("adc_decompress: GETTYPE bData %x state %u offset %u length %u\n",
131 bData, strm->state, strm->offset, strm->length);
132 break;
133 }
134 case ADC_STATE_LONGOP2: {
135 /* Grab first offset byte */
136 bData = *(strm->next_in);
137 strm->next_in++;
138 strm->avail_in--;
139 strm->offset = bData * 0x100;
140 strm->state = ADC_STATE_LONGOP1;
141 adc_dbgmsg("adc_decompress: LONGOP2 bData %x state %u offset %u length %u\n",
142 bData, strm->state, strm->offset, strm->length);
143 break;
144 }
145 case ADC_STATE_LONGOP1: {
146 /* Grab second offset byte */
147 bData = *(strm->next_in);
148 strm->next_in++;
149 strm->avail_in--;
150 strm->offset += bData + 1;
151 strm->state = ADC_STATE_LONGLOOK;
152 adc_dbgmsg("adc_decompress: LONGOP1 bData %x state %u offset %u length %u\n",
153 bData, strm->state, strm->offset, strm->length);
154 break;
155 }
156 case ADC_STATE_SHORTOP: {
157 /* Grab offset byte */
158 bData = *(strm->next_in);
159 strm->next_in++;
160 strm->avail_in--;
161 strm->offset += bData + 1;
162 strm->state = ADC_STATE_SHORTLOOK;
163 adc_dbgmsg("adc_decompress: SHORTOP bData %x state %u offset %u length %u\n",
164 bData, strm->state, strm->offset, strm->length);
165 break;
166 }
167
168 case ADC_STATE_RAWDATA: {
169 /* Grab data */
170 adc_dbgmsg("adc_decompress: RAWDATA offset %u length %u\n", strm->offset, strm->length);
171 while ((strm->avail_in > 0) && (strm->avail_out > 0) && (strm->length > 0)) {
172 bData = *(strm->next_in);
173 strm->next_in++;
174 strm->avail_in--;
175 /* store to output */
176 *(strm->next_out) = bData;
177 strm->next_out++;
178 strm->avail_out--;
179 /* store to buffer */
180 if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
181 strm->curr = strm->buffer;
182 }
183 *(strm->curr) = bData;
184 strm->curr++;
185 if (strm->buffered < ADC_BUFF_SIZE) {
186 strm->buffered++;
187 }
188 strm->length--;
189 }
190 if (strm->length == 0) {
191 /* adc_dbgmsg("adc_decompress: RAWDATADONE buffered %u avail_in %u avail_out %u \n",
192 strm->buffered, strm->avail_in, strm->avail_out); */
193 strm->state = ADC_STATE_GETTYPE;
194 }
195 break;
196 }
197
198 case ADC_STATE_SHORTLOOK:
199 case ADC_STATE_LONGLOOK: {
200 /* Copy data */
201 adc_dbgmsg("adc_decompress: LOOKBACK offset %u length %u avail_in %u avail_out %u\n",
202 strm->offset, strm->length, strm->avail_in, strm->avail_out);
203 while ((strm->avail_out > 0) && (strm->length > 0)) {
204 /* state validation first */
205 if (strm->offset > 0x10000) {
206 cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
207 return ADC_DATA_ERROR;
208 } else if ((strm->state == ADC_STATE_SHORTLOOK) && (strm->offset > 0x400)) {
209 cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
210 return ADC_DATA_ERROR;
211 }
212 if (strm->offset > strm->buffered) {
213 cli_dbgmsg("adc_decompress: too large LOOKBACK offset %u\n", strm->offset);
214 return ADC_DATA_ERROR;
215 }
216 /* retrieve byte */
217 if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
218 strm->curr = strm->buffer;
219 }
220 if (strm->curr >= (strm->buffer + strm->offset)) {
221 bData = *(uint8_t *)(strm->curr - strm->offset);
222 } else {
223 bData = *(uint8_t *)(strm->curr + ADC_BUFF_SIZE - strm->offset);
224 }
225 /* store to output */
226 *(strm->next_out) = bData;
227 strm->next_out++;
228 strm->avail_out--;
229 /* store to buffer */
230 *(strm->curr) = bData;
231 strm->curr++;
232 if (strm->buffered < ADC_BUFF_SIZE) {
233 strm->buffered++;
234 }
235 strm->length--;
236 }
237 if (strm->length == 0) {
238 strm->state = ADC_STATE_GETTYPE;
239 /* adc_dbgmsg("adc_decompress: LOOKBACKDONE buffered %u avail_in %u avail_out %u \n",
240 strm->buffered, strm->avail_in, strm->avail_out); */
241 }
242 break;
243 }
244
245 default: {
246 /* bad state */
247 cli_errmsg("adc_decompress: invalid state %u\n", strm->state);
248 return ADC_DATA_ERROR;
249 }
250 } /* end switch */
251 } /* end while */
252
253 /* There really isn't a terminator, just end of data */
254 if (didNothing && strm->avail_out) {
255 if (strm->state == ADC_STATE_GETTYPE) {
256 /* Nothing left to do */
257 return ADC_STREAM_END;
258 } else {
259 /* Ended mid phrase */
260 cli_dbgmsg("adc_decompress: stream ended mid-phrase, state %u\n", strm->state);
261 return ADC_DATA_ERROR;
262 }
263 }
264 return ADC_OK;
265 }
266
267 /* Cleanup routine, frees buffer */
adc_decompressEnd(adc_stream * strm)268 int adc_decompressEnd(adc_stream *strm)
269 {
270 if (strm == NULL) {
271 return ADC_IO_ERROR;
272 }
273 if (strm->state == ADC_STATE_UNINIT) {
274 return ADC_DATA_ERROR;
275 }
276
277 if (strm->buffer != NULL) {
278 free(strm->buffer);
279 }
280 strm->buffered = 0;
281 strm->state = ADC_STATE_UNINIT;
282 strm->length = 0;
283 strm->offset = 0;
284
285 return ADC_OK;
286 }
287