Browse code

Address code-review comments, fix several memleaks

Changes include:
- Fixing several memory leaks noticed when running with ASan
- Adds documentation for several functions and structs
- Simplifies the interface for using cli_targetinfo_init/destroy
and cli_exe_info_init/destroy
- A few other minor changes

Andrew authored on 2019/03/13 01:45:19
Showing 11 changed files
... ...
@@ -2818,6 +2818,7 @@ int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
2818 2818
             cli_bytecode_context_clear(&ctx);
2819 2819
             return rc;
2820 2820
         } else {
2821
+            cli_bytecode_context_clear(&ctx);
2821 2822
             return CL_VIRUS;
2822 2823
         }
2823 2824
     }
... ...
@@ -455,7 +455,6 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
455 455
         section_hdr = (struct elf_section_hdr32 *)cli_calloc(shnum, shentsize);
456 456
         if (!section_hdr) {
457 457
             cli_errmsg("ELF: Can't allocate memory for section headers\n");
458
-            cli_exe_info_destroy(elfinfo);
459 458
             return CL_EMEM;
460 459
         }
461 460
         if (ctx) {
... ...
@@ -473,7 +472,6 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
473 473
                 cli_dbgmsg("ELF: Possibly broken ELF file\n");
474 474
             }
475 475
             free(section_hdr);
476
-            cli_exe_info_destroy(elfinfo);
477 476
             if (ctx && SCAN_HEURISTIC_BROKEN) {
478 477
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
479 478
                 return CL_VIRUS;
... ...
@@ -558,7 +556,6 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
558 558
         section_hdr = (struct elf_section_hdr64 *)cli_calloc(shnum, shentsize);
559 559
         if (!section_hdr) {
560 560
             cli_errmsg("ELF: Can't allocate memory for section headers\n");
561
-            cli_exe_info_destroy(elfinfo);
562 561
             return CL_EMEM;
563 562
         }
564 563
         if (ctx) {
... ...
@@ -576,7 +573,6 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
576 576
                 cli_dbgmsg("ELF: Possibly broken ELF file\n");
577 577
             }
578 578
             free(section_hdr);
579
-            cli_exe_info_destroy(elfinfo);
580 579
             if (ctx && SCAN_HEURISTIC_BROKEN) {
581 580
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
582 581
                 return CL_VIRUS;
... ...
@@ -805,6 +801,12 @@ int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
805 805
 
806 806
     cli_dbgmsg("in cli_elfheader\n");
807 807
 
808
+    // TODO This code assumes elfinfo->offset == 0, which might not always
809
+    // be the case.  For now just print this debug message and continue on
810
+    if (0 != elfinfo->offset) {
811
+        cli_dbgmsg("cli_elfheader: Assumption Violated: elfinfo->offset != 0\n");
812
+    }
813
+
808 814
     ret = cli_elf_fileheader(NULL, map, &file_hdr, &conv, &is64);
809 815
     if (ret != CL_CLEAN) {
810 816
         return -1;
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
2
+ *  Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 3
  *
4 4
  *  Authors: Andrew Williams
5 5
  *
... ...
@@ -21,19 +21,50 @@
21 21
 #include "execs.h"
22 22
 #include <string.h>
23 23
 
24
+/**
25
+ * Initialize a struct cli_exe_info so that it's ready to be populated
26
+ * by the EXE header parsing functions (cli_peheader, cli_elfheader, and
27
+ * cli_machoheader) and/or cli_exe_info_destroy.
28
+ *
29
+ * @param exeinfo a pointer to the struct cli_exe_info to initialize
30
+ * @param offset the file offset corresponding to the start of the
31
+ *        executable that exeinfo stores information about
32
+ */
24 33
 void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset)
25 34
 {
26 35
 
27 36
     if (NULL == exeinfo) {
28 37
         return;
29 38
     }
30
-    // TODO the memset below might not be needed.  Instead, replace with:
31
-    // exeinfo->sections = NULL;
32
-    // memset(&exeinfo->vinfo, '\0', sizeof(exeinfo->vinfo));
39
+
33 40
     memset(exeinfo, '\0', sizeof(*exeinfo));
34 41
     exeinfo->offset = offset;
42
+
43
+    // TODO Replace the memset above with the following once we can make
44
+    // certain that this is the only initialization needed (maybe run with
45
+    // MemorySanitizer?)
46
+
47
+    ///* Initialize all of the members which are actually used by the matcher
48
+    // * and by the bytecode runtime.  The rest is executable specific and
49
+    // * we'll leave it to be populated by the exe parsing code. */
50
+    //exeinfo->offset = offset;
51
+    //exeinfo->sections = NULL;
52
+    //exeinfo->nsections = 0;
53
+    //exeinfo->ep = 0;
54
+    ///* NOTE: These are PE-specific to an extent, but we should still
55
+    // * initialize them for other exe types because they are used by
56
+    // * the matcher/bytecode runtime. */
57
+    //exeinfo->hdr_size = 0;
58
+    //exeinfo->res_addr = 0;
59
+    //cli_hashset_init_noalloc(&(exeinfo->vinfo));
35 60
 }
36 61
 
62
+/**
63
+ * Free resources associated with a struct cli_exe_info initialized
64
+ * via cli_exe_info_init
65
+ *
66
+ * @param exeinfo a pointer to the struct cli_exe_info to destroy
67
+ */
37 68
 void cli_exe_info_destroy(struct cli_exe_info *exeinfo)
38 69
 {
39 70
 
... ...
@@ -33,17 +33,19 @@
33 33
  *  NOTE: This is used to store PE, MachO, and ELF section information. Not
34 34
  *  all members are populated by the respective parsing functions.
35 35
  *
36
- *  NOTE: This structure MUST stay in-sync with the ones defined within the
37
- *  clamav-bytecode-compiler source at:
38
- *  - clang/lib/Headers/bytecode_execs.h
39
- *  - llvm/tools/clang/lib/Headers/bytecode_execs.h
40
- *  We allocate space for an array of these and pass it directly to the
41
- *  bytecode sig runtime for use.
36
+ *  NOTE: This header file originates in the clamav-devel source and gets
37
+ *  copied into the clamav-bytecode-compiler source through a script
38
+ *  (sync-clamav.sh). This is done because an array of this structure is
39
+ *  allocated by libclamav and passed to the bytecode sig runtime.
42 40
  *
43
- *  TODO Next time we are making changes to the clamav-bytecode-compiler
44
- *  source, modify this structure to also include the section name (here and
45
- *  there).  Then, populate this field in the PE/MachO/ELF header parsing
46
- *  functions.  Choose a length that's reasonable for all platforms
41
+ *  If you need to make changes to this structure, you will need to update
42
+ *  it in both repos.  Also, I'm not sure whether changing this structure
43
+ *  would require a recompile of all previous bytecode sigs.  This should
44
+ *  be investigated before changes are made.
45
+ *
46
+ *  TODO Modify this structure to also include the section name (in both
47
+ *  repos).  Then, populate this field in the libclamav PE/MachO/ELF header
48
+ *  parsing functions.  Choose a length that's reasonable for all platforms
47 49
 */
48 50
 struct cli_exe_section {
49 51
     uint32_t rva;  /**< Relative VirtualAddress */
... ...
@@ -61,18 +63,17 @@ struct cli_exe_section {
61 61
  *  NOTE: This is used to store PE, MachO, and ELF executable information,
62 62
  *  but it predominantly has fields for PE info.  Not all members are
63 63
  *  populated by the respective parsing functions.
64
- * 
65
- *  TODO: Document which fields are PE only (maybe put those into a union of
66
- *  structs containing the various type-specific members)
67
-
68
- *  NOTE: This structure is also defined in the clamav-bytecode-compiler
69
- *  source at:
70
- *  - clang/lib/Headers/bytecode_execs.h
71
- *  - llvm/tools/clang/lib/Headers/bytecode_execs.h
72
- *  Based on how we use it, though, it doesn't need to stay in-sync
73 64
  *
74
- *  TODO Next time we are making changes to the clamav-bytecode-compiler
75
- *  source, remove this structure definition there so it's not confusing
65
+ *  NOTE: This header file originates in the clamav-devel source and gets
66
+ *  copied into the clamav-bytecode-compiler source through a script
67
+ *  (sync-clamav.sh). This is done because an array of cli_exe_section
68
+ *  structs is allocated by libclamav and passed to the bytecode sig
69
+ *  runtime.
70
+ *
71
+ *  This structure is not used by the bytecode sig runtime, so it can be
72
+ *  modified in the clamav-devel repo without requiring the changes to
73
+ *  be propagated to the clamav-bytecode-compile repo and that code rebuilt.
74
+ *  It'd be nice to keep them in sync if possible, though.
76 75
 */
77 76
 struct cli_exe_info {
78 77
     /** Information about all the sections of this file. 
... ...
@@ -91,15 +92,12 @@ struct cli_exe_info {
91 91
      */
92 92
     uint16_t nsections;
93 93
 
94
-    // TODO Remove - not required
95
-    void *dummy; /* for compat - preserve offset */
94
+    /***************** Begin PE-specific Section *****************/
96 95
 
97
-    /** Resources RVA - PE ONLY */
98
-    // TODO Maybe get rid of this - it looks like it's only used by the
99
-    // icon matching code (and maybe the bytecode API more broadly?)
96
+    /** Resources RVA */
100 97
     uint32_t res_addr;
101 98
 
102
-    /** Size of the  header (aligned) - PE ONLY. This corresponds to
99
+    /** Size of the  header (aligned). This corresponds to
103 100
      *  SizeOfHeaders in the optional header
104 101
     */
105 102
     uint32_t hdr_size;
... ...
@@ -140,7 +138,7 @@ struct cli_exe_info {
140 140
     /* Raw data copied in from the EXE directly.
141 141
      *
142 142
      * NOTE: The data in the members below haven't been converted to host
143
-     * endianness, so all field accesses most account for this to ensure
143
+     * endianness, so all field accesses must account for this to ensure
144 144
      * proper functionality on big endian systems (the PE header is always
145 145
      * little-endian)
146 146
      */
... ...
@@ -159,9 +157,10 @@ struct cli_exe_info {
159 159
      * the unpopulated entries will be memset'd to zero.
160 160
      */
161 161
     struct pe_image_data_dir dirs[16];
162
+
163
+    /***************** End PE-specific Section *****************/
162 164
 };
163 165
 
164
-// TODO Document
165 166
 void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset);
166 167
 void cli_exe_info_destroy(struct cli_exe_info *exeinfo);
167 168
 
... ...
@@ -204,9 +204,16 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
204 204
     fmap_t *map = *ctx->fmap;
205 205
     ssize_t at;
206 206
 
207
-    if (fileinfo)
207
+    if (fileinfo) {
208 208
         matcher = 1;
209 209
 
210
+        // TODO This code assumes fileinfo->offset == 0, which might not always
211
+        // be the case.  For now just print this debug message and continue on
212
+        if (0 != fileinfo->offset) {
213
+            cli_dbgmsg("cli_scanmacho: Assumption Violated: fileinfo->offset != 0\n");
214
+        }
215
+    }
216
+
210 217
     if (fmap_readn(map, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) {
211 218
         cli_dbgmsg("cli_scanmacho: Can't read header\n");
212 219
         return matcher ? -1 : CL_EFORMAT;
... ...
@@ -504,23 +504,39 @@ int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned
504 504
     return CL_SUCCESS;
505 505
 }
506 506
 
507
+/**
508
+ * Initialize a struct cli_target_info so that it's ready to have its exeinfo
509
+ * populated by the call to cli_targetinfo and/or destroyed by
510
+ * cli_targetinfo_destroy.
511
+ *
512
+ * @param info a pointer to the struct cli_target_info to initialize
513
+ */
507 514
 void cli_targetinfo_init(struct cli_target_info *info)
508 515
 {
509 516
 
510 517
     if (NULL == info) {
511 518
         return;
512 519
     }
513
-    // Things that must be initialized here:
514
-    // - status (set to 0)
515
-    // - vinfo
516
-    // Maybe other things.
517
-    // TODO Consider replacing with just the required member assignments
518
-    // for performance
519
-    memset(info, 0, sizeof(struct cli_target_info));
520
-
521
-    cli_hashset_init_noalloc(&info->exeinfo.vinfo);
520
+    info->status = 0;
521
+    cli_exe_info_init(&(info->exeinfo), 0);
522 522
 }
523 523
 
524
+/** Parse the executable headers and, if successful, populate exeinfo
525
+ *
526
+ * @param info A structure to populate with info from the exe header. This
527
+ *             MUST be initialized via cli_targetinfo_init prior to calling
528
+ * @param target the target executable file type. Possible values are:
529
+ *               - 1 - PE32 / PE32+
530
+ *               - 6 - ELF
531
+ *               - 9 - MachO
532
+ * @param map The fmap_t backing the file being scanned
533
+ *
534
+ * @return If target refers to a supported executable file type, the exe header
535
+ *         will be parsed and, if successful, info->status will be set to 1.
536
+ *         If parsing the exe header fails, info->status will be set to -1.
537
+ *         The caller MUST destroy info via a call to cli_targetinfo_destroy
538
+ *         regardless of what info->status is set to.
539
+ */
524 540
 void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
525 541
 {
526 542
     int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
... ...
@@ -542,14 +558,21 @@ void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *m
542 542
         info->status = 1;
543 543
 }
544 544
 
545
+/**
546
+ * Free resources associated with a struct cli_target_info initialized
547
+ * via cli_targetinfo_init
548
+ *
549
+ * @param info a pointer to the struct cli_target_info to destroy
550
+ */
545 551
 void cli_targetinfo_destroy(struct cli_target_info *info)
546 552
 {
547 553
 
548
-    if (NULL == info || info->status != 1) {
554
+    if (NULL == info) {
549 555
         return;
550 556
     }
551 557
 
552 558
     cli_exe_info_destroy(&(info->exeinfo));
559
+    info->status = 0;
553 560
 }
554 561
 
555 562
 int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
... ...
@@ -701,6 +724,9 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t
701 701
     const char **oldvirname;
702 702
     struct cli_exe_info info;
703 703
 
704
+    // TODO This isn't a good check, since EP will be zero for DLLs and
705
+    // (assuming pedata->ep is populated from exeinfo->pe) non-zero for
706
+    // some MachO and ELF executables
704 707
     if (!ctx->hooks.pedata->ep) {
705 708
         cli_dbgmsg("bytecode: matchicon only works with PE files\n");
706 709
         return -1;
... ...
@@ -981,7 +1007,18 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
981 981
      * (which is broken for signed binaries within signed binaries).
982 982
      * 
983 983
      * If we want to add support for more signature parsing in the future
984
-     * (Ex: MachO sigs), do that here too. */
984
+     * (Ex: MachO sigs), do that here too.
985
+     *
986
+     * One benefit of not continuing on to scan files with trusted signatures
987
+     * is that the bytes associated with the exe won't get counted against the
988
+     * scansize limits, which means we have an increased chance of catching
989
+     * malware in container types (NSIS, iShield, etc.) where the file size is
990
+     * large.  A common case where this occurs is installers that embed one
991
+     * or more of the various Microsoft Redistributable Setup packages.  These
992
+     * can easily be 5 MB or more in size, and might appear before malware
993
+     * does in a given sample.
994
+     */
995
+
985 996
     if (1 == info.status && i == 1) {
986 997
         ret = cli_check_auth_header(ctx, &(info.exeinfo));
987 998
 
... ...
@@ -373,6 +373,10 @@ void findres(uint32_t by_type, uint32_t by_name, fmap_t *map, struct cli_exe_inf
373 373
         return;
374 374
     }
375 375
 
376
+    if (0 != peinfo->offset) {
377
+        cli_dbgmsg("findres: Assumption Violated: Looking for version info when peinfo->offset != 0\n");
378
+    }
379
+
376 380
     res_rva = EC32(peinfo->dirs[2].VirtualAddress);
377 381
 
378 382
     if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size), 16)) || err)
... ...
@@ -3305,6 +3309,8 @@ int cli_scanpe(cli_ctx *ctx)
3305 3305
         uint32_t fileoffset;
3306 3306
         const char *tbuff;
3307 3307
 
3308
+        // TODO shouldn't peinfo->ep be used here instead?  ep is the file
3309
+        // offset, vep is the entry point RVA
3308 3310
         fileoffset = (peinfo->vep + cli_readint32(epbuff + 1) + 5);
3309 3311
         while (fileoffset == 0x154 || fileoffset == 0x158) {
3310 3312
             char *src;
... ...
@@ -4450,7 +4456,6 @@ int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo)
4450 4450
  * @param map The fmap_t backing the file being scanned
4451 4451
  * @param peinfo A structure to populate with info from the PE header. This
4452 4452
  *               MUST be initialized via cli_exe_info_init prior to calling
4453
- *               being passed in.
4454 4453
  * @param opts A bitfield indicating various options related to PE header
4455 4454
  *             parsing.  The options are (prefixed with CLI_PEHEADER_OPT_):
4456 4455
  *              - NONE - Do default parsing
... ...
@@ -4474,9 +4479,8 @@ int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo)
4474 4474
  *         is returned. If it seems like the PE is broken,
4475 4475
  *         CLI_PEHEADER_RET_BROKEN_PE is returned.  Otherwise, one of the
4476 4476
  *         other error codes is returned.
4477
- *         If CLI_PEHEADER_RET_SUCCESS is returned, it is the caller's
4478
- *         responsibility to destroy peinfo.  Otherwise, it's safe to do
4479
- *         so but not required.
4477
+ *         The caller MUST destroy peinfo, regardless of what this function
4478
+ *         returns.
4480 4479
  *
4481 4480
  * TODO What constitutes a "broken PE" seems somewhat arbitrary in places.
4482 4481
  * I think a PE should only be considered broken if it will not run on
... ...
@@ -4506,7 +4510,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4506 4506
     struct pe_image_file_hdr *file_hdr;
4507 4507
     struct pe_image_optional_hdr32 *opt32;
4508 4508
     struct pe_image_optional_hdr64 *opt64;
4509
-    struct pe_image_section_hdr *section_hdrs;
4509
+    struct pe_image_section_hdr *section_hdrs = NULL;
4510 4510
     unsigned int i, j, section_pe_idx;
4511 4511
     unsigned int err;
4512 4512
     uint32_t salign, falign;
... ...
@@ -4516,6 +4520,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4516 4516
     uint32_t is_exe = 0;
4517 4517
     int native      = 0;
4518 4518
     int read;
4519
+    int ret = CLI_PEHEADER_RET_GENERIC_ERROR;
4519 4520
 #if HAVE_JSON
4520 4521
     int toval                   = 0;
4521 4522
     struct json_object *pe_json = NULL;
... ...
@@ -4526,7 +4531,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4526 4526
         (opts & CLI_PEHEADER_OPT_COLLECT_JSON ||
4527 4527
          opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO)) {
4528 4528
         cli_errmsg("cli_peheader: ctx can't be NULL for options specified\n");
4529
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
4529
+        goto done;
4530 4530
     }
4531 4531
 
4532 4532
 #if HAVE_JSON
... ...
@@ -4538,18 +4543,19 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4538 4538
     fsize = map->len - peinfo->offset;
4539 4539
     if (fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) {
4540 4540
         cli_dbgmsg("cli_peheader: Can't read DOS signature\n");
4541
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
4541
+        goto done;
4542 4542
     }
4543 4543
 
4544 4544
     if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) {
4545 4545
         cli_dbgmsg("cli_peheader: Invalid DOS signature\n");
4546
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
4546
+        goto done;
4547 4547
     }
4548 4548
 
4549 4549
     if (fmap_readn(map, &(peinfo->e_lfanew), peinfo->offset + 58 + sizeof(e_magic), sizeof(peinfo->e_lfanew)) != sizeof(peinfo->e_lfanew)) {
4550 4550
         /* truncated header? */
4551 4551
         cli_dbgmsg("cli_peheader: Unable to read e_lfanew - truncated header?\n");
4552
-        return CLI_PEHEADER_RET_BROKEN_PE;
4552
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
4553
+        goto done;
4553 4554
     }
4554 4555
 
4555 4556
     peinfo->e_lfanew = EC32(peinfo->e_lfanew);
... ...
@@ -4558,20 +4564,20 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4558 4558
     }
4559 4559
     if (!peinfo->e_lfanew) {
4560 4560
         cli_dbgmsg("cli_peheader: Not a PE file - e_lfanew == 0\n");
4561
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
4561
+        goto done;
4562 4562
     }
4563 4563
 
4564 4564
     if (fmap_readn(map, &(peinfo->file_hdr), peinfo->offset + peinfo->e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
4565 4565
         /* bad information in e_lfanew - probably not a PE file */
4566 4566
         cli_dbgmsg("cli_peheader: Can't read file header\n");
4567
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
4567
+        goto done;
4568 4568
     }
4569 4569
 
4570 4570
     file_hdr = &(peinfo->file_hdr);
4571 4571
 
4572 4572
     if (EC32(file_hdr->Magic) != PE_IMAGE_NT_SIGNATURE) {
4573 4573
         cli_dbgmsg("cli_peheader: Invalid PE signature (probably NE file)\n");
4574
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
4574
+        goto done;
4575 4575
     }
4576 4576
 
4577 4577
     if (EC16(file_hdr->Characteristics) & 0x2000) {
... ...
@@ -4745,7 +4751,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4745 4745
                 cli_dbgmsg("cli_peheader: Invalid NumberOfSections (>%d)\n", PE_MAXSECTIONS);
4746 4746
             }
4747 4747
         }
4748
-        return CLI_PEHEADER_RET_BROKEN_PE;
4748
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
4749
+        goto done;
4749 4750
     }
4750 4751
 
4751 4752
     timestamp    = (time_t)EC32(file_hdr->TimeDateStamp);
... ...
@@ -4753,13 +4760,14 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4753 4753
 
4754 4754
     if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4755 4755
         cli_dbgmsg("NumberOfSections: %d\n", peinfo->nsections);
4756
-        cli_dbgmsg("TimeDateStamp: %s\n", cli_ctime(&timestamp, timestr, sizeof(timestr)));
4756
+        cli_dbgmsg("TimeDateStamp: %s", cli_ctime(&timestamp, timestr, sizeof(timestr)));
4757 4757
         cli_dbgmsg("SizeOfOptionalHeader: 0x%x\n", opt_hdr_size);
4758 4758
     }
4759 4759
 
4760 4760
 #if HAVE_JSON
4761 4761
     if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4762 4762
         cli_jsonint(pe_json, "NumberOfSections", peinfo->nsections);
4763
+        /* NOTE: the TimeDateStamp value will look like "Wed Dec 31 19:00:00 1969\n" */
4763 4764
         cli_jsonstr(pe_json, "TimeDateStamp", cli_ctime(&timestamp, timestr, sizeof(timestr)));
4764 4765
         cli_jsonint(pe_json, "SizeOfOptionalHeader", opt_hdr_size);
4765 4766
     }
... ...
@@ -4776,13 +4784,15 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4776 4776
             pe_add_heuristic_property(ctx, "BadOptionalHeaderSize");
4777 4777
         }
4778 4778
 #endif
4779
-        return CLI_PEHEADER_RET_BROKEN_PE;
4779
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
4780
+        goto done;
4780 4781
     }
4781 4782
 
4782 4783
     at = peinfo->offset + peinfo->e_lfanew + sizeof(struct pe_image_file_hdr);
4783 4784
     if (fmap_readn(map, &(peinfo->pe_opt.opt32), at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
4784 4785
         cli_dbgmsg("cli_peheader: Can't read optional file header\n");
4785
-        return CLI_PEHEADER_RET_BROKEN_PE;
4786
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
4787
+        goto done;
4786 4788
     }
4787 4789
     stored_opt_hdr_size = sizeof(struct pe_image_optional_hdr32);
4788 4790
     at += stored_opt_hdr_size;
... ...
@@ -4800,12 +4810,14 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4800 4800
                 pe_add_heuristic_property(ctx, "BadOptionalHeaderSizePE32Plus");
4801 4801
             }
4802 4802
 #endif
4803
-            return CLI_PEHEADER_RET_BROKEN_PE;
4803
+            ret = CLI_PEHEADER_RET_BROKEN_PE;
4804
+            goto done;
4804 4805
         }
4805 4806
 
4806 4807
         if (fmap_readn(map, (void *)(((size_t) & (peinfo->pe_opt.opt64)) + sizeof(struct pe_image_optional_hdr32)), at, OPT_HDR_SIZE_DIFF) != OPT_HDR_SIZE_DIFF) {
4807 4808
             cli_dbgmsg("cli_peheader: Can't read additional optional file header bytes\n");
4808
-            return CLI_PEHEADER_RET_BROKEN_PE;
4809
+            ret = CLI_PEHEADER_RET_BROKEN_PE;
4810
+            goto done;
4809 4811
         }
4810 4812
 
4811 4813
         stored_opt_hdr_size += OPT_HDR_SIZE_DIFF;
... ...
@@ -4987,14 +4999,16 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
4987 4987
     if (!native && (!salign || (salign % 0x1000))) {
4988 4988
         cli_dbgmsg("cli_peheader: Bad section alignment\n");
4989 4989
         if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
4990
-            return CLI_PEHEADER_RET_BROKEN_PE;
4990
+            ret = CLI_PEHEADER_RET_BROKEN_PE;
4991
+            goto done;
4991 4992
         }
4992 4993
     }
4993 4994
 
4994 4995
     if (!native && (!falign || (falign % 0x200))) {
4995 4996
         cli_dbgmsg("cli_peheader: Bad file alignment\n");
4996 4997
         if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
4997
-            return CLI_PEHEADER_RET_BROKEN_PE;
4998
+            ret = CLI_PEHEADER_RET_BROKEN_PE;
4999
+            goto done;
4998 5000
         }
4999 5001
     }
5000 5002
 
... ...
@@ -5023,13 +5037,14 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5023 5023
 
5024 5024
     if (opt_hdr_size < (stored_opt_hdr_size + data_dirs_size)) {
5025 5025
         cli_dbgmsg("cli_peheader: SizeOfOptionalHeader too small (doesn't include data dir size)\n");
5026
-        return CLI_PEHEADER_RET_BROKEN_PE;
5026
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
5027
+        goto done;
5027 5028
     }
5028 5029
 
5029 5030
     read = fmap_readn(map, peinfo->dirs, at, data_dirs_size);
5030 5031
     if (read < 0 || (uint32_t)read != data_dirs_size) {
5031 5032
         cli_dbgmsg("cli_peheader: Can't read optional file header data dirs\n");
5032
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
5033
+        goto done;
5033 5034
     }
5034 5035
     at += data_dirs_size;
5035 5036
 
... ...
@@ -5060,25 +5075,21 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5060 5060
 
5061 5061
     if (!peinfo->sections) {
5062 5062
         cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n");
5063
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
5063
+        goto done;
5064 5064
     }
5065 5065
 
5066 5066
     section_hdrs = (struct pe_image_section_hdr *)cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr));
5067 5067
 
5068 5068
     if (!section_hdrs) {
5069 5069
         cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n");
5070
-        free(peinfo->sections);
5071
-        peinfo->sections = NULL;
5072
-        return CLI_PEHEADER_RET_GENERIC_ERROR;
5070
+        goto done;
5073 5071
     }
5074 5072
 
5075 5073
     read = fmap_readn(map, section_hdrs, at, peinfo->nsections * sizeof(struct pe_image_section_hdr));
5076 5074
     if (read < 0 || (uint32_t)read != peinfo->nsections * sizeof(struct pe_image_section_hdr)) {
5077 5075
         cli_dbgmsg("cli_peheader: Can't read section header - possibly broken PE file\n");
5078
-        free(section_hdrs);
5079
-        free(peinfo->sections);
5080
-        peinfo->sections = NULL;
5081
-        return CLI_PEHEADER_RET_BROKEN_PE;
5076
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
5077
+        goto done;
5082 5078
     }
5083 5079
     at += sizeof(struct pe_image_section_hdr) * peinfo->nsections;
5084 5080
 
... ...
@@ -5122,10 +5133,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5122 5122
             if (section->raw >= fsize || section->uraw >= fsize) {
5123 5123
                 cli_dbgmsg("cli_peheader: Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", section_pe_idx, (unsigned long)section->raw, (unsigned long)fsize);
5124 5124
                 if (peinfo->nsections == 1) {
5125
-                    free(section_hdrs);
5126
-                    free(peinfo->sections);
5127
-                    peinfo->sections = NULL;
5128
-                    return CLI_PEHEADER_RET_BROKEN_PE;
5125
+                    ret = CLI_PEHEADER_RET_BROKEN_PE;
5126
+                    goto done;
5129 5127
                 }
5130 5128
 
5131 5129
                 for (j = i; j < peinfo->nsections - 1; j++)
... ...
@@ -5161,10 +5170,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5161 5161
             add_section_info(ctx, &peinfo->sections[i]);
5162 5162
 
5163 5163
             if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
5164
-                free(section_hdrs);
5165
-                free(peinfo->sections);
5166
-                peinfo->sections = NULL;
5167
-                return CLI_PEHEADER_RET_JSON_TIMEOUT;
5164
+                ret = CLI_PEHEADER_RET_JSON_TIMEOUT;
5165
+                goto done;
5168 5166
             }
5169 5167
         }
5170 5168
 #endif
... ...
@@ -5207,10 +5214,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5207 5207
         if (!salign || (section->urva % salign)) { /* Bad section alignment */
5208 5208
             cli_dbgmsg("cli_peheader: Broken PE - section's VirtualAddress is misaligned\n");
5209 5209
             if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5210
-                free(section_hdrs);
5211
-                free(peinfo->sections);
5212
-                peinfo->sections = NULL;
5213
-                return CLI_PEHEADER_RET_BROKEN_PE;
5210
+                ret = CLI_PEHEADER_RET_BROKEN_PE;
5211
+                goto done;
5214 5212
             }
5215 5213
         }
5216 5214
 
... ...
@@ -5218,22 +5223,16 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5218 5218
         // section? Why the exception for uraw?
5219 5219
         if (section->urva >> 31 || section->uvsz >> 31 || (section->rsz && section->uraw >> 31) || peinfo->sections[i].ursz >> 31) {
5220 5220
             cli_dbgmsg("cli_peheader: Found PE values with sign bit set\n");
5221
-
5222
-            free(section_hdrs);
5223
-            free(peinfo->sections);
5224
-            peinfo->sections = NULL;
5225
-
5226
-            return CLI_PEHEADER_RET_BROKEN_PE;
5221
+            ret = CLI_PEHEADER_RET_BROKEN_PE;
5222
+            goto done;
5227 5223
         }
5228 5224
 
5229 5225
         if (!i) {
5230 5226
             if (section->urva != peinfo->hdr_size) { /* Bad first section RVA */
5231 5227
                 cli_dbgmsg("cli_peheader: First section doesn't start immediately after the header\n");
5232 5228
                 if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5233
-                    free(section_hdrs);
5234
-                    free(peinfo->sections);
5235
-                    peinfo->sections = NULL;
5236
-                    return CLI_PEHEADER_RET_BROKEN_PE;
5229
+                    ret = CLI_PEHEADER_RET_BROKEN_PE;
5230
+                    goto done;
5237 5231
                 }
5238 5232
             }
5239 5233
 
... ...
@@ -5243,10 +5242,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5243 5243
             if (section->urva - peinfo->sections[i - 1].urva != peinfo->sections[i - 1].vsz) { /* No holes, no overlapping, no virtual disorder */
5244 5244
                 cli_dbgmsg("cli_peheader: Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
5245 5245
                 if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5246
-                    free(section_hdrs);
5247
-                    free(peinfo->sections);
5248
-                    peinfo->sections = NULL;
5249
-                    return CLI_PEHEADER_RET_BROKEN_PE;
5246
+                    ret = CLI_PEHEADER_RET_BROKEN_PE;
5247
+                    goto done;
5250 5248
                 }
5251 5249
             }
5252 5250
 
... ...
@@ -5268,15 +5265,12 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5268 5268
 
5269 5269
     peinfo->overlay_size = fsize - peinfo->overlay_start;
5270 5270
 
5271
-    free(section_hdrs);
5272
-
5273 5271
     // NOTE: For DLLs the entrypoint is likely to be zero
5274
-    // TODO ^^^ Does this mean this doesn't work for DLLs?
5272
+    // TODO Should this offset include peinfo->offset?
5275 5273
     if (!(peinfo->ep = cli_rawaddr(peinfo->vep, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) {
5276 5274
         cli_dbgmsg("cli_peheader: Broken PE file - Can't map EntryPoint to a file offset\n");
5277
-        free(peinfo->sections);
5278
-        peinfo->sections = NULL;
5279
-        return CLI_PEHEADER_RET_BROKEN_PE;
5275
+        ret = CLI_PEHEADER_RET_BROKEN_PE;
5276
+        goto done;
5280 5277
     }
5281 5278
 
5282 5279
 #if HAVE_JSON
... ...
@@ -5284,9 +5278,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5284 5284
         cli_jsonint(pe_json, "EntryPointOffset", peinfo->ep);
5285 5285
 
5286 5286
         if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
5287
-            free(peinfo->sections);
5288
-            peinfo->sections = NULL;
5289
-            return CLI_PEHEADER_RET_JSON_TIMEOUT;
5287
+            ret = CLI_PEHEADER_RET_JSON_TIMEOUT;
5288
+            goto done;
5290 5289
         }
5291 5290
     }
5292 5291
 #endif
... ...
@@ -5306,6 +5299,12 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5306 5306
         const uint8_t *vptr, *baseptr;
5307 5307
         uint32_t rva, res_sz;
5308 5308
 
5309
+        // TODO This code assumes peinfo->offset == 0, which might not always
5310
+        // be the case.
5311
+        if (0 != peinfo->offset) {
5312
+            cli_dbgmsg("cli_peheader: Assumption Violated: Looking for version info when peinfo->offset != 0\n");
5313
+        }
5314
+
5309 5315
         memset(&vlist, 0, sizeof(vlist));
5310 5316
         findres(0x10, 0xffffffff, map, peinfo, versioninfo_cb, &vlist);
5311 5317
         if (!vlist.count)
... ...
@@ -5313,9 +5312,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5313 5313
 
5314 5314
         if (cli_hashset_init(&peinfo->vinfo, 32, 80)) {
5315 5315
             cli_errmsg("cli_peheader: Unable to init vinfo hashset\n");
5316
-            free(peinfo->sections);
5317
-            peinfo->sections = NULL;
5318
-            return CLI_PEHEADER_RET_GENERIC_ERROR;
5316
+            goto done;
5319 5317
         }
5320 5318
 
5321 5319
         err = 0;
... ...
@@ -5446,10 +5443,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5446 5446
 
5447 5447
                             if (cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) {
5448 5448
                                 cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n");
5449
-                                cli_hashset_destroy(&peinfo->vinfo);
5450
-                                free(peinfo->sections);
5451
-                                peinfo->sections = NULL;
5452
-                                return CLI_PEHEADER_RET_GENERIC_ERROR;
5449
+                                goto done;
5453 5450
                             }
5454 5451
 
5455 5452
                             if (cli_debug_flag) {
... ...
@@ -5487,7 +5481,16 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct
5487 5487
     // Do final preperations for peinfo to be passed back
5488 5488
     peinfo->is_dll = is_dll;
5489 5489
 
5490
-    return CLI_PEHEADER_RET_SUCCESS;
5490
+    ret = CLI_PEHEADER_RET_SUCCESS;
5491
+
5492
+done:
5493
+    /* In the fail case, peinfo will get destroyed by the caller */
5494
+
5495
+    if (NULL != section_hdrs) {
5496
+        free(section_hdrs);
5497
+    }
5498
+
5499
+    return ret;
5491 5500
 }
5492 5501
 
5493 5502
 // TODO We should sort based on VirtualAddress instead, since PointerToRawData
... ...
@@ -1,6 +1,6 @@
1 1
 /*
2
- *  Copyright (C) 2015, 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3
- *  Copyright (C) 2007-2008 Sourcefire, Inc.
2
+ *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3
+ *  Copyright (C) 2007-2013 Sourcefire, Inc.
4 4
  *
5 5
  *  Authors: Alberto Wu, Tomasz Kojm, Andrew Williams
6 6
  * 
... ...
@@ -4529,7 +4529,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4529 4529
     if ((dd = opendir(dirname)) == NULL) {
4530 4530
         cli_errmsg("cli_loaddbdir(): Can't open directory %s\n", dirname);
4531 4531
         ret = CL_EOPEN;
4532
-        goto cleanup;
4532
+        goto done;
4533 4533
     }
4534 4534
 
4535 4535
     dirname_len = strlen(dirname);
... ...
@@ -4564,7 +4564,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4564 4564
         if (!dbfile) {
4565 4565
             cli_errmsg("cli_loaddbdir(): dbfile == NULL\n");
4566 4566
             ret = CL_EMEM;
4567
-            goto cleanup;
4567
+            goto done;
4568 4568
         }
4569 4569
         if (ends_with_sep)
4570 4570
             sprintf(dbfile, "%s%s", dirname, dent->d_name);
... ...
@@ -4585,6 +4585,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4585 4585
 
4586 4586
         } else if (!strcmp(dent->d_name, "daily.cld")) {
4587 4587
             /* the daily db must be loaded before main */
4588
+            // TODO Why is this the case?
4588 4589
             load_priority = DB_LOAD_PRIORITY_DAILY_CLD;
4589 4590
 
4590 4591
             have_daily_cld = !access(dbfile, R_OK);
... ...
@@ -4593,7 +4594,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4593 4593
                 if (!daily_cld) {
4594 4594
                     cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile);
4595 4595
                     ret = CL_EMALFDB;
4596
-                    goto cleanup;
4596
+                    goto done;
4597 4597
                 }
4598 4598
             }
4599 4599
 
... ...
@@ -4606,7 +4607,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4606 4606
                 if (!daily_cvd) {
4607 4607
                     cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile);
4608 4608
                     ret = CL_EMALFDB;
4609
-                    goto cleanup;
4609
+                    goto done;
4610 4610
                 }
4611 4611
             }
4612 4612
 
... ...
@@ -4639,7 +4640,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4639 4639
         if (NULL == entry) {
4640 4640
             cli_errmsg("cli_loaddbdir(): entry == NULL\n");
4641 4641
             ret = CL_EMEM;
4642
-            goto cleanup;
4642
+            goto done;
4643 4643
         }
4644 4644
 
4645 4645
         entry->path          = dbfile;
... ...
@@ -4651,18 +4652,20 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4651 4651
     /* The list entries are stored in priority order, so now just loop through
4652 4652
      * and load everything.
4653 4653
      * NOTE: If there's a daily.cld and a daily.cvd, we'll only load whichever
4654
-     * has the highest version number. */
4655
-
4656
-    // TODO Should we treat all cld/cvd pairs like we do the daily ones?
4654
+     * has the highest version number.  If they have the same version number
4655
+     * we load daily.cld, since that will load faster (it won't attempt to
4656
+     * verify the digital signature of the db).
4657
+     * TODO It'd be ideal if we treated all cld/cvd pairs like we do the daily
4658
+     * ones, and only loaded the one with the highest version. */
4657 4659
     for (iter = head; iter != NULL; iter = iter->next) {
4658 4660
 
4659 4661
         if (DB_LOAD_PRIORITY_DAILY_CLD == iter->load_priority && have_daily_cvd) {
4660
-            if (daily_cld->version <= daily_cvd->version) {
4662
+            if (daily_cld->version < daily_cvd->version) {
4661 4663
                 continue;
4662 4664
             }
4663 4665
 
4664 4666
         } else if (DB_LOAD_PRIORITY_DAILY_CVD == iter->load_priority && have_daily_cld) {
4665
-            if (daily_cld->version > daily_cvd->version) {
4667
+            if (daily_cld->version >= daily_cvd->version) {
4666 4668
                 continue;
4667 4669
             }
4668 4670
         }
... ...
@@ -4670,11 +4673,11 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned
4670 4670
         ret = cli_load(iter->path, engine, signo, options, NULL);
4671 4671
         if (ret) {
4672 4672
             cli_errmsg("cli_loaddbdir(): error loading database %s\n", iter->path);
4673
-            goto cleanup;
4673
+            goto done;
4674 4674
         }
4675 4675
     }
4676 4676
 
4677
-cleanup:
4677
+done:
4678 4678
     for (iter = head; iter != NULL; iter = next) {
4679 4679
         next = iter->next;
4680 4680
         free(iter->path);
... ...
@@ -4763,7 +4766,7 @@ int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, uns
4763 4763
         cli_dbgmsg("Bytecode engine disabled\n");
4764 4764
     }
4765 4765
 
4766
-    if (cli_cache_init(engine))
4766
+    if (!engine->cache && cli_cache_init(engine))
4767 4767
         return CL_EMEM;
4768 4768
 
4769 4769
     engine->dboptions |= dboptions;
... ...
@@ -5085,6 +5088,11 @@ int cl_engine_free(struct cl_engine *engine)
5085 5085
         mpool_free(engine->mempool, root);
5086 5086
     }
5087 5087
 
5088
+    if ((root = engine->hm_imp)) {
5089
+        hm_free(root);
5090
+        mpool_free(engine->mempool, root);
5091
+    }
5092
+
5088 5093
     if ((root = engine->hm_fp)) {
5089 5094
         hm_free(root);
5090 5095
         mpool_free(engine->mempool, root);
... ...
@@ -5255,6 +5263,9 @@ int cl_engine_compile(struct cl_engine *engine)
5255 5255
     if (engine->hm_mdb)
5256 5256
         hm_flush(engine->hm_mdb);
5257 5257
 
5258
+    if (engine->hm_imp)
5259
+        hm_flush(engine->hm_imp);
5260
+
5258 5261
     if (engine->hm_fp)
5259 5262
         hm_flush(engine->hm_fp);
5260 5263
 
... ...
@@ -28,19 +28,14 @@
28 28
 #include "str.h"
29 29
 #include "cvd.h"
30 30
 
31
-// TODO Is it safe to remove .db2 and .db3 from here?  These strings aren't
32
-// referenced anywhere else in the source.
33
-
34
-// NOTE: We don't include .info in CLI_DBEXT because they are only used for
35
-// one specific purpose - verifying the contents of database container files.
36
-// This list is geared towards file extensions of files that users can provide
37
-// to ClamAV directly.
31
+/* NOTE: We don't include .info in CLI_DBEXT because they are only used for
32
+ * one specific purpose - verifying the contents of database container files.
33
+ * This list is geared towards file extensions of files that users can provide
34
+ * to ClamAV directly. */
38 35
 #ifdef HAVE_YARA
39 36
 #define CLI_DBEXT(ext)                   \
40 37
     (                                    \
41 38
         cli_strbcasestr(ext, ".db") ||   \
42
-        cli_strbcasestr(ext, ".db2") ||  \
43
-        cli_strbcasestr(ext, ".db3") ||  \
44 39
         cli_strbcasestr(ext, ".hdb") ||  \
45 40
         cli_strbcasestr(ext, ".hdu") ||  \
46 41
         cli_strbcasestr(ext, ".fp") ||   \
... ...
@@ -82,8 +77,6 @@
82 82
 #define CLI_DBEXT(ext)                   \
83 83
     (                                    \
84 84
         cli_strbcasestr(ext, ".db") ||   \
85
-        cli_strbcasestr(ext, ".db2") ||  \
86
-        cli_strbcasestr(ext, ".db3") ||  \
87 85
         cli_strbcasestr(ext, ".hdb") ||  \
88 86
         cli_strbcasestr(ext, ".hdu") ||  \
89 87
         cli_strbcasestr(ext, ".fp") ||   \
... ...
@@ -1505,7 +1505,7 @@ static int cli_scanhtml(cli_ctx *ctx)
1505 1505
 static int cli_scanscript(cli_ctx *ctx)
1506 1506
 {
1507 1507
     const unsigned char *buff;
1508
-    unsigned char *normalized;
1508
+    unsigned char *normalized = NULL;
1509 1509
     struct text_norm_state state;
1510 1510
     char *tmpname = NULL;
1511 1511
     int ofd       = -1, ret;
... ...
@@ -1513,6 +1513,8 @@ static int cli_scanscript(cli_ctx *ctx)
1513 1513
     uint32_t maxpatlen, offset = 0;
1514 1514
     struct cli_matcher *groot;
1515 1515
     struct cli_ac_data gmdata, tmdata;
1516
+    int gmdata_initialized = 0;
1517
+    int tmdata_initialized = 0;
1516 1518
     struct cli_ac_data *mdata[2];
1517 1519
     fmap_t *map;
1518 1520
     size_t at                  = 0;
... ...
@@ -1537,25 +1539,26 @@ static int cli_scanscript(cli_ctx *ctx)
1537 1537
     /* CL_ENGINE_MAX_SCRIPTNORMALIZE */
1538 1538
     if (curr_len > ctx->engine->maxscriptnormalize) {
1539 1539
         cli_dbgmsg("cli_scanscript: exiting (file larger than MaxScriptSize)\n");
1540
-        return CL_CLEAN;
1540
+        ret = CL_CLEAN;
1541
+        goto done;
1541 1542
     }
1542 1543
 
1543 1544
     if (!(normalized = cli_malloc(SCANBUFF + maxpatlen))) {
1544 1545
         cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF);
1545
-        return CL_EMEM;
1546
+        ret = CL_EMEM;
1547
+        goto done;
1546 1548
     }
1547 1549
     text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
1548 1550
 
1549 1551
     if ((ret = cli_ac_initdata(&tmdata, troot ? troot->ac_partsigs : 0, troot ? troot->ac_lsigs : 0, troot ? troot->ac_reloff_num : 0, CLI_DEFAULT_AC_TRACKLEN))) {
1550
-        free(normalized);
1551
-        return ret;
1552
+        goto done;
1552 1553
     }
1554
+    tmdata_initialized = 1;
1553 1555
 
1554 1556
     if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
1555
-        cli_ac_freedata(&tmdata);
1556
-        free(normalized);
1557
-        return ret;
1557
+        goto done;
1558 1558
     }
1559
+    gmdata_initialized = 1;
1559 1560
 
1560 1561
     /* dump to disk only if explicitly asked to
1561 1562
      * or if necessary to check relative offsets,
... ...
@@ -1662,9 +1665,18 @@ static int cli_scanscript(cli_ctx *ctx)
1662 1662
 
1663 1663
 done:
1664 1664
     cli_targetinfo_destroy(&info);
1665
-    free(normalized);
1666
-    cli_ac_freedata(&tmdata);
1667
-    cli_ac_freedata(&gmdata);
1665
+
1666
+    if (NULL != normalized) {
1667
+        free(normalized);
1668
+    }
1669
+
1670
+    if (tmdata_initialized) {
1671
+        cli_ac_freedata(&tmdata);
1672
+    }
1673
+
1674
+    if (gmdata_initialized) {
1675
+        cli_ac_freedata(&gmdata);
1676
+    }
1668 1677
 
1669 1678
     if (ofd != -1)
1670 1679
         close(ofd);