Browse code

libclamav: added an engine option to set max partitions in raw dmgs libclamav: added partition intersection checking support clamd/clamscan: added max-partitions and partition-intersection options

Kevin Lin authored on 2014/02/07 08:55:40
Showing 8 changed files
... ...
@@ -853,6 +853,16 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
853 853
     val = cl_engine_get_num(engine, CL_ENGINE_MAX_ZIPTYPERCG, NULL);
854 854
     logg("Limits: MaxZipTypeRcg limit set to %llu bytes.\n", val);
855 855
 
856
+    if((opt = optget(opts, "MaxPartitions"))->active) {
857
+        if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_PARTITIONS, opt->numarg))) {
858
+            logg("!cli_engine_set_num(MaxPartitions) failed: %s\n", cl_strerror(ret));
859
+            cl_engine_free(engine);
860
+            return 1;
861
+        }
862
+    }
863
+    val = cl_engine_get_num(engine, CL_ENGINE_MAX_PARTITIONS, NULL);
864
+    logg("Limits: MaxPartitions limit set to %llu.\n", val);
865
+
856 866
     if(optget(opts, "ScanArchive")->enabled) {
857 867
 	logg("Archive support enabled.\n");
858 868
 	options |= CL_SCAN_ARCHIVE;
... ...
@@ -952,6 +962,11 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
952 952
 	}
953 953
     }
954 954
 
955
+    if(optget(opts,"PartitionIntersection")->enabled) {
956
+        options |= CL_SCAN_PARTITION_INTXN;
957
+        logg("Raw DMG: Always checking for partitons intersections\n");
958
+    }
959
+
955 960
     if(optget(opts,"HeuristicScanPrecedence")->enabled) {
956 961
 	    options |= CL_SCAN_HEURISTIC_PRECEDENCE;
957 962
 	    logg("Heuristic: precedence enabled\n");
... ...
@@ -823,6 +823,14 @@ int scanmanager(const struct optstruct *opts)
823 823
 	}
824 824
     }
825 825
 
826
+    if((opt = optget(opts, "max-partitions"))->active) {
827
+	if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_PARTITIONS, opt->numarg))) {
828
+	    logg("!cli_engine_set_num(CL_ENGINE_MAX_PARTITIONS) failed: %s\n", cl_strerror(ret));
829
+	    cl_engine_free(engine);
830
+	    return 2;
831
+	}
832
+    }
833
+
826 834
     /* set scan options */
827 835
     if(optget(opts, "allmatch")->enabled)
828 836
 	options |= CL_SCAN_ALLMATCHES;
... ...
@@ -833,6 +841,9 @@ int scanmanager(const struct optstruct *opts)
833 833
     if(optget(opts,"phishing-cloak")->enabled)
834 834
 	options |= CL_SCAN_PHISHING_BLOCKCLOAK;
835 835
 
836
+    if(optget(opts,"partition-intersection")->enabled)
837
+	options |= CL_SCAN_PARTITION_INTXN;
838
+
836 839
     if(optget(opts,"heuristic-scan-precedence")->enabled)
837 840
 	options |= CL_SCAN_HEURISTIC_PRECEDENCE;
838 841
 
... ...
@@ -150,6 +150,7 @@ typedef enum {
150 150
 #define CL_SCAN_BLOCKMACROS		0x100000
151 151
 #define CL_SCAN_ALLMATCHES		0x200000
152 152
 #define CL_SCAN_SWF			0x400000
153
+#define CL_SCAN_PARTITION_INTXN         0x800000
153 154
 
154 155
 #define CL_SCAN_PERFORMANCE_INFO        0x40000000 /* collect performance timings */
155 156
 #define CL_SCAN_INTERNAL_COLLECT_SHA    0x80000000 /* Enables hash output in sha-collect builds - for internal use only */
... ...
@@ -204,7 +205,8 @@ enum cl_engine_field {
204 204
     CL_ENGINE_MAX_ZIPTYPERCG,       /* uint64_t */
205 205
     CL_ENGINE_FORCETODISK,          /* uint32_t */
206 206
     CL_ENGINE_DISABLE_CACHE,        /* uint32_t */
207
-    CL_ENGINE_DISABLE_PE_STATS      /* uint32_t */
207
+    CL_ENGINE_DISABLE_PE_STATS,     /* uint32_t */
208
+    CL_ENGINE_MAX_PARTITIONS        /* uint32_t */
208 209
 };
209 210
 
210 211
 enum bytecode_security {
... ...
@@ -410,6 +410,9 @@ struct cl_engine *cl_engine_new(void)
410 410
     new->cb_stats_get_size = clamav_stats_get_size;
411 411
     new->cb_stats_get_hostid = clamav_stats_get_hostid;
412 412
 
413
+    /* Setup raw dmg max settings */
414
+    new->maxpartitions = 50;
415
+
413 416
     cli_dbgmsg("Initialized %s engine\n", cl_retver());
414 417
     return new;
415 418
 }
... ...
@@ -542,6 +545,9 @@ int cl_engine_set_num(struct cl_engine *engine, enum cl_engine_field field, long
542 542
             engine->engine_options &= ~(ENGINE_OPTIONS_DISABLE_PE_STATS);
543 543
         }
544 544
         break;
545
+    case CL_ENGINE_MAX_PARTITIONS:
546
+        engine->maxpartitions = (uint32_t)num;
547
+        break;
545 548
 	default:
546 549
 	    cli_errmsg("cl_engine_set_num: Incorrect field number\n");
547 550
 	    return CL_EARG;
... ...
@@ -609,6 +615,8 @@ long long cl_engine_get_num(const struct cl_engine *engine, enum cl_engine_field
609 609
 	    return engine->bytecode_mode;
610 610
     case CL_ENGINE_DISABLE_CACHE:
611 611
         return engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE;
612
+    case CL_ENGINE_MAX_PARTITIONS:
613
+        return engine->maxpartitions;
612 614
 	default:
613 615
 	    cli_errmsg("cl_engine_get: Incorrect field number\n");
614 616
 	    if(err)
... ...
@@ -715,6 +723,8 @@ struct cl_settings *cl_engine_settings_copy(const struct cl_engine *engine)
715 715
     settings->cb_stats_get_size = engine->cb_stats_get_size;
716 716
     settings->cb_stats_get_hostid = engine->cb_stats_get_hostid;
717 717
 
718
+    settings->maxpartitions = engine->maxpartitions;
719
+
718 720
     return settings;
719 721
 }
720 722
 
... ...
@@ -785,6 +795,8 @@ int cl_engine_settings_apply(struct cl_engine *engine, const struct cl_settings
785 785
     engine->cb_stats_get_size = settings->cb_stats_get_size;
786 786
     engine->cb_stats_get_hostid = settings->cb_stats_get_hostid;
787 787
 
788
+    engine->maxpartitions = settings->maxpartitions;
789
+
788 790
     return CL_SUCCESS;
789 791
 }
790 792
 
... ...
@@ -327,6 +327,9 @@ struct cl_engine {
327 327
     clcb_stats_get_num cb_stats_get_num;
328 328
     clcb_stats_get_size cb_stats_get_size;
329 329
     clcb_stats_get_hostid cb_stats_get_hostid;
330
+
331
+    /* Raw dmg max settings */
332
+    uint32_t maxpartitions;
330 333
 };
331 334
 
332 335
 struct cl_settings {
... ...
@@ -378,6 +381,9 @@ struct cl_settings {
378 378
     clcb_stats_get_num cb_stats_get_num;
379 379
     clcb_stats_get_size cb_stats_get_size;
380 380
     clcb_stats_get_hostid cb_stats_get_hostid;
381
+
382
+    /* Raw dmg max settings */
383
+    uint32_t maxpartitions;
381 384
 };
382 385
 
383 386
 extern int (*cli_unrar_open)(int fd, const char *dirname, unrar_state_t *state);
384 387
new file mode 100644
... ...
@@ -0,0 +1,103 @@
0
+/*
1
+ *  Copyright (C) 2014 Sourcefire, Inc.
2
+ *
3
+ *  Authors: Kevin Lin <klin@sourcefire.com>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#if HAVE_CONFIG_H
21
+#include "clamav-config.h"
22
+#endif
23
+
24
+#include "cltypes.h"
25
+#include "others.h"
26
+#include "prtn_intxn.h"
27
+
28
+static int prtn_intxn_list_is_empty(prtn_intxn_list_t* list)
29
+{
30
+    return (list->Head == NULL);
31
+}
32
+
33
+int prtn_intxn_list_init(prtn_intxn_list_t* list)
34
+{
35
+    list->Head = NULL;
36
+    list->Size = 0;
37
+    return CL_SUCCESS;
38
+}
39
+
40
+int prtn_intxn_list_check(prtn_intxn_list_t* list, unsigned *pitxn, off_t start, size_t size)
41
+{
42
+    prtn_intxn_node_t *new_node, *check_node;
43
+    int ret = CL_CLEAN;
44
+
45
+    *pitxn = list->Size;
46
+
47
+    check_node = list->Head;
48
+    while (check_node != NULL) {
49
+        (*pitxn)--;
50
+
51
+        if (start > check_node->Start) {
52
+            if (check_node->Start+check_node->Size > start) {
53
+                ret = CL_VIRUS;
54
+                break;
55
+            }
56
+        }
57
+        else if (start < check_node->Start) {
58
+            if (start+size > check_node->Start) {
59
+                ret = CL_VIRUS;
60
+                break;
61
+            }
62
+        }
63
+        else {
64
+            ret = CL_VIRUS;
65
+            break;
66
+        }
67
+
68
+        check_node = check_node->Next;
69
+    }
70
+
71
+    /* allocate new node for partition bounds */
72
+    new_node = (prtn_intxn_node_t *) cli_malloc(sizeof(prtn_intxn_node_t));
73
+    if (!new_node) {
74
+        cli_dbgmsg("PRTN_INTXN: could not allocate new node for checklist!\n");
75
+        prtn_intxn_list_free(list);
76
+        return CL_EMEM;
77
+    }
78
+
79
+    new_node->Start = start;
80
+    new_node->Size = size;
81
+    new_node->Next = list->Head;
82
+
83
+    list->Head = new_node;
84
+    (list->Size)++;
85
+    return ret;
86
+}
87
+
88
+int prtn_intxn_list_free(prtn_intxn_list_t* list)
89
+{
90
+    prtn_intxn_node_t *next = NULL;
91
+
92
+    while (!prtn_intxn_list_is_empty(list)) {
93
+        next = list->Head->Next;
94
+
95
+        free(list->Head);
96
+
97
+        list->Head = next;
98
+        list->Size--;
99
+    }
100
+
101
+    return CL_SUCCESS;
102
+}
0 103
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+/*
1
+ *  Copyright (C) 2014 Sourcefire, Inc.
2
+ *
3
+ *  Authors: Kevin Lin <klin@sourcefire.com>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#ifndef __PRTN_INTXN_H
21
+#define __PRTN_INTXN_H
22
+
23
+#if HAVE_CONFIG_H
24
+#include "clamav-config.h"
25
+#endif
26
+
27
+#include "cltypes.h"
28
+#include "others.h"
29
+
30
+struct prtn_intxn_node;
31
+typedef struct prtn_intxn_node {
32
+    off_t Start;
33
+    size_t Size;
34
+    struct prtn_intxn_node *Next;
35
+} prtn_intxn_node_t;
36
+
37
+typedef struct prtn_intxn_list {
38
+    struct prtn_intxn_node *Head;
39
+    size_t Size; /* for debug */
40
+} prtn_intxn_list_t;
41
+
42
+int prtn_intxn_list_init(prtn_intxn_list_t *list);
43
+int prtn_intxn_list_check(prtn_intxn_list_t *list, unsigned *pitxn, off_t start, size_t size);
44
+int prtn_intxn_list_free(prtn_intxn_list_t *list);
45
+
46
+#endif
... ...
@@ -319,6 +319,8 @@ const struct clam_option __clam_options[] = {
319 319
 
320 320
     { "PhishingAlwaysBlockSSLMismatch", "phishing-ssl", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Always block SSL mismatches in URLs, even if they're not in the database.\nThis feature can lead to false positives.", "" },
321 321
 
322
+    { "PartitionIntersection", "partition-intersection", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Detect partition intersections in raw dmgs using heuristics.", "yes" },
323
+
322 324
     { "HeuristicScanPrecedence", "heuristic-scan-precedence", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Allow heuristic match to take precedence.\nWhen enabled, if a heuristic scan (such as phishingScan) detects\na possible virus/phish it will stop scan immediately. Recommended, saves CPU\nscan-time.\nWhen disabled, virus/phish detected by heuristic scans will be reported only\nat the end of a scan. If an archive contains both a heuristically detected\nvirus/phish, and a real malware, the real malware will be reported.\nKeep this disabled if you intend to handle \"*.Heuristics.*\" viruses\ndifferently from \"real\" malware.\nIf a non-heuristically-detected virus (signature-based) is found first,\nthe scan is interrupted immediately, regardless of this config option.", "yes" },
323 325
 
324 326
     { "StructuredDataDetection", "detect-structured", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Enable the Data Loss Prevention module.", "no" },
... ...
@@ -366,6 +368,8 @@ const struct clam_option __clam_options[] = {
366 366
 
367 367
     { "MaxZipTypeRcg", "max-ziptypercg", 0, TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXZIPTYPERCG, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a ZIP file to reanalyze type recognition.\nZIP files larger than this value will skip the step to potentially reanalyze as PE.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "1M" },
368 368
 
369
+    { "MaxPartitions", "max-partitions", 0, TYPE_NUMBER, MATCH_NUMBER, 50, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum number of partitions of a raw DMG to be scanned.\nRaw DMGs with more partitions than this value will have up to the value number partitions scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "128" },
370
+
369 371
     /* OnAccess settings */
370 372
     { "ScanOnAccess", NULL, 0, TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "This option enables on-access scanning (Linux only)", "no" },
371 373