Coverage Report

Created: 2023-12-08 06:48

/src/clamav/libclamav/matcher.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (C) 2013-2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3
 *  Copyright (C) 2007-2013 Sourcefire, Inc.
4
 *
5
 *  Authors: Tomasz Kojm
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 <string.h>
27
#include <ctype.h>
28
#include <sys/types.h>
29
#include <sys/stat.h>
30
#ifdef HAVE_UNISTD_H
31
#include <unistd.h>
32
#endif
33
#include <stdbool.h>
34
35
#include "clamav.h"
36
#include "clamav_rust.h"
37
#include "others.h"
38
#include "matcher-ac.h"
39
#include "matcher-bm.h"
40
#include "matcher-pcre.h"
41
#include "filetypes.h"
42
#include "matcher.h"
43
#include "pe.h"
44
#include "elf.h"
45
#include "execs.h"
46
#include "special.h"
47
#include "scanners.h"
48
#include "str.h"
49
#include "default.h"
50
#include "macho.h"
51
#include "fmap.h"
52
#include "pe_icons.h"
53
#include "regex/regex.h"
54
#include "filtering.h"
55
#include "perflogging.h"
56
#include "bytecode_priv.h"
57
#include "bytecode_api_impl.h"
58
#ifdef HAVE_YARA
59
#include "yara_clam.h"
60
#include "yara_exec.h"
61
#endif
62
63
#ifdef CLI_PERF_LOGGING
64
65
static inline void perf_log_filter(int32_t pos, int32_t length, int8_t trie)
66
{
67
    cli_perf_log_add(RAW_BYTES_SCANNED, length);
68
    cli_perf_log_add(FILTER_BYTES_SCANNED, length - pos);
69
    cli_perf_log_count2(TRIE_SCANNED, trie, length - pos);
70
}
71
72
static inline int perf_log_tries(int8_t acmode, int8_t bm_called, int32_t length)
73
{
74
    if (bm_called)
75
        cli_perf_log_add(BM_SCANNED, length);
76
    if (acmode)
77
        cli_perf_log_add(AC_SCANNED, length);
78
    return 0;
79
}
80
81
#else
82
static inline void perf_log_filter(int32_t pos, uint32_t length, int8_t trie)
83
26.4M
{
84
26.4M
    UNUSEDPARAM(pos);
85
26.4M
    UNUSEDPARAM(length);
86
26.4M
    UNUSEDPARAM(trie);
87
26.4M
}
88
89
static inline int perf_log_tries(int8_t acmode, int8_t bm_called, int32_t length)
90
42.9M
{
91
42.9M
    UNUSEDPARAM(acmode);
92
42.9M
    UNUSEDPARAM(bm_called);
93
42.9M
    UNUSEDPARAM(length);
94
95
42.9M
    return 0;
96
42.9M
}
97
#endif
98
99
static inline cl_error_t matcher_run(const struct cli_matcher *root,
100
                                     const unsigned char *buffer, uint32_t length,
101
                                     const char **virname, struct cli_ac_data *mdata,
102
                                     uint32_t offset,
103
                                     const struct cli_target_info *tinfo,
104
                                     cli_file_t ftype,
105
                                     struct cli_matched_type **ftoffset,
106
                                     unsigned int acmode,
107
                                     unsigned int pcremode,
108
                                     struct cli_ac_result **acres,
109
                                     fmap_t *map,
110
                                     struct cli_bm_off *offdata,
111
                                     struct cli_pcre_off *poffdata,
112
                                     cli_ctx *ctx)
113
26.4M
{
114
26.4M
    cl_error_t ret, saved_ret = CL_CLEAN;
115
26.4M
    int32_t pos = 0;
116
26.4M
    struct filter_match_info info;
117
26.4M
    uint32_t orig_length, orig_offset;
118
26.4M
    const unsigned char *orig_buffer;
119
120
26.4M
    if (root->filter) {
121
18.8M
        if (filter_search_ext(root->filter, buffer, length, &info) == -1) {
122
            /*  for safety always scan last maxpatlen bytes */
123
6.72M
            pos = length - root->maxpatlen - 1;
124
6.72M
            if (pos < 0) pos = 0;
125
6.72M
            perf_log_filter(pos, length, root->type);
126
12.1M
        } else {
127
            /* must not cut buffer for 64[4-4]6161, because we must be able to check
128
             * 64! */
129
12.1M
            pos = info.first_match - root->maxpatlen - 1;
130
12.1M
            if (pos < 0) pos = 0;
131
12.1M
            perf_log_filter(pos, length, root->type);
132
12.1M
        }
133
18.8M
    } else {
134
7.62M
        perf_log_filter(0, length, root->type);
135
7.62M
    }
136
137
26.4M
    orig_length = length;
138
26.4M
    orig_buffer = buffer;
139
26.4M
    orig_offset = offset;
140
26.4M
    length -= pos;
141
26.4M
    buffer += pos;
142
26.4M
    offset += pos;
143
26.4M
    if (!root->ac_only) {
144
16.5M
        perf_log_tries(0, 1, length);
145
16.5M
        if (root->bm_offmode) {
146
            /* Don't use prefiltering for BM offset mode, since BM keeps tracks
147
             * of offsets itself, and doesn't work if we skip chunks of input
148
             * data */
149
569k
            ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, ctx);
150
15.9M
        } else {
151
15.9M
            ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, ctx);
152
15.9M
        }
153
16.5M
        if (ret != CL_SUCCESS) {
154
0
            if (ret != CL_VIRUS)
155
0
                return ret;
156
            /* else (ret == CL_VIRUS) */
157
158
0
            ret = cli_append_virus(ctx, *virname);
159
0
            if (ret != CL_SUCCESS)
160
0
                return ret;
161
0
        }
162
16.5M
    }
163
26.4M
    perf_log_tries(acmode, 0, length);
164
26.4M
    ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, ctx);
165
26.4M
    if (ret != CL_SUCCESS) {
166
6.58M
        if (ret == CL_VIRUS) {
167
0
            ret = cli_append_virus(ctx, *virname);
168
0
            if (ret != CL_SUCCESS)
169
0
                return ret;
170
6.58M
        } else if (ret > CL_TYPENO && acmode & AC_SCAN_VIR) {
171
6.58M
            saved_ret = ret;
172
6.58M
        } else {
173
0
            return ret;
174
0
        }
175
6.58M
    }
176
177
26.4M
    if (root->bcomp_metas) {
178
0
        ret = cli_bcomp_scanbuf(orig_buffer, orig_length, acres, root, mdata, ctx);
179
0
        if (ret != CL_CLEAN) {
180
0
            if (ret > CL_TYPENO && acmode & AC_SCAN_VIR) {
181
0
                saved_ret = ret;
182
0
            } else {
183
0
                return ret;
184
0
            }
185
0
        }
186
0
    }
187
188
26.4M
    switch (ftype) {
189
739k
        case CL_TYPE_GIF:
190
980k
        case CL_TYPE_TIFF:
191
3.05M
        case CL_TYPE_JPEG:
192
3.37M
        case CL_TYPE_PNG:
193
3.38M
        case CL_TYPE_GRAPHICS: {
194
3.38M
            if (ctx->recursion_stack[ctx->recursion_level].calculated_image_fuzzy_hash &&
195
3.38M
                !fuzzy_hash_check(root->fuzzy_hashmap, mdata, ctx->recursion_stack[ctx->recursion_level].image_fuzzy_hash)) {
196
0
                cli_errmsg("Unexpected error when checking for fuzzy hash matches.\n");
197
0
                return CL_ERROR;
198
0
            }
199
3.38M
        }
200
26.4M
        default:
201
26.4M
            break;
202
26.4M
    }
203
204
26.4M
#if HAVE_PCRE
205
    /* due to logical triggered, pcres cannot be evaluated until after full subsig matching */
206
    /* cannot save pcre execution state without possible evasion; must scan entire buffer */
207
    /* however, scanning the whole buffer may require the whole buffer being loaded into memory */
208
26.4M
    if (root->pcre_metas) {
209
0
        int rc;
210
0
        uint64_t maxfilesize;
211
212
0
        if (map && (pcremode == PCRE_SCAN_FMAP)) {
213
0
            if (offset + length >= map->len) {
214
                /* check that scanned map does not exceed pcre maxfilesize limit */
215
0
                maxfilesize = (uint64_t)cl_engine_get_num(ctx->engine, CL_ENGINE_PCRE_MAX_FILESIZE, &rc);
216
0
                if (rc != CL_SUCCESS)
217
0
                    return rc;
218
0
                if (maxfilesize && (map->len > maxfilesize)) {
219
0
                    cli_dbgmsg("matcher_run: pcre max filesize (map) exceeded (limit: %llu, needed: %llu)\n",
220
0
                               (long long unsigned)maxfilesize, (long long unsigned)map->len);
221
0
                    return CL_EMAXSIZE;
222
0
                }
223
224
0
                cli_dbgmsg("matcher_run: performing regex matching on full map: %u+%u(%u) >= %zu\n", offset, length, offset + length, map->len);
225
226
0
                buffer = fmap_need_off_once(map, 0, map->len);
227
0
                if (!buffer)
228
0
                    return CL_EMEM;
229
230
                /* scan the full buffer */
231
0
                ret = cli_pcre_scanbuf(buffer, map->len, virname, acres, root, mdata, poffdata, ctx);
232
0
            }
233
0
        } else if (pcremode == PCRE_SCAN_BUFF) {
234
            /* check that scanned buffer does not exceed pcre maxfilesize limit */
235
0
            maxfilesize = (uint64_t)cl_engine_get_num(ctx->engine, CL_ENGINE_PCRE_MAX_FILESIZE, &rc);
236
0
            if (rc != CL_SUCCESS)
237
0
                return rc;
238
0
            if (maxfilesize && (length > maxfilesize)) {
239
0
                cli_dbgmsg("matcher_run: pcre max filesize (buf) exceeded (limit: %llu, needed: %u)\n", (long long unsigned)maxfilesize, length);
240
0
                return CL_EMAXSIZE;
241
0
            }
242
243
0
            cli_dbgmsg("matcher_run: performing regex matching on buffer with no map: %u+%u(%u)\n", offset, length, offset + length);
244
            /* scan the specified buffer */
245
0
            ret = cli_pcre_scanbuf(buffer, length, virname, acres, root, mdata, poffdata, ctx);
246
0
        }
247
0
    }
248
26.4M
#endif /* HAVE_PCRE */
249
    /* end experimental fragment */
250
251
26.4M
    if (ctx && ret == CL_VIRUS) {
252
0
        ret = cli_append_virus(ctx, *virname);
253
0
        if (ret != CL_SUCCESS)
254
0
            return ret;
255
0
    }
256
257
26.4M
    if (saved_ret && ret == CL_CLEAN) {
258
0
        return saved_ret;
259
0
    }
260
261
26.4M
    return ret;
262
26.4M
}
263
264
cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
265
284k
{
266
284k
    cl_error_t ret = CL_CLEAN;
267
284k
    unsigned int i = 0, j = 0;
268
284k
    struct cli_ac_data matcher_data;
269
284k
    struct cli_matcher *generic_ac_root, *target_ac_root = NULL;
270
284k
    const char *virname            = NULL;
271
284k
    const struct cl_engine *engine = ctx->engine;
272
273
284k
    if (!engine) {
274
0
        cli_errmsg("cli_scan_buff: engine == NULL\n");
275
0
        return CL_ENULLARG;
276
0
    }
277
278
284k
    generic_ac_root = engine->root[0]; /* generic signatures */
279
280
284k
    if (ftype != CL_TYPE_ANY) {
281
        // Identify the target type, to find the matcher root for that target.
282
283
1.97M
        for (i = 1; i < CLI_MTARGETS; i++) {
284
4.79M
            for (j = 0; j < cli_mtargets[i].target_count; ++j) {
285
3.09M
                if (cli_mtargets[i].target[j] == ftype) {
286
                    // Identified the target type, now get the matcher root for that target.
287
284k
                    target_ac_root = ctx->engine->root[i];
288
284k
                    break; // Break out of inner loop
289
284k
                }
290
3.09M
            }
291
1.97M
            if (target_ac_root) break;
292
1.97M
        }
293
284k
    }
294
295
284k
    if (target_ac_root) {
296
        /* If a target-specific specific signature root was found for the given file type, match with it. */
297
298
284k
        if (!acdata) {
299
            // no ac matcher data was provided, so we need to initialize our own.
300
0
            ret = cli_ac_initdata(&matcher_data, target_ac_root->ac_partsigs, target_ac_root->ac_lsigs, target_ac_root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
301
0
            if (CL_SUCCESS != ret) {
302
0
                return ret;
303
0
            }
304
0
        }
305
306
284k
        ret = matcher_run(target_ac_root, buffer, length, &virname,
307
284k
                          acdata ? (acdata[0]) : (&matcher_data),
308
284k
                          offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, ctx->fmap, NULL, NULL, ctx);
309
310
284k
        if (!acdata) {
311
            // no longer need our AC local matcher data (if using)
312
0
            cli_ac_freedata(&matcher_data);
313
0
        }
314
315
284k
        if (ret == CL_EMEM || ret == CL_VIRUS) {
316
0
            return ret;
317
0
        }
318
319
        // reset virname back to NULL for matching with the generic AC root.
320
284k
        virname = NULL;
321
284k
    }
322
323
284k
    if (!acdata) {
324
        // no ac matcher data was provided, so we need to initialize our own.
325
0
        ret = cli_ac_initdata(&matcher_data, generic_ac_root->ac_partsigs, generic_ac_root->ac_lsigs, generic_ac_root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
326
0
        if (CL_SUCCESS != ret) {
327
0
            return ret;
328
0
        }
329
0
    }
330
331
284k
    ret = matcher_run(generic_ac_root, buffer, length, &virname,
332
284k
                      acdata ? (acdata[1]) : (&matcher_data),
333
284k
                      offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, ctx->fmap, NULL, NULL, ctx);
334
335
284k
    if (!acdata) {
336
        // no longer need our AC local matcher data (if using)
337
0
        cli_ac_freedata(&matcher_data);
338
0
    }
339
340
284k
    return ret;
341
284k
}
342
343
/*
344
 * offdata[0]: type
345
 * offdata[1]: offset value
346
 * offdata[2]: max shift
347
 * offdata[3]: section number
348
 */
349
cl_error_t cli_caloff(const char *offstr, const struct cli_target_info *info, cli_target_t target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
350
18.1M
{
351
18.1M
    char offcpy[65] = {0};
352
18.1M
    unsigned int n = 0, val = 0;
353
18.1M
    char *pt = NULL;
354
355
18.1M
    if (!info) { /* decode offset string */
356
2.91M
        if (!offstr) {
357
0
            cli_errmsg("cli_caloff: offstr == NULL\n");
358
0
            return CL_ENULLARG;
359
0
        }
360
361
2.91M
        if (!strcmp(offstr, "*")) {
362
1.17M
            offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY;
363
1.17M
            return CL_SUCCESS;
364
1.17M
        }
365
366
1.73M
        if (strlen(offstr) > 64) {
367
14
            cli_errmsg("cli_caloff: Offset string too long\n");
368
14
            return CL_EMALFDB;
369
14
        }
370
1.73M
        strcpy(offcpy, offstr);
371
372
1.73M
        if ((pt = strchr(offcpy, ','))) {
373
646k
            if (!cli_isnumber(pt + 1)) {
374
3
                cli_errmsg("cli_caloff: Invalid offset shift value\n");
375
3
                return CL_EMALFDB;
376
3
            }
377
646k
            offdata[2] = atoi(pt + 1);
378
646k
            *pt        = 0;
379
1.09M
        } else {
380
1.09M
            offdata[2] = 0;
381
1.09M
        }
382
383
1.73M
        *offset_max = *offset_min = CLI_OFF_NONE;
384
385
1.73M
        if (!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) {
386
21.6k
            if (offcpy[2] == '+')
387
2.87k
                offdata[0] = CLI_OFF_EP_PLUS;
388
18.7k
            else
389
18.7k
                offdata[0] = CLI_OFF_EP_MINUS;
390
391
21.6k
            if (!cli_isnumber(&offcpy[3])) {
392
5
                cli_errmsg("cli_caloff: Invalid offset value\n");
393
5
                return CL_EMALFDB;
394
5
            }
395
21.6k
            offdata[1] = atoi(&offcpy[3]);
396
397
1.71M
        } else if (offcpy[0] == 'S') {
398
6.20k
            if (offcpy[1] == 'E') {
399
1.67k
                if (!cli_isnumber(&offcpy[2])) {
400
4
                    cli_errmsg("cli_caloff: Invalid section number\n");
401
4
                    return CL_EMALFDB;
402
4
                }
403
1.67k
                offdata[0] = CLI_OFF_SE;
404
1.67k
                offdata[3] = atoi(&offcpy[2]);
405
406
4.52k
            } else if (!strncmp(offstr, "SL+", 3)) {
407
1.52k
                offdata[0] = CLI_OFF_SL_PLUS;
408
1.52k
                if (!cli_isnumber(&offcpy[3])) {
409
3
                    cli_errmsg("cli_caloff: Invalid offset value\n");
410
3
                    return CL_EMALFDB;
411
3
                }
412
1.52k
                offdata[1] = atoi(&offcpy[3]);
413
414
3.00k
            } else if (sscanf(offcpy, "S%u+%u", &n, &val) == 2) {
415
2.96k
                offdata[0] = CLI_OFF_SX_PLUS;
416
2.96k
                offdata[1] = val;
417
2.96k
                offdata[3] = n;
418
2.96k
            } else {
419
38
                cli_errmsg("cli_caloff: Invalid offset string\n");
420
38
                return CL_EMALFDB;
421
38
            }
422
423
1.71M
        } else if (!strncmp(offcpy, "EOF-", 4)) {
424
167k
            offdata[0] = CLI_OFF_EOF_MINUS;
425
167k
            if (!cli_isnumber(&offcpy[4])) {
426
3
                cli_errmsg("cli_caloff: Invalid offset value\n");
427
3
                return CL_EMALFDB;
428
3
            }
429
167k
            offdata[1] = atoi(&offcpy[4]);
430
1.54M
        } else if (!strncmp(offcpy, "VI", 2)) {
431
            /* versioninfo */
432
30.4k
            offdata[0] = CLI_OFF_VERSION;
433
1.51M
        } else if (strchr(offcpy, '$')) {
434
1.15k
            if (sscanf(offcpy, "$%u$", &n) != 1) {
435
24
                cli_errmsg("cli_caloff: Invalid macro($) in offset: %s\n", offcpy);
436
24
                return CL_EMALFDB;
437
24
            }
438
1.13k
            if (n >= 32) {
439
95
                cli_errmsg("cli_caloff: at most 32 macro groups supported\n");
440
95
                return CL_EMALFDB;
441
95
            }
442
1.03k
            offdata[0] = CLI_OFF_MACRO;
443
1.03k
            offdata[1] = n;
444
1.51M
        } else {
445
1.51M
            offdata[0] = CLI_OFF_ABSOLUTE;
446
1.51M
            if (!cli_isnumber(offcpy)) {
447
162
                cli_errmsg("cli_caloff: Invalid offset value\n");
448
162
                return CL_EMALFDB;
449
162
            }
450
1.51M
            *offset_min = offdata[1] = atoi(offcpy);
451
1.51M
            *offset_max              = *offset_min + offdata[2];
452
1.51M
        }
453
454
1.73M
        if (offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE &&
455
1.73M
            offdata[0] != CLI_OFF_EOF_MINUS && offdata[0] != CLI_OFF_MACRO) {
456
58.2k
            if (target != TARGET_PE && target != TARGET_ELF && target != TARGET_MACHO) {
457
17
                cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target);
458
17
                return CL_EMALFDB;
459
17
            }
460
58.2k
        }
461
462
15.2M
    } else {
463
        /* calculate relative offsets */
464
15.2M
        *offset_min = CLI_OFF_NONE;
465
15.2M
        if (offset_max)
466
15.2M
            *offset_max = CLI_OFF_NONE;
467
15.2M
        if (info->status == -1) {
468
            // If the executable headers weren't parsed successfully then we
469
            // can't process any ndb/ldb EOF-n/EP+n/EP-n/Sx+n/SEx/SL+n subsigs
470
2.52M
            return CL_SUCCESS;
471
2.52M
        }
472
473
12.6M
        switch (offdata[0]) {
474
12.6M
            case CLI_OFF_EOF_MINUS:
475
12.6M
                *offset_min = info->fsize - offdata[1];
476
12.6M
                break;
477
478
0
            case CLI_OFF_EP_PLUS:
479
0
                *offset_min = info->exeinfo.ep + offdata[1];
480
0
                break;
481
482
0
            case CLI_OFF_EP_MINUS:
483
0
                *offset_min = info->exeinfo.ep - offdata[1];
484
0
                break;
485
486
0
            case CLI_OFF_SL_PLUS:
487
0
                *offset_min = info->exeinfo.sections[info->exeinfo.nsections - 1].raw + offdata[1];
488
0
                break;
489
490
0
            case CLI_OFF_SX_PLUS:
491
0
                if (offdata[3] >= info->exeinfo.nsections)
492
0
                    *offset_min = CLI_OFF_NONE;
493
0
                else
494
0
                    *offset_min = info->exeinfo.sections[offdata[3]].raw + offdata[1];
495
0
                break;
496
497
0
            case CLI_OFF_SE:
498
0
                if (offdata[3] >= info->exeinfo.nsections) {
499
0
                    *offset_min = CLI_OFF_NONE;
500
0
                } else {
501
0
                    *offset_min = info->exeinfo.sections[offdata[3]].raw;
502
0
                    if (offset_max)
503
0
                        *offset_max = *offset_min + info->exeinfo.sections[offdata[3]].rsz + offdata[2];
504
                    // TODO offdata[2] == MaxShift. Won't this make offset_max
505
                    // extend beyond the end of the section?  This doesn't seem like
506
                    // what we want...
507
0
                }
508
0
                break;
509
510
0
            case CLI_OFF_VERSION:
511
0
                if (offset_max)
512
0
                    *offset_min = *offset_max = CLI_OFF_ANY;
513
0
                break;
514
0
            default:
515
0
                cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]);
516
0
                return CL_EARG;
517
12.6M
        }
518
519
12.6M
        if (offset_max && *offset_max == CLI_OFF_NONE && *offset_min != CLI_OFF_NONE)
520
12.6M
            *offset_max = *offset_min + offdata[2];
521
12.6M
    }
522
523
14.4M
    return CL_SUCCESS;
524
18.1M
}
525
526
void cli_targetinfo_init(struct cli_target_info *info)
527
15.4M
{
528
529
15.4M
    if (NULL == info) {
530
0
        return;
531
0
    }
532
15.4M
    info->status = 0;
533
15.4M
    cli_exe_info_init(&(info->exeinfo), 0);
534
15.4M
}
535
536
void cli_targetinfo(struct cli_target_info *info, cli_target_t target, cli_ctx *ctx)
537
15.4M
{
538
15.4M
    cl_error_t (*einfo)(cli_ctx *, struct cli_exe_info *) = NULL;
539
540
15.4M
    info->fsize = ctx->fmap->len;
541
542
15.4M
    switch (target) {
543
406k
        case TARGET_PE:
544
406k
            einfo = cli_pe_targetinfo;
545
406k
            break;
546
119k
        case TARGET_ELF:
547
119k
            einfo = cli_elfheader;
548
119k
            break;
549
2.14M
        case TARGET_MACHO:
550
2.14M
            einfo = cli_machoheader;
551
2.14M
            break;
552
12.8M
        default:
553
12.8M
            return;
554
15.4M
    }
555
556
2.66M
    if (CL_SUCCESS != einfo(ctx, &info->exeinfo))
557
2.52M
        info->status = -1;
558
148k
    else
559
148k
        info->status = 1;
560
2.66M
}
561
562
void cli_targetinfo_destroy(struct cli_target_info *info)
563
15.4M
{
564
565
15.4M
    if (NULL == info) {
566
0
        return;
567
0
    }
568
569
15.4M
    cli_exe_info_destroy(&(info->exeinfo));
570
15.4M
    info->status = 0;
571
15.4M
}
572
573
cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname)
574
3.29M
{
575
3.29M
    cl_error_t status = CL_VIRUS;
576
3.29M
    char md5[33];
577
3.29M
    unsigned int i;
578
3.29M
    const char *virname = NULL;
579
3.29M
    fmap_t *map;
580
3.29M
    int32_t stack_index;
581
3.29M
    const char *ptr;
582
3.29M
    uint8_t shash1[SHA1_HASH_SIZE * 2 + 1];
583
3.29M
    uint8_t shash256[SHA256_HASH_SIZE * 2 + 1];
584
3.29M
    int have_sha1, have_sha256;
585
3.29M
    unsigned char *digest;
586
3.29M
    size_t size;
587
588
3.29M
    stack_index = (int32_t)ctx->recursion_level;
589
590
35.0M
    while (stack_index >= 0) {
591
31.7M
        map = ctx->recursion_stack[stack_index].fmap;
592
593
31.7M
        if (CL_SUCCESS != fmap_get_hash(map, &digest, CLI_HASH_MD5)) {
594
0
            cli_dbgmsg("cli_check_fp: Failed to get a hash for the map at stack index # %u\n", stack_index);
595
0
            stack_index--;
596
0
            continue;
597
0
        }
598
31.7M
        size = map->len;
599
600
        /*
601
         * First, check the MD5 digest.
602
         * MD5 is default, so it always exists.
603
         */
604
31.7M
        if (cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
605
0
            cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: %d\n", virname, (int)size);
606
0
            return CL_CLEAN;
607
31.7M
        } else if (cli_hm_scan_wild(digest, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
608
0
            cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: *\n", virname);
609
0
            return CL_CLEAN;
610
0
        }
611
612
31.7M
        if (cli_debug_flag || ctx->engine->cb_hash) {
613
0
            const char *name = ctx->recursion_stack[stack_index].fmap->name;
614
0
            const char *type = cli_ftname(ctx->recursion_stack[stack_index].type);
615
616
0
            for (i = 0; i < 16; i++)
617
0
                sprintf(md5 + i * 2, "%02x", digest[i]);
618
0
            md5[32] = 0;
619
620
0
            cli_dbgmsg("FP SIGNATURE: %s:%u:%s  # Name: %s, Type: %s\n",
621
0
                       md5, (unsigned int)size, vname ? vname : "Name", name ? name : "n/a", type);
622
0
        }
623
624
31.7M
        have_sha1   = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA1) || cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1);
625
31.7M
        have_sha256 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA256);
626
31.7M
        if (have_sha1 || have_sha256) {
627
0
            if ((ptr = fmap_need_off_once(map, 0, size))) {
628
0
                if (have_sha1) {
629
0
                    cl_sha1(ptr, size, &shash1[SHA1_HASH_SIZE], NULL);
630
631
0
                    if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
632
0
                        cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
633
0
                        return CL_CLEAN;
634
0
                    }
635
0
                    if (cli_hm_scan_wild(&shash1[SHA1_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
636
0
                        cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
637
0
                        return CL_CLEAN;
638
0
                    }
639
                    /* See whether the hash matches those loaded in from .cat files
640
                     * (associated with the .CAB file type) */
641
0
                    if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
642
0
                        cli_dbgmsg("cli_check_fp(sha1): Found .CAB false positive detection via catalog file\n");
643
0
                        return CL_CLEAN;
644
0
                    }
645
0
                }
646
647
0
                if (have_sha256) {
648
0
                    cl_sha256(ptr, size, &shash256[SHA256_HASH_SIZE], NULL);
649
650
0
                    if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
651
0
                        cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
652
0
                        return CL_CLEAN;
653
0
                    }
654
0
                    if (cli_hm_scan_wild(&shash256[SHA256_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
655
0
                        cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
656
0
                        return CL_CLEAN;
657
0
                    }
658
                    /* See whether the hash matches those loaded in from .cat files
659
                     * (associated with the .CAB file type) */
660
0
                    if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
661
0
                        cli_dbgmsg("cli_check_fp(sha256): Found .CAB false positive detection via catalog file\n");
662
0
                        return CL_CLEAN;
663
0
                    }
664
0
                }
665
0
            }
666
0
        }
667
668
#ifdef HAVE__INTERNAL__SHA_COLLECT
669
        if (SCAN_DEV_COLLECT_SHA && (ctx->sha_collect > 0)) {
670
            if ((ptr = fmap_need_off_once(map, 0, size))) {
671
                if (!have_sha256)
672
                    cl_sha256(ptr, size, shash256 + SHA256_HASH_SIZE, NULL);
673
674
                for (i = 0; i < SHA256_HASH_SIZE; i++)
675
                    sprintf((char *)shash256 + i * 2, "%02x", shash256[SHA256_HASH_SIZE + i]);
676
677
                if (!have_sha1)
678
                    cl_sha1(ptr, size, shash1 + SHA1_HASH_SIZE);
679
680
                for (i = 0; i < SHA1_HASH_SIZE; i++)
681
                    sprintf((char *)shash1 + i * 2, "%02x", shash1[SHA1_HASH_SIZE + i]);
682
683
                if (NULL == ctx->target_filepath) {
684
                    cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", "NO_IDEA");
685
                } else {
686
                    cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", ctx->target_filepath);
687
                }
688
            } else
689
                cli_errmsg("can't compute sha\n!");
690
691
            ctx->sha_collect = -1;
692
        }
693
#endif
694
695
31.7M
        if (ctx->engine->cb_hash)
696
0
            ctx->engine->cb_hash(fmap_fd(ctx->fmap), size, (const unsigned char *)md5, vname ? vname : "noname", ctx->cb_ctx);
697
698
31.7M
        if (ctx->engine->cb_stats_add_sample) {
699
0
            stats_section_t sections;
700
0
            memset(&sections, 0x00, sizeof(stats_section_t));
701
702
0
            if (!(ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_STATS) &&
703
0
                !(ctx->engine->dconf->stats & (DCONF_STATS_DISABLED | DCONF_STATS_PE_SECTION_DISABLED)))
704
0
                cli_genhash_pe(ctx, CL_GENHASH_PE_CLASS_SECTION, 1, &sections);
705
706
            // TODO We probably only want to call cb_stats_add_sample when
707
            // sections.section != NULL... leaving as is for now
708
0
            ctx->engine->cb_stats_add_sample(vname ? vname : "noname", digest, size, &sections, ctx->engine->stats_data);
709
710
0
            if (sections.sections) {
711
0
                free(sections.sections);
712
0
            }
713
0
        }
714
715
31.7M
        stack_index -= 1;
716
31.7M
    }
717
718
3.29M
    return status;
719
3.29M
}
720
721
static cl_error_t matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
722
0
{
723
0
    icon_groupset iconset;
724
725
0
    if (!ctx ||
726
0
        !ctx->engine ||
727
0
        !ctx->engine->iconcheck ||
728
0
        !ctx->engine->iconcheck->group_counts[0] ||
729
0
        !ctx->engine->iconcheck->group_counts[1] ||
730
0
        !exeinfo->res_addr) return CL_CLEAN;
731
732
0
    if (!(ctx->dconf->pe & PE_CONF_MATCHICON))
733
0
        return CL_CLEAN;
734
735
0
    cli_icongroupset_init(&iconset);
736
0
    cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
737
0
    cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
738
0
    return cli_scanicon(&iconset, ctx, exeinfo);
739
0
}
740
741
int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t grp1len,
742
                            const uint8_t *grp2, int32_t grp2len)
743
0
{
744
0
    cl_error_t ret;
745
0
    char group1[128], group2[128];
746
0
    struct cli_exe_info info;
747
748
    // TODO This isn't a good check, since EP will be zero for DLLs and
749
    // (assuming pedata->ep is populated from exeinfo->pe) non-zero for
750
    // some MachO and ELF executables
751
0
    if (!ctx->hooks.pedata->ep) {
752
0
        cli_dbgmsg("bytecode: matchicon only works with PE files\n");
753
0
        return -1;
754
0
    }
755
0
    if ((size_t)grp1len > sizeof(group1) - 1 ||
756
0
        (size_t)grp2len > sizeof(group2) - 1)
757
0
        return -1;
758
759
0
    memcpy(group1, grp1, grp1len);
760
0
    memcpy(group2, grp2, grp2len);
761
0
    group1[grp1len] = 0;
762
0
    group2[grp2len] = 0;
763
0
    memset(&info, 0, sizeof(info));
764
0
    if (ctx->bc->kind == BC_PE_UNPACKER || ctx->bc->kind == BC_PE_ALL) {
765
0
        if (le16_to_host(ctx->hooks.pedata->file_hdr.Characteristics) & 0x2000 ||
766
0
            !ctx->hooks.pedata->dirs[2].Size)
767
0
            info.res_addr = 0;
768
0
        else
769
0
            info.res_addr = ctx->hooks.pedata->dirs[2].VirtualAddress;
770
0
    } else
771
0
        info.res_addr = ctx->resaddr; /* from target_info */
772
0
    info.sections  = (struct cli_exe_section *)ctx->sections;
773
0
    info.nsections = ctx->hooks.pedata->nsections;
774
0
    info.hdr_size  = ctx->hooks.pedata->hdr_size;
775
0
    cli_dbgmsg("bytecode matchicon %s %s\n", group1, group2);
776
0
    ret = matchicon(ctx->ctx, &info, group1[0] ? group1 : NULL,
777
0
                    group2[0] ? group2 : NULL);
778
779
0
    return (int32_t)ret;
780
0
}
781
782
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, uint32_t attributes)
783
790k
{
784
790k
    cl_error_t status = CL_CLEAN;
785
790k
    int empty;
786
790k
    fmap_t *new_map = NULL;
787
788
790k
    new_map = fmap_check_empty(desc, 0, 0, &empty, name);
789
790k
    if (NULL == new_map) {
790
2
        if (!empty) {
791
0
            cli_dbgmsg("cli_scan_desc: Failed to allocate new map for file descriptor scan.\n");
792
0
            status = CL_EMEM;
793
0
        }
794
2
        goto done;
795
2
    }
796
797
790k
    status = cli_recursion_stack_push(ctx, new_map, ftype, true, attributes); /* Perform scan with child fmap */
798
790k
    if (CL_SUCCESS != status) {
799
8.28k
        cli_dbgmsg("cli_scan_desc: Failed to scan fmap.\n");
800
8.28k
        goto done;
801
8.28k
    }
802
803
781k
    status = cli_scan_fmap(ctx, ftype, filetype_only, ftoffset, acmode, acres, NULL);
804
805
781k
    (void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
806
807
790k
done:
808
790k
    if (NULL != new_map) {
809
790k
        funmap(new_map);
810
790k
    }
811
812
790k
    return status;
813
781k
}
814
815
static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
816
0
{
817
0
    uint32_t i, icnt = ac_lsig->tdb.intermediates[0];
818
819
    // -1 is the deepest layer (the current layer), so we start at -2, which is the first ancestor
820
0
    int32_t j = -2;
821
822
0
    if (ctx->recursion_level < icnt)
823
0
        return 0;
824
825
0
    for (i = icnt; i > 0; i--) {
826
0
        if (ac_lsig->tdb.intermediates[i] == CL_TYPE_ANY)
827
0
            continue;
828
0
        if (ac_lsig->tdb.intermediates[i] != cli_recursion_stack_get_type(ctx, j--))
829
0
            return 0;
830
0
    }
831
0
    return 1;
832
0
}
833
834
static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
835
0
{
836
0
    cl_error_t status           = CL_CLEAN;
837
0
    unsigned evalcnt            = 0;
838
0
    uint64_t evalids            = 0;
839
0
    fmap_t *new_map             = NULL;
840
0
    struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
841
0
    char *exp                   = ac_lsig->u.logic;
842
0
    char *exp_end               = exp + strlen(exp);
843
844
0
    status = cli_ac_chkmacro(root, acdata, lsid);
845
0
    if (status != CL_SUCCESS)
846
0
        return status;
847
848
0
    if (cli_ac_chklsig(exp, exp_end, acdata->lsigcnt[lsid], &evalcnt, &evalids, 0) != 1) {
849
        // Logical expression did not match.
850
0
        goto done;
851
0
    }
852
853
    // Logical expression matched.
854
    // Need to check the other conditions, like target description block, icon group, bytecode, etc.
855
856
    // If the lsig requires a specific container type, check if check that it matches
857
0
    if (ac_lsig->tdb.container &&
858
0
        ac_lsig->tdb.container[0] != cli_recursion_stack_get_type(ctx, -2)) {
859
        // So far the match is good, but the container type doesn't match.
860
        // Because this may need to match in a different scenario where the
861
        // container does match, we do not want to cache this result.
862
0
        ctx->fmap->dont_cache_flag = 1;
863
864
0
        goto done;
865
0
    }
866
867
    // If the lsig has intermediates, check if they match the current recursion stack
868
0
    if (ac_lsig->tdb.intermediates &&
869
0
        !intermediates_eval(ctx, ac_lsig)) {
870
        // So far the match is good, but the intermediates type(s) do not match.
871
        // Because this may need to match in a different scenario where the
872
        // intermediates do match, we do not want to cache this result.
873
0
        ctx->fmap->dont_cache_flag = 1;
874
875
0
        goto done;
876
0
    }
877
878
    // If the lsig has filesize requirements, check if they match
879
0
    if (ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > ctx->fmap->len || ac_lsig->tdb.filesize[1] < ctx->fmap->len)) {
880
0
        goto done;
881
0
    }
882
883
0
    if (ac_lsig->tdb.ep || ac_lsig->tdb.nos) {
884
0
        if (!target_info || target_info->status != 1)
885
0
            goto done;
886
0
        if (ac_lsig->tdb.ep && (ac_lsig->tdb.ep[0] > target_info->exeinfo.ep || ac_lsig->tdb.ep[1] < target_info->exeinfo.ep))
887
0
            goto done;
888
0
        if (ac_lsig->tdb.nos && (ac_lsig->tdb.nos[0] > target_info->exeinfo.nsections || ac_lsig->tdb.nos[1] < target_info->exeinfo.nsections))
889
0
            goto done;
890
0
    }
891
892
0
    if (ac_lsig->tdb.handlertype) {
893
        // This logical signature has a handler type, which means it's effectively a complex file type signature.
894
        // Instead of alerting, we'll make a duplicate fmap (add recursion depth, to prevent infinite loops) and
895
        // scan the file with the handler type.
896
897
0
        if (hash && 0 != memcmp(ctx->handlertype_hash, hash, 16)) {
898
            /*
899
             * Create an fmap window into our current fmap using the original offset & length, and rescan as the new type
900
             *
901
             * TODO: Unsure if creating an fmap is the right move, or if we should rescan with the current fmap as-is,
902
             * since it's not really a container so much as it is type reassignment. This new fmap layer protect against
903
             * a possible infinite loop by applying the scan recursion limit, but maybe there's a better way?
904
             * Testing with both HandlerType type reassignment sigs + Container/Intermediates sigs should indicate if
905
             * a change is needed.
906
             */
907
0
            new_map = fmap_duplicate(ctx->fmap, 0, ctx->fmap->len, ctx->fmap->name);
908
0
            if (NULL == new_map) {
909
0
                status = CL_EMEM;
910
0
                cli_dbgmsg("Failed to duplicate the current fmap for a re-scan as a different type.\n");
911
0
                goto done;
912
0
            }
913
914
0
            memcpy(ctx->handlertype_hash, hash, 16);
915
916
0
            status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true, LAYER_ATTRIBUTES_NONE); /* Perform scan with child fmap */
917
0
            if (CL_SUCCESS != status) {
918
0
                cli_dbgmsg("Failed to re-scan fmap as a new type.\n");
919
0
                goto done;
920
0
            }
921
922
0
            status = cli_magic_scan(ctx, ac_lsig->tdb.handlertype[0]);
923
924
0
            (void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
925
926
0
            goto done;
927
0
        }
928
0
    }
929
930
0
    if (ac_lsig->tdb.icongrp1 || ac_lsig->tdb.icongrp2) {
931
        // Logical sig depends on icon match. Check for the icon match.
932
933
0
        if (!target_info || target_info->status != TARGET_PE) {
934
            // Icon group feature only applies to PE files, so target description must match a PE file.
935
            // This is a signature issue and should have been caught at load time, but just in case, we're checking again here.
936
0
            goto done;
937
0
        }
938
939
0
        if (CL_VIRUS != matchicon(ctx, &target_info->exeinfo, ac_lsig->tdb.icongrp1, ac_lsig->tdb.icongrp2)) {
940
            // No icon match!
941
0
            goto done;
942
0
        }
943
0
    }
944
945
0
    if (!ac_lsig->bc_idx) {
946
        // Logical sig does not depend on bytecode match. Report the virus.
947
0
        status = cli_append_virus(ctx, ac_lsig->virname);
948
0
        if (status != CL_SUCCESS) {
949
0
            goto done;
950
0
        }
951
0
    } else {
952
        // Logical sig depends on bytecode match. Check for the bytecode match.
953
0
        status = cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], ctx->fmap);
954
0
        if (CL_SUCCESS != status) {
955
0
            goto done;
956
0
        }
957
958
        // Check time limit here, because bytecode functions may take a while.
959
0
        status = cli_checktimelimit(ctx);
960
0
        if (CL_SUCCESS != status) {
961
0
            goto done;
962
0
        }
963
0
    }
964
965
0
done:
966
0
    if (NULL != new_map) {
967
0
        free_duplicate_fmap(new_map);
968
0
    }
969
970
0
    return status;
971
0
}
972
973
#ifdef HAVE_YARA
974
static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
975
0
{
976
0
    struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
977
0
    cl_error_t rc;
978
0
    YR_SCAN_CONTEXT context;
979
980
0
    (void)hash;
981
982
0
    memset(&context, 0, sizeof(YR_SCAN_CONTEXT));
983
0
    context.fmap      = ctx->fmap;
984
0
    context.file_size = ctx->fmap->len;
985
0
    if (target_info != NULL) {
986
0
        if (target_info->status == 1)
987
0
            context.entry_point = target_info->exeinfo.ep;
988
0
    }
989
990
0
    rc = yr_execute_code(ac_lsig, acdata, &context, 0, 0);
991
992
0
    if (rc == CL_VIRUS) {
993
0
        if (ac_lsig->flag & CLI_LSIG_FLAG_PRIVATE) {
994
0
            rc = CL_CLEAN;
995
0
        } else {
996
0
            rc = cli_append_virus(ctx, ac_lsig->virname);
997
0
        }
998
0
    }
999
0
    return rc;
1000
0
}
1001
#endif
1002
1003
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
1004
25.6M
{
1005
25.6M
    uint32_t i;
1006
25.6M
    cl_error_t status = CL_SUCCESS;
1007
1008
25.6M
    for (i = 0; i < root->ac_lsigs; i++) {
1009
0
        if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL) {
1010
0
            status = lsig_eval(ctx, root, acdata, target_info, hash, i);
1011
0
        }
1012
0
#ifdef HAVE_YARA
1013
0
        else if (root->ac_lsigtable[i]->type == CLI_YARA_NORMAL || root->ac_lsigtable[i]->type == CLI_YARA_OFFSET) {
1014
0
            status = yara_eval(ctx, root, acdata, target_info, hash, i);
1015
0
        }
1016
0
#endif
1017
1018
0
        if (CL_SUCCESS != status) {
1019
0
            break;
1020
0
        }
1021
1022
0
        if (i % 10 == 0) {
1023
            // Check the time limit every n'th lsig.
1024
            // In testing with a large signature set, we found n = 10 to be just as fast as 100 or
1025
            // 1000 and has a significant performance improvement over checking with every lsig.
1026
0
            status = cli_checktimelimit(ctx);
1027
0
            if (CL_SUCCESS != status) {
1028
0
                cli_dbgmsg("Exceeded scan time limit while evaluating logical and yara signatures (max: %u)\n", ctx->engine->maxscantime);
1029
0
                break;
1030
0
            }
1031
0
        }
1032
0
    }
1033
1034
25.6M
    return status;
1035
25.6M
}
1036
1037
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
1038
15.2M
{
1039
15.2M
    const unsigned char *buff;
1040
15.2M
    cl_error_t ret = CL_CLEAN, type = CL_CLEAN;
1041
15.2M
    bool compute_hash[CLI_HASH_AVAIL_TYPES];
1042
15.2M
    unsigned int i = 0, j = 0;
1043
15.2M
    uint32_t maxpatlen, bytes, offset = 0;
1044
1045
15.2M
    struct cli_ac_data generic_ac_data;
1046
15.2M
    bool gdata_initialized = false;
1047
1048
15.2M
    struct cli_ac_data target_ac_data;
1049
15.2M
    bool tdata_initialized = false;
1050
1051
15.2M
    struct cli_bm_off bm_offsets_table;
1052
15.2M
    bool bm_offsets_table_initialized = false;
1053
1054
15.2M
    struct cli_pcre_off generic_pcre_offsets_table;
1055
15.2M
    bool generic_pcre_offsets_table_initialized = false;
1056
1057
15.2M
    struct cli_pcre_off target_pcre_offsets_table;
1058
15.2M
    bool target_pcre_offsets_table_initialized = false;
1059
1060
15.2M
    unsigned char digest[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
1061
1062
15.2M
    struct cli_matcher *generic_ac_root = NULL, *target_ac_root = NULL;
1063
1064
15.2M
    struct cli_target_info info;
1065
15.2M
    bool info_initialized = false;
1066
1067
15.2M
    struct cli_matcher *hdb, *fp;
1068
1069
15.2M
    void *md5ctx    = NULL;
1070
15.2M
    void *sha1ctx   = NULL;
1071
15.2M
    void *sha256ctx = NULL;
1072
1073
15.2M
    if (!ctx->engine) {
1074
0
        cli_errmsg("cli_scan_fmap: engine == NULL\n");
1075
0
        ret = CL_ENULLARG;
1076
0
        goto done;
1077
0
    }
1078
1079
15.2M
    md5ctx = cl_hash_init("md5");
1080
15.2M
    if (!(md5ctx)) {
1081
0
        ret = CL_EMEM;
1082
0
        goto done;
1083
0
    }
1084
1085
15.2M
    sha1ctx = cl_hash_init("sha1");
1086
15.2M
    if (!(sha1ctx)) {
1087
0
        ret = CL_EMEM;
1088
0
        goto done;
1089
0
    }
1090
1091
15.2M
    sha256ctx = cl_hash_init("sha256");
1092
15.2M
    if (!(sha256ctx)) {
1093
0
        ret = CL_EMEM;
1094
0
        goto done;
1095
0
    }
1096
1097
15.2M
    if (!filetype_only) {
1098
15.2M
        generic_ac_root = ctx->engine->root[0]; /* generic signatures */
1099
15.2M
    }
1100
1101
15.2M
    if (ftype != CL_TYPE_ANY) {
1102
        // Identify the target type, to find the matcher root for that target.
1103
1104
149M
        for (i = 1; i < CLI_MTARGETS; i++) {
1105
334M
            for (j = 0; j < cli_mtargets[i].target_count; ++j) {
1106
199M
                if (cli_mtargets[i].target[j] == ftype) {
1107
                    // Identified the target type, now get the matcher root for that target.
1108
9.87M
                    target_ac_root = ctx->engine->root[i];
1109
9.87M
                    break; // Break out of inner loop
1110
9.87M
                }
1111
199M
            }
1112
144M
            if (target_ac_root) break;
1113
144M
        }
1114
14.7M
    }
1115
1116
15.2M
    if (!generic_ac_root) {
1117
0
        if (!target_ac_root) {
1118
            // Don't have a matcher root for either generic signatures or target-specific signatures.
1119
            // Nothing to do!
1120
0
            ret = CL_CLEAN;
1121
0
            goto done;
1122
0
        }
1123
1124
        // Only have a matcher root for target-specific signatures.
1125
0
        maxpatlen = target_ac_root->maxpatlen;
1126
15.2M
    } else {
1127
15.2M
        if (target_ac_root) {
1128
            // Have both generic and target-specific signatures.
1129
9.87M
            maxpatlen = MAX(target_ac_root->maxpatlen, generic_ac_root->maxpatlen);
1130
9.87M
        } else {
1131
            // Only have generic signatures.
1132
5.34M
            maxpatlen = generic_ac_root->maxpatlen;
1133
5.34M
        }
1134
15.2M
    }
1135
1136
15.2M
    cli_targetinfo_init(&info);
1137
15.2M
    cli_targetinfo(&info, i, ctx);
1138
15.2M
    info_initialized = true;
1139
1140
15.2M
    if (-1 == info.status) {
1141
2.52M
        cli_dbgmsg("cli_scan_fmap: Failed to successfully parse the executable header. "
1142
2.52M
                   "Scan features will be disabled, such as "
1143
2.52M
                   "NDB/LDB subsigs using EOF-n/EP+n/EP-n/Sx+n/SEx/SL+n, "
1144
2.52M
                   "fuzzy icon matching, "
1145
2.52M
                   "MDB/IMP sigs, "
1146
2.52M
                   "and bytecode sigs that require exe metadata\n");
1147
2.52M
    }
1148
1149
    /* If it's a PE, check the Authenticode header.  This would be more
1150
     * appropriate in cli_scanpe, but scanraw->cli_scan_fmap gets
1151
     * called first for PEs, and we want to determine the trust/block
1152
     * status early on so we can skip things like embedded PE extraction
1153
     * (which is broken for signed binaries within signed binaries).
1154
     *
1155
     * If we want to add support for more signature parsing in the future
1156
     * (Ex: MachO sigs), do that here too.
1157
     *
1158
     * One benefit of not continuing on to scan files with trusted signatures
1159
     * is that the bytes associated with the exe won't get counted against the
1160
     * scansize limits, which means we have an increased chance of catching
1161
     * malware in container types (NSIS, iShield, etc.) where the file size is
1162
     * large.  A common case where this occurs is installers that embed one
1163
     * or more of the various Microsoft Redistributable Setup packages.  These
1164
     * can easily be 5 MB or more in size, and might appear before malware
1165
     * does in a given sample.
1166
     */
1167
1168
15.2M
    if (1 == info.status && i == 1) {
1169
130k
        ret = cli_check_auth_header(ctx, &(info.exeinfo));
1170
130k
        if (ret == CL_VIRUS || ret == CL_VERIFIED) {
1171
0
            goto done;
1172
0
        }
1173
1174
130k
        ret = CL_CLEAN;
1175
130k
    }
1176
1177
15.2M
    if (!filetype_only) {
1178
        /* If we're not doing a filetype-only scan, so we definitely need to include generic signatures.
1179
           So initialize the ac data for the generic signatures root. */
1180
1181
15.2M
        ret = cli_ac_initdata(&generic_ac_data, generic_ac_root->ac_partsigs, generic_ac_root->ac_lsigs, generic_ac_root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
1182
15.2M
        if (CL_SUCCESS != ret) {
1183
0
            goto done;
1184
0
        }
1185
15.2M
        gdata_initialized = true;
1186
1187
        /* Recalculate the relative offsets in ac sigs (e.g. those that are based on pe/elf/macho section start/end). */
1188
15.2M
        ret = cli_ac_caloff(generic_ac_root, &generic_ac_data, &info);
1189
15.2M
        if (CL_SUCCESS != ret) {
1190
0
            goto done;
1191
0
        }
1192
1193
        /* Recalculate the pcre offsets.
1194
           This does an allocation, that we will need to free later. */
1195
15.2M
        ret = cli_pcre_recaloff(generic_ac_root, &generic_pcre_offsets_table, &info, ctx);
1196
15.2M
        if (CL_SUCCESS != ret) {
1197
0
            goto done;
1198
0
        }
1199
15.2M
        generic_pcre_offsets_table_initialized = true;
1200
15.2M
    }
1201
1202
15.2M
    if (target_ac_root) {
1203
        /* We have to match against target-specific signatures.
1204
           So initialize the ac data for the target-specific signatures root. */
1205
1206
9.87M
        ret = cli_ac_initdata(&target_ac_data, target_ac_root->ac_partsigs, target_ac_root->ac_lsigs, target_ac_root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
1207
9.87M
        if (CL_SUCCESS != ret) {
1208
0
            goto done;
1209
0
        }
1210
9.87M
        tdata_initialized = true;
1211
1212
        /* Recalculate the relative offsets in ac sigs (e.g. those that are based on pe/elf/macho section start/end). */
1213
9.87M
        ret = cli_ac_caloff(target_ac_root, &target_ac_data, &info);
1214
9.87M
        if (CL_SUCCESS != ret) {
1215
0
            goto done;
1216
0
        }
1217
1218
9.87M
        if (target_ac_root->bm_offmode) {
1219
406k
            if (ctx->fmap->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
1220
                /* Recalculate the relative offsets in boyer-moore signatures (e.g. those that are based on pe/elf/macho section start/end). */
1221
20.4k
                ret = cli_bm_initoff(target_ac_root, &bm_offsets_table, &info);
1222
20.4k
                if (CL_SUCCESS != ret) {
1223
0
                    goto done;
1224
0
                }
1225
20.4k
                bm_offsets_table_initialized = true;
1226
20.4k
            }
1227
406k
        }
1228
1229
        /* Recalculate the pcre offsets.
1230
           This does an allocation, that we will need to free later. */
1231
9.87M
        ret = cli_pcre_recaloff(target_ac_root, &target_pcre_offsets_table, &info, ctx);
1232
9.87M
        if (CL_SUCCESS != ret) {
1233
0
            goto done;
1234
0
        }
1235
9.87M
        target_pcre_offsets_table_initialized = true;
1236
9.87M
    }
1237
1238
15.2M
    hdb = ctx->engine->hm_hdb;
1239
15.2M
    fp  = ctx->engine->hm_fp;
1240
1241
15.2M
    if (!filetype_only && hdb) {
1242
        /* We're not just doing file typing, we're checking for viruses.
1243
           So we need to compute the hash sigs, if there are any.
1244
1245
           Computing the hash in chunks the same size and time that we do for
1246
           matching with the AC & BM pattern matchers is an optimization so we
1247
           we can do both processes while the cache is still hot. */
1248
1249
0
        if (!refhash) {
1250
0
            if (cli_hm_have_size(hdb, CLI_HASH_MD5, ctx->fmap->len) ||
1251
0
                cli_hm_have_size(fp, CLI_HASH_MD5, ctx->fmap->len) ||
1252
0
                cli_hm_have_wild(hdb, CLI_HASH_MD5) ||
1253
0
                cli_hm_have_wild(fp, CLI_HASH_MD5)) {
1254
0
                compute_hash[CLI_HASH_MD5] = true;
1255
0
            } else {
1256
0
                compute_hash[CLI_HASH_MD5] = false;
1257
0
            }
1258
0
        } else {
1259
0
            compute_hash[CLI_HASH_MD5] = 0;
1260
0
            memcpy(digest[CLI_HASH_MD5], refhash, 16);
1261
0
        }
1262
1263
0
        if (cli_hm_have_size(hdb, CLI_HASH_SHA1, ctx->fmap->len) ||
1264
0
            cli_hm_have_wild(hdb, CLI_HASH_SHA1) ||
1265
0
            cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
1266
0
            cli_hm_have_wild(fp, CLI_HASH_SHA1)) {
1267
0
            compute_hash[CLI_HASH_SHA1] = true;
1268
0
        } else {
1269
0
            compute_hash[CLI_HASH_SHA1] = false;
1270
0
        }
1271
1272
0
        if (cli_hm_have_size(hdb, CLI_HASH_SHA256, ctx->fmap->len) ||
1273
0
            cli_hm_have_wild(hdb, CLI_HASH_SHA256) ||
1274
0
            cli_hm_have_size(fp, CLI_HASH_SHA256, ctx->fmap->len) ||
1275
0
            cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
1276
0
            compute_hash[CLI_HASH_SHA256] = true;
1277
0
        } else {
1278
0
            compute_hash[CLI_HASH_SHA256] = false;
1279
0
        }
1280
0
    }
1281
1282
15.6M
    while (offset < ctx->fmap->len) {
1283
15.6M
        if (cli_checktimelimit(ctx) != CL_SUCCESS) {
1284
0
            cli_dbgmsg("Exceeded scan time limit while scanning fmap (max: %u)\n", ctx->engine->maxscantime);
1285
0
            ret = CL_ETIMEOUT;
1286
0
            goto done;
1287
0
        }
1288
1289
15.6M
        bytes = MIN(ctx->fmap->len - offset, SCANBUFF);
1290
15.6M
        if (!(buff = fmap_need_off_once(ctx->fmap, offset, bytes)))
1291
0
            break;
1292
15.6M
        if (ctx->scanned)
1293
15.6M
            *ctx->scanned += bytes / CL_COUNT_PRECISION;
1294
1295
15.6M
        if (target_ac_root) {
1296
10.2M
            const char *virname = NULL;
1297
1298
10.2M
            ret = matcher_run(target_ac_root, buff, bytes, &virname, &target_ac_data, offset,
1299
10.2M
                              &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, ctx->fmap,
1300
10.2M
                              bm_offsets_table_initialized ? &bm_offsets_table : NULL,
1301
10.2M
                              &target_pcre_offsets_table, ctx);
1302
10.2M
            if (ret == CL_VIRUS || ret == CL_EMEM) {
1303
0
                goto done;
1304
0
            }
1305
10.2M
        }
1306
1307
15.6M
        if (!filetype_only) {
1308
15.6M
            const char *virname = NULL;
1309
1310
15.6M
            ret = matcher_run(generic_ac_root, buff, bytes, &virname, &generic_ac_data, offset,
1311
15.6M
                              &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, ctx->fmap,
1312
15.6M
                              NULL,
1313
15.6M
                              &generic_pcre_offsets_table, ctx);
1314
15.6M
            if (ret == CL_VIRUS || ret == CL_EMEM) {
1315
0
                goto done;
1316
15.6M
            } else if ((acmode & AC_SCAN_FT) && ((cli_file_t)ret >= CL_TYPENO)) {
1317
6.58M
                if (ret > type)
1318
6.52M
                    type = ret;
1319
6.58M
            }
1320
1321
            /* if (bytes <= (maxpatlen * (offset!=0))), it means the last window finished the file hashing *
1322
             *   since the last window is responsible for adding intersection between windows (maxpatlen)  */
1323
15.6M
            if (hdb && (bytes > (maxpatlen * (offset != 0)))) {
1324
0
                const void *data  = buff + maxpatlen * (offset != 0);
1325
0
                uint32_t data_len = bytes - maxpatlen * (offset != 0);
1326
1327
0
                if (compute_hash[CLI_HASH_MD5])
1328
0
                    cl_update_hash(md5ctx, (void *)data, data_len);
1329
0
                if (compute_hash[CLI_HASH_SHA1])
1330
0
                    cl_update_hash(sha1ctx, (void *)data, data_len);
1331
0
                if (compute_hash[CLI_HASH_SHA256])
1332
0
                    cl_update_hash(sha256ctx, (void *)data, data_len);
1333
0
            }
1334
15.6M
        }
1335
1336
15.6M
        if (bytes < SCANBUFF)
1337
15.2M
            break;
1338
1339
448k
        offset += bytes - maxpatlen;
1340
448k
    }
1341
1342
15.2M
    if (!filetype_only && hdb) {
1343
        /* We're not just doing file typing, we're scanning for malware.
1344
           So we need to check the hash sigs, if there are any. */
1345
1346
0
        cli_hash_type_t hashtype;
1347
1348
0
        if (compute_hash[CLI_HASH_MD5]) {
1349
0
            cl_finish_hash(md5ctx, digest[CLI_HASH_MD5]);
1350
0
            md5ctx = NULL;
1351
1352
            // Save the MD5 hash for later use (e.g. in FP checks).
1353
0
            fmap_set_hash(ctx->fmap, digest[CLI_HASH_MD5], CLI_HASH_MD5);
1354
0
        }
1355
0
        if (refhash) {
1356
            // Set "compute_hash" to 1 because we'll use this later to know if we have a hash to check.
1357
0
            compute_hash[CLI_HASH_MD5] = 1;
1358
0
        }
1359
1360
0
        if (compute_hash[CLI_HASH_SHA1]) {
1361
0
            cl_finish_hash(sha1ctx, digest[CLI_HASH_SHA1]);
1362
0
            sha1ctx = NULL;
1363
1364
            // Save the SHA1 hash for later use (e.g. in FP checks).
1365
0
            fmap_set_hash(ctx->fmap, digest[CLI_HASH_SHA1], CLI_HASH_SHA1);
1366
0
        }
1367
0
        if (compute_hash[CLI_HASH_SHA256]) {
1368
0
            cl_finish_hash(sha256ctx, digest[CLI_HASH_SHA256]);
1369
0
            sha256ctx = NULL;
1370
1371
            // Save the SHA256 hash for later use (e.g. in FP checks).
1372
0
            fmap_set_hash(ctx->fmap, digest[CLI_HASH_SHA256], CLI_HASH_SHA256);
1373
0
        }
1374
1375
0
        for (hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
1376
0
            const char *virname   = NULL;
1377
0
            const char *virname_w = NULL;
1378
1379
            /* If no hash, skip to next type */
1380
0
            if (!compute_hash[hashtype]) {
1381
0
                continue;
1382
0
            }
1383
1384
            /* Do hash scan checking hash sigs with specific size */
1385
0
            ret = cli_hm_scan(digest[hashtype], ctx->fmap->len, &virname, hdb, hashtype);
1386
0
            if (ret == CL_VIRUS) {
1387
                /* Matched with size-based hash ... */
1388
0
                ret = cli_append_virus(ctx, virname);
1389
0
                if (ret != CL_SUCCESS) {
1390
0
                    goto done;
1391
0
                }
1392
0
            }
1393
1394
            /* Do hash scan checking hash sigs with wildcard size */
1395
0
            ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype);
1396
0
            if (ret == CL_VIRUS) {
1397
                /* Matched with size-agnostic hash ... */
1398
0
                ret = cli_append_virus(ctx, virname_w);
1399
0
                if (ret != CL_SUCCESS) {
1400
0
                    goto done;
1401
0
                }
1402
0
            }
1403
0
        }
1404
0
    }
1405
1406
    /*
1407
     * Evaluate the logical expressions for clamav logical signatures and YARA rules.
1408
     */
1409
    // Evaluate for the target-specific signature AC matches.
1410
15.2M
    if (NULL != target_ac_root) {
1411
9.87M
        if (ret != CL_VIRUS) {
1412
9.87M
            ret = cli_exp_eval(ctx, target_ac_root, &target_ac_data, &info, (const char *)refhash);
1413
9.87M
        }
1414
9.87M
    }
1415
1416
    // Evaluate for the generic signature AC matches.
1417
15.2M
    if (NULL != generic_ac_root) {
1418
15.2M
        if (ret != CL_VIRUS) {
1419
15.2M
            ret = cli_exp_eval(ctx, generic_ac_root, &generic_ac_data, &info, (const char *)refhash);
1420
15.2M
        }
1421
15.2M
    }
1422
1423
15.2M
done:
1424
15.2M
    if (NULL != md5ctx) {
1425
15.2M
        cl_hash_destroy(md5ctx);
1426
15.2M
    }
1427
15.2M
    if (NULL != sha1ctx) {
1428
15.2M
        cl_hash_destroy(sha1ctx);
1429
15.2M
    }
1430
15.2M
    if (NULL != sha256ctx) {
1431
15.2M
        cl_hash_destroy(sha256ctx);
1432
15.2M
    }
1433
1434
15.2M
    if (gdata_initialized) {
1435
15.2M
        cli_ac_freedata(&generic_ac_data);
1436
15.2M
    }
1437
15.2M
    if (tdata_initialized) {
1438
9.87M
        cli_ac_freedata(&target_ac_data);
1439
9.87M
    }
1440
1441
15.2M
    if (generic_pcre_offsets_table_initialized) {
1442
15.2M
        cli_pcre_freeoff(&generic_pcre_offsets_table);
1443
15.2M
    }
1444
15.2M
    if (target_pcre_offsets_table_initialized) {
1445
9.87M
        cli_pcre_freeoff(&target_pcre_offsets_table);
1446
9.87M
    }
1447
1448
15.2M
    if (info_initialized) {
1449
15.2M
        cli_targetinfo_destroy(&info);
1450
15.2M
    }
1451
1452
15.2M
    if (bm_offsets_table_initialized) {
1453
20.4k
        cli_bm_freeoff(&bm_offsets_table);
1454
20.4k
    }
1455
1456
15.2M
    if (ret != CL_SUCCESS) {
1457
0
        return ret;
1458
0
    }
1459
1460
15.2M
    return (acmode & AC_SCAN_FT) ? type : CL_SUCCESS;
1461
15.2M
}
1462
1463
#define CDBRANGE(field, val)                                              \
1464
0
    if (field[0] != CLI_OFF_ANY) {                                        \
1465
0
        if (field[0] == field[1] && field[0] != val)                      \
1466
0
            continue;                                                     \
1467
0
        else if (field[0] != field[1] && ((field[0] && field[0] > val) || \
1468
0
                                          (field[1] && field[1] < val)))  \
1469
0
            continue;                                                     \
1470
0
    }
1471
1472
cl_error_t cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, unsigned int filepos, int res1, void *res2)
1473
5.68M
{
1474
5.68M
    const struct cli_cdb *cdb;
1475
5.68M
    cl_error_t ret = CL_SUCCESS;
1476
1477
5.68M
    cli_dbgmsg("CDBNAME:%s:%llu:%s:%llu:%llu:%d:%u:%u:%p\n",
1478
5.68M
               cli_ftname(cli_recursion_stack_get_type(ctx, -1)), (long long unsigned)fsizec, fname, (long long unsigned)fsizec, (long long unsigned)fsizer,
1479
5.68M
               encrypted, filepos, res1, res2);
1480
1481
5.68M
    if (ctx->engine && ctx->engine->cb_meta) {
1482
0
        if (ctx->engine->cb_meta(cli_ftname(cli_recursion_stack_get_type(ctx, -1)), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
1483
0
            cli_dbgmsg("inner file blocked by callback: %s\n", fname);
1484
1485
0
            ret = cli_append_virus(ctx, "Detected.By.Callback");
1486
0
            if (ret != CL_SUCCESS) {
1487
0
                return ret;
1488
0
            }
1489
0
        }
1490
0
    }
1491
1492
5.68M
    if (NULL == ctx->engine || (NULL == (cdb = ctx->engine->cdb))) {
1493
5.68M
        return CL_CLEAN;
1494
5.68M
    }
1495
1496
0
    do {
1497
0
        if (cdb->ctype != CL_TYPE_ANY && cdb->ctype != cli_recursion_stack_get_type(ctx, -1))
1498
0
            continue;
1499
1500
0
        if (cdb->encrypted != 2 && cdb->encrypted != encrypted)
1501
0
            continue;
1502
1503
0
        if (cdb->res1 && (cdb->ctype == CL_TYPE_ZIP || cdb->ctype == CL_TYPE_RAR) && cdb->res1 != res1)
1504
0
            continue;
1505
1506
0
        CDBRANGE(cdb->csize, cli_recursion_stack_get_size(ctx, -1));
1507
0
        CDBRANGE(cdb->fsizec, fsizec);
1508
0
        CDBRANGE(cdb->fsizer, fsizer);
1509
0
        CDBRANGE(cdb->filepos, filepos);
1510
1511
0
        if (cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
1512
0
            continue;
1513
1514
0
        ret = cli_append_virus(ctx, cdb->virname);
1515
0
        if (ret != CL_SUCCESS) {
1516
0
            return ret;
1517
0
        }
1518
1519
0
    } while ((cdb = cdb->next));
1520
1521
0
    return ret;
1522
0
}