1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2007-2013 Sourcefire, Inc.
4 *
5 * Authors: Tomasz Kojm
6 *
7 * Acknowledgements: Decompression scheme by M. Winterhoff.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program 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
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
22 */
23
24 #if HAVE_CONFIG_H
25 #include "clamav-config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <string.h>
34
35 #include "clamav.h"
36 #include "others.h"
37 #include "msexpand.h"
38 #include "fmap.h"
39
40 #ifndef HAVE_ATTRIB_PACKED
41 #define __attribute__(x)
42 #endif
43
44 #ifdef HAVE_PRAGMA_PACK
45 #pragma pack(1)
46 #endif
47
48 #ifdef HAVE_PRAGMA_PACK_HPPA
49 #pragma pack 1
50 #endif
51
52 #define EC32(x) le32_to_host(x)
53 #define EC16(x) le16_to_host(x)
54
55 #define MAGIC1 0x44445a53
56 #define MAGIC2 0x3327f088
57 #define MAGIC3 0x0041
58
59 struct msexp_hdr {
60 uint32_t magic1;
61 uint32_t magic2;
62 uint16_t magic3;
63 uint32_t fsize;
64 } __attribute__((packed));
65
66 #ifdef HAVE_PRAGMA_PACK
67 #pragma pack()
68 #endif
69
70 #ifdef HAVE_PRAGMA_PACK_HPPA
71 #pragma pack
72 #endif
73
74 #define B_SIZE 4096
75 #define RW_SIZE 2048
76
77 #define READBYTES \
78 rbytes = MIN(RW_SIZE, map->len - cur_off); \
79 if (!rbytes) \
80 break; \
81 rbuff = fmap_need_off_once(map, cur_off, rbytes); \
82 if (!rbuff) \
83 return CL_EREAD; \
84 cur_off += rbytes; \
85 r = 0;
86
87 #define WRITEBYTES \
88 ret = cli_writen(ofd, wbuff, w); \
89 if (ret == (size_t)-1 || (unsigned int)ret != w) \
90 return CL_EWRITE; \
91 wbytes += w; \
92 if (wbytes >= fsize) \
93 return CL_SUCCESS; \
94 w = 0;
95
cli_msexpand(cli_ctx * ctx,int ofd)96 cl_error_t cli_msexpand(cli_ctx *ctx, int ofd)
97 {
98 const struct msexp_hdr *hdr;
99 uint8_t i, mask, bits;
100 unsigned char buff[B_SIZE], wbuff[RW_SIZE];
101 const unsigned char *rbuff = NULL; // rbuff will be set to a real address by READBYTES
102 // in the first iteration of the loop.
103 unsigned int j = B_SIZE - 16, k, l, r = 0, w = 0, rbytes = 0, wbytes = 0;
104 fmap_t *map = ctx->fmap;
105 off_t cur_off = sizeof(*hdr);
106 unsigned int fsize;
107 size_t ret;
108
109 if (!(hdr = fmap_need_off_once(map, 0, sizeof(*hdr))))
110 return CL_EREAD;
111
112 if (EC32(hdr->magic1) != MAGIC1 || EC32(hdr->magic2) != MAGIC2 || EC16(hdr->magic3) != MAGIC3) {
113 cli_dbgmsg("MSEXPAND: Not supported file format\n");
114 return CL_EFORMAT;
115 }
116
117 fsize = EC32(hdr->fsize);
118 cli_dbgmsg("MSEXPAND: File size from header: %u\n", fsize);
119
120 if (cli_checklimits("MSEXPAND", ctx, fsize, 0, 0) != CL_CLEAN)
121 return CL_SUCCESS;
122
123 memset(buff, 0, B_SIZE);
124 while (1) {
125
126 if (!rbytes || (r == rbytes)) {
127 READBYTES;
128 }
129
130 bits = rbuff[r];
131 r++;
132
133 mask = 1;
134 for (i = 0; i < 8; i++) {
135 if (bits & mask) {
136 if (r == rbytes) {
137 READBYTES;
138 }
139
140 if (w == RW_SIZE) {
141 WRITEBYTES;
142 }
143
144 wbuff[w] = buff[j] = rbuff[r];
145 r++;
146 w++;
147 j++;
148 j %= B_SIZE;
149 } else {
150 if (r == rbytes) {
151 READBYTES;
152 }
153 k = rbuff[r];
154 r++;
155
156 if (r == rbytes) {
157 READBYTES;
158 }
159 l = rbuff[r];
160 r++;
161
162 k += (l & 0xf0) << 4;
163 l = (l & 0x0f) + 3;
164 while (l--) {
165 if (w == RW_SIZE) {
166 WRITEBYTES;
167 }
168 wbuff[w] = buff[j] = buff[k];
169 w++;
170 k++;
171 k %= B_SIZE;
172 j++;
173 j %= B_SIZE;
174 }
175 }
176 mask *= 2;
177 }
178 }
179
180 if (w) {
181 WRITEBYTES;
182 }
183
184 return CL_SUCCESS;
185 }
186