/src/clamav/libclamav/cpio.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2013-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
3 | | * Copyright (C) 2009-2013 Sourcefire, Inc. |
4 | | * |
5 | | * Authors: Tomasz Kojm <tkojm@clamav.net> |
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 <string.h> |
28 | | #include <ctype.h> |
29 | | #ifdef HAVE_UNISTD_H |
30 | | #include <unistd.h> |
31 | | #endif |
32 | | #include <sys/types.h> |
33 | | #include <sys/stat.h> |
34 | | #include <fcntl.h> |
35 | | |
36 | | #include "clamav.h" |
37 | | #include "others.h" |
38 | | #include "cpio.h" |
39 | | #include "scanners.h" |
40 | | #include "matcher.h" |
41 | | |
42 | | struct cpio_hdr_old { |
43 | | uint16_t magic; |
44 | | uint16_t dev; |
45 | | uint16_t ino; |
46 | | uint16_t mode; |
47 | | uint16_t uid; |
48 | | uint16_t gid; |
49 | | uint16_t nlink; |
50 | | uint16_t rdev; |
51 | | uint16_t mtime[2]; |
52 | | uint16_t namesize; |
53 | | uint16_t filesize[2]; |
54 | | }; |
55 | | |
56 | | struct cpio_hdr_odc { |
57 | | char magic[6]; |
58 | | char dev[6]; |
59 | | char ino[6]; |
60 | | char mode[6]; |
61 | | char uid[6]; |
62 | | char gid[6]; |
63 | | char nlink[6]; |
64 | | char rdev[6]; |
65 | | char mtime[11]; |
66 | | char namesize[6]; |
67 | | char filesize[11]; |
68 | | }; |
69 | | |
70 | | struct cpio_hdr_newc { |
71 | | char magic[6]; |
72 | | char ino[8]; |
73 | | char mode[8]; |
74 | | char uid[8]; |
75 | | char gid[8]; |
76 | | char nlink[8]; |
77 | | char mtime[8]; |
78 | | char filesize[8]; |
79 | | char devmajor[8]; |
80 | | char devminor[8]; |
81 | | char rdevmajor[8]; |
82 | | char rdevminor[8]; |
83 | | char namesize[8]; |
84 | | char check[8]; |
85 | | }; |
86 | | |
87 | 45.2k | #define EC16(v, conv) (conv ? cbswap16(v) : v) |
88 | | |
89 | | static void sanitname(char *name) |
90 | 29.9k | { |
91 | 618k | while (*name) { |
92 | 588k | if (!isascii(*name) || strchr("%\\\t\n\r", *name)) |
93 | 138k | *name = '_'; |
94 | 588k | name++; |
95 | 588k | } |
96 | 29.9k | } |
97 | | |
98 | | cl_error_t cli_scancpio_old(cli_ctx *ctx) |
99 | 22.0k | { |
100 | 22.0k | cl_error_t status = CL_SUCCESS; |
101 | 22.0k | struct cpio_hdr_old hdr_old; |
102 | 22.0k | char *fmap_name = NULL; |
103 | 22.0k | char name[513]; |
104 | 22.0k | unsigned int file = 0, trailer = 0; |
105 | 22.0k | uint32_t filesize, namesize, hdr_namesize; |
106 | 22.0k | int conv; |
107 | 22.0k | size_t pos = 0; |
108 | | |
109 | 22.0k | memset(name, 0, sizeof(name)); |
110 | | |
111 | 35.8k | while (fmap_readn(ctx->fmap, &hdr_old, pos, sizeof(hdr_old)) == sizeof(hdr_old)) { |
112 | 29.9k | pos += sizeof(hdr_old); |
113 | 29.9k | if (!hdr_old.magic && trailer) { |
114 | 388 | status = CL_SUCCESS; |
115 | 388 | goto done; |
116 | 388 | } |
117 | | |
118 | 29.5k | if (hdr_old.magic == 070707) { |
119 | 10.2k | conv = 0; |
120 | 19.3k | } else if (hdr_old.magic == 0143561) { |
121 | 11.3k | conv = 1; |
122 | 11.3k | } else { |
123 | 7.94k | cli_dbgmsg("cli_scancpio_old: Invalid magic number\n"); |
124 | 7.94k | status = CL_EFORMAT; |
125 | 7.94k | goto done; |
126 | 7.94k | } |
127 | | |
128 | 21.6k | cli_dbgmsg("CPIO: -- File %u --\n", ++file); |
129 | | |
130 | 21.6k | if (hdr_old.namesize) { |
131 | 11.5k | hdr_namesize = EC16(hdr_old.namesize, conv); |
132 | 11.5k | namesize = MIN(sizeof(name), hdr_namesize); |
133 | 11.5k | if (fmap_readn(ctx->fmap, &name, pos, namesize) != namesize) { |
134 | 7.76k | cli_dbgmsg("cli_scancpio_old: Can't read file name\n"); |
135 | 7.76k | status = CL_EFORMAT; |
136 | 7.76k | goto done; |
137 | 7.76k | } |
138 | 3.82k | pos += namesize; |
139 | 3.82k | name[namesize - 1] = 0; |
140 | 3.82k | sanitname(name); |
141 | 3.82k | cli_dbgmsg("CPIO: Name: %s\n", name); |
142 | 3.82k | if (!strcmp(name, "TRAILER!!!")) { |
143 | 464 | trailer = 1; |
144 | 464 | } |
145 | | |
146 | 3.82k | if (namesize < hdr_namesize) { |
147 | 1.52k | if (hdr_namesize % 2) { |
148 | 657 | hdr_namesize++; |
149 | 657 | } |
150 | 1.52k | pos += hdr_namesize - namesize; |
151 | 2.29k | } else if (hdr_namesize % 2) { |
152 | 987 | pos++; |
153 | 987 | } |
154 | | |
155 | 3.82k | fmap_name = name; |
156 | 3.82k | } |
157 | 13.8k | filesize = (uint32_t)((uint32_t)EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv)); |
158 | 13.8k | cli_dbgmsg("CPIO: Filesize: %u\n", filesize); |
159 | 13.8k | if (!filesize) |
160 | 7.84k | continue; |
161 | | |
162 | 6.00k | status = cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0); |
163 | 6.00k | if (status != CL_SUCCESS) { |
164 | 0 | goto done; |
165 | 0 | } |
166 | | |
167 | 6.00k | if ((EC16(hdr_old.mode, conv) & 0170000) != 0100000) { |
168 | 5.40k | cli_dbgmsg("CPIO: Not a regular file, skipping\n"); |
169 | 5.40k | } else { |
170 | 602 | status = cli_magic_scan_nested_fmap_type(ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, fmap_name, LAYER_ATTRIBUTES_NONE); |
171 | 602 | if (status != CL_SUCCESS) { |
172 | 29 | goto done; |
173 | 29 | } |
174 | 602 | } |
175 | 5.97k | if (filesize % 2) { |
176 | 4.18k | filesize++; |
177 | 4.18k | } |
178 | | |
179 | 5.97k | pos += filesize; |
180 | 5.97k | } |
181 | | |
182 | 22.0k | done: |
183 | | |
184 | 22.0k | return status; |
185 | 22.0k | } |
186 | | |
187 | | cl_error_t cli_scancpio_odc(cli_ctx *ctx) |
188 | 26.5k | { |
189 | 26.5k | cl_error_t status = CL_SUCCESS; |
190 | 26.5k | struct cpio_hdr_odc hdr_odc; |
191 | 26.5k | char name[513] = {0}, buff[12] = {0}; |
192 | 26.5k | unsigned int file = 0, trailer = 0; |
193 | 26.5k | uint32_t filesize = 0, namesize = 0, hdr_namesize = 0; |
194 | 26.5k | size_t pos = 0; |
195 | | |
196 | 26.5k | memset(&hdr_odc, 0, sizeof(hdr_odc)); |
197 | | |
198 | 37.3k | while (fmap_readn(ctx->fmap, &hdr_odc, pos, sizeof(hdr_odc)) == sizeof(hdr_odc)) { |
199 | 29.3k | pos += sizeof(hdr_odc); |
200 | 29.3k | if (!hdr_odc.magic[0] && trailer) { |
201 | 0 | status = CL_SUCCESS; |
202 | 0 | goto done; |
203 | 0 | } |
204 | | |
205 | 29.3k | if (strncmp(hdr_odc.magic, "070707", 6)) { |
206 | 3.54k | cli_dbgmsg("cli_scancpio_odc: Invalid magic string\n"); |
207 | 3.54k | status = CL_EFORMAT; |
208 | 3.54k | goto done; |
209 | 3.54k | } |
210 | | |
211 | 25.7k | cli_dbgmsg("CPIO: -- File %u --\n", ++file); |
212 | | |
213 | 25.7k | strncpy(buff, hdr_odc.namesize, 6); |
214 | 25.7k | buff[6] = 0; |
215 | 25.7k | if (sscanf(buff, "%o", &hdr_namesize) != 1) { |
216 | 10.2k | cli_dbgmsg("cli_scancpio_odc: Can't convert name size\n"); |
217 | 10.2k | status = CL_EFORMAT; |
218 | 10.2k | goto done; |
219 | 10.2k | } |
220 | 15.4k | if (hdr_namesize) { |
221 | 12.2k | namesize = MIN(sizeof(name), hdr_namesize); |
222 | 12.2k | if (fmap_readn(ctx->fmap, &name, pos, namesize) != namesize) { |
223 | 1.19k | cli_dbgmsg("cli_scancpio_odc: Can't read file name\n"); |
224 | 1.19k | status = CL_EFORMAT; |
225 | 1.19k | goto done; |
226 | 1.19k | } |
227 | 11.0k | pos += namesize; |
228 | 11.0k | name[namesize - 1] = 0; |
229 | 11.0k | sanitname(name); |
230 | 11.0k | cli_dbgmsg("CPIO: Name: %s\n", name); |
231 | 11.0k | if (!strcmp(name, "TRAILER!!!")) { |
232 | 0 | trailer = 1; |
233 | 0 | } |
234 | | |
235 | 11.0k | if (namesize < hdr_namesize) { |
236 | 6.58k | pos += hdr_namesize - namesize; |
237 | 6.58k | } |
238 | 11.0k | } |
239 | | |
240 | 14.2k | strncpy(buff, hdr_odc.filesize, 11); |
241 | 14.2k | buff[11] = 0; |
242 | 14.2k | if (sscanf(buff, "%o", &filesize) != 1) { |
243 | 3.27k | cli_dbgmsg("cli_scancpio_odc: Can't convert file size\n"); |
244 | 3.27k | status = CL_EFORMAT; |
245 | 3.27k | goto done; |
246 | 3.27k | } |
247 | 11.0k | cli_dbgmsg("CPIO: Filesize: %u\n", filesize); |
248 | 11.0k | if (!filesize) { |
249 | 2.31k | continue; |
250 | 2.31k | } |
251 | | |
252 | 8.70k | status = cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0); |
253 | 8.70k | if (status == CL_VIRUS) { |
254 | 0 | goto done; |
255 | 0 | } |
256 | | |
257 | 8.70k | status = cli_magic_scan_nested_fmap_type(ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, name, LAYER_ATTRIBUTES_NONE); |
258 | 8.70k | if (status != CL_SUCCESS) { |
259 | 281 | goto done; |
260 | 281 | } |
261 | | |
262 | 8.42k | pos += filesize; |
263 | 8.42k | } |
264 | | |
265 | 26.5k | done: |
266 | | |
267 | 26.5k | return status; |
268 | 26.5k | } |
269 | | |
270 | | cl_error_t cli_scancpio_newc(cli_ctx *ctx, int crc) |
271 | 49.6k | { |
272 | 49.6k | cl_error_t status = CL_SUCCESS; |
273 | 49.6k | struct cpio_hdr_newc hdr_newc; |
274 | 49.6k | char name[513], buff[9]; |
275 | 49.6k | unsigned int file = 0, trailer = 0; |
276 | 49.6k | uint32_t filesize, namesize, hdr_namesize, pad; |
277 | 49.6k | size_t pos = 0; |
278 | | |
279 | 49.6k | memset(name, 0, 513); |
280 | | |
281 | 60.0k | while (fmap_readn(ctx->fmap, &hdr_newc, pos, sizeof(hdr_newc)) == sizeof(hdr_newc)) { |
282 | 46.4k | pos += sizeof(hdr_newc); |
283 | 46.4k | if (!hdr_newc.magic[0] && trailer) { |
284 | 4 | status = CL_SUCCESS; |
285 | 4 | goto done; |
286 | 4 | } |
287 | | |
288 | 46.4k | if ((!crc && strncmp(hdr_newc.magic, "070701", 6)) || (crc && strncmp(hdr_newc.magic, "070702", 6))) { |
289 | 2.88k | cli_dbgmsg("cli_scancpio_newc: Invalid magic string\n"); |
290 | 2.88k | status = CL_EFORMAT; |
291 | 2.88k | goto done; |
292 | 2.88k | } |
293 | | |
294 | 43.5k | cli_dbgmsg("CPIO: -- File %u --\n", ++file); |
295 | | |
296 | 43.5k | strncpy(buff, hdr_newc.namesize, 8); |
297 | 43.5k | buff[8] = 0; |
298 | 43.5k | if (sscanf(buff, "%x", &hdr_namesize) != 1) { |
299 | 23.1k | cli_dbgmsg("cli_scancpio_newc: Can't convert name size\n"); |
300 | 23.1k | status = CL_EFORMAT; |
301 | 23.1k | goto done; |
302 | 23.1k | } |
303 | 20.3k | if (hdr_namesize) { |
304 | 20.2k | namesize = MIN(sizeof(name), hdr_namesize); |
305 | 20.2k | if (fmap_readn(ctx->fmap, &name, pos, namesize) != namesize) { |
306 | 5.05k | cli_dbgmsg("cli_scancpio_newc: Can't read file name\n"); |
307 | 5.05k | status = CL_EFORMAT; |
308 | 5.05k | goto done; |
309 | 5.05k | } |
310 | 15.1k | pos += namesize; |
311 | 15.1k | name[namesize - 1] = 0; |
312 | 15.1k | sanitname(name); |
313 | 15.1k | cli_dbgmsg("CPIO: Name: %s\n", name); |
314 | 15.1k | if (!strcmp(name, "TRAILER!!!")) { |
315 | 4 | trailer = 1; |
316 | 4 | } |
317 | | |
318 | 15.1k | pad = (4 - (sizeof(hdr_newc) + hdr_namesize) % 4) % 4; |
319 | 15.1k | if (namesize < hdr_namesize) { |
320 | 7.30k | if (pad) { |
321 | 4.99k | hdr_namesize += pad; |
322 | 4.99k | } |
323 | 7.30k | pos += hdr_namesize - namesize; |
324 | 7.86k | } else if (pad) { |
325 | 6.43k | pos += pad; |
326 | 6.43k | } |
327 | 15.1k | } |
328 | | |
329 | 15.3k | strncpy(buff, hdr_newc.filesize, 8); |
330 | 15.3k | buff[8] = 0; |
331 | 15.3k | if (sscanf(buff, "%x", &filesize) != 1) { |
332 | 4.01k | cli_dbgmsg("cli_scancpio_newc: Can't convert file size\n"); |
333 | 4.01k | status = CL_EFORMAT; |
334 | 4.01k | goto done; |
335 | 4.01k | } |
336 | 11.3k | cli_dbgmsg("CPIO: Filesize: %u\n", filesize); |
337 | 11.3k | if (!filesize) { |
338 | 654 | continue; |
339 | 654 | } |
340 | | |
341 | 10.6k | status = cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0); |
342 | 10.6k | if (status == CL_VIRUS) { |
343 | 0 | goto done; |
344 | 0 | } |
345 | | |
346 | 10.6k | status = cli_magic_scan_nested_fmap_type(ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, name, LAYER_ATTRIBUTES_NONE); |
347 | 10.6k | if (status != CL_SUCCESS) { |
348 | 827 | goto done; |
349 | 827 | } |
350 | | |
351 | 9.82k | if ((pad = filesize % 4)) { |
352 | 7.76k | filesize += (4 - pad); |
353 | 7.76k | } |
354 | | |
355 | 9.82k | pos += filesize; |
356 | 9.82k | } |
357 | | |
358 | 49.6k | done: |
359 | | |
360 | 49.6k | return status; |
361 | 49.6k | } |