Coverage Report

Created: 2024-05-20 06:31

/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
}