Browse code

refactoring byte compare functionality as a subsig; adding loader and matchers for bytecompare subsig

Mickey Sola authored on 2018/09/22 05:49:38
Showing 9 changed files
... ...
@@ -578,7 +578,9 @@ libclamav_la_SOURCES = \
578 578
 	hwp.c \
579 579
 	hwp.h \
580 580
 	lzw/lzwdec.c \
581
-	lzw/lzwdec.h
581
+	lzw/lzwdec.h \
582
+	matcher-byte-comp.c \
583
+	matcher-byte-comp.h
582 584
 
583 585
 if ENABLE_YARA
584 586
 libclamav_la_SOURCES += yara_arena.c \
... ...
@@ -303,8 +303,9 @@ am__libclamav_la_SOURCES_DIST = matcher-ac.c matcher-ac.h matcher-bm.c \
303 303
 	msdoc.h matcher-pcre.c matcher-pcre.h regex_pcre.c \
304 304
 	regex_pcre.h msxml.c msxml.h msxml_parser.c msxml_parser.h \
305 305
 	tiff.c tiff.h hwp.c hwp.h lzw/lzwdec.c lzw/lzwdec.h \
306
-	yara_arena.c yara_arena.h yara_compiler.c yara_compiler.h \
307
-	yara_exec.c yara_exec.h yara_hash.c yara_hash.h yara_grammar.y \
306
+	matcher-byte-comp.c matcher-byte-comp.h yara_arena.c \
307
+	yara_arena.h yara_compiler.c yara_compiler.h yara_exec.c \
308
+	yara_exec.h yara_hash.c yara_hash.h yara_grammar.y \
308 309
 	yara_lexer.l yara_lexer.h yara_parser.c yara_parser.h \
309 310
 	yara_clam.h bignum.h bignum_fast.h \
310 311
 	tomsfastmath/addsub/fp_add.c tomsfastmath/addsub/fp_add_d.c \
... ...
@@ -445,7 +446,8 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
445 445
 	libclamav_la-msdoc.lo libclamav_la-matcher-pcre.lo \
446 446
 	libclamav_la-regex_pcre.lo libclamav_la-msxml.lo \
447 447
 	libclamav_la-msxml_parser.lo libclamav_la-tiff.lo \
448
-	libclamav_la-hwp.lo libclamav_la-lzwdec.lo $(am__objects_1) \
448
+	libclamav_la-hwp.lo libclamav_la-lzwdec.lo \
449
+	libclamav_la-matcher-byte-comp.lo $(am__objects_1) \
449 450
 	libclamav_la-fp_add.lo libclamav_la-fp_add_d.lo \
450 451
 	libclamav_la-fp_addmod.lo libclamav_la-fp_cmp.lo \
451 452
 	libclamav_la-fp_cmp_d.lo libclamav_la-fp_cmp_mag.lo \
... ...
@@ -1341,7 +1343,8 @@ libclamav_la_SOURCES = matcher-ac.c matcher-ac.h matcher-bm.c \
1341 1341
 	openioc.h msdoc.c msdoc.h matcher-pcre.c matcher-pcre.h \
1342 1342
 	regex_pcre.c regex_pcre.h msxml.c msxml.h msxml_parser.c \
1343 1343
 	msxml_parser.h tiff.c tiff.h hwp.c hwp.h lzw/lzwdec.c \
1344
-	lzw/lzwdec.h $(am__append_9) bignum.h bignum_fast.h \
1344
+	lzw/lzwdec.h matcher-byte-comp.c matcher-byte-comp.h \
1345
+	$(am__append_9) bignum.h bignum_fast.h \
1345 1346
 	tomsfastmath/addsub/fp_add.c tomsfastmath/addsub/fp_add_d.c \
1346 1347
 	tomsfastmath/addsub/fp_addmod.c tomsfastmath/addsub/fp_cmp.c \
1347 1348
 	tomsfastmath/addsub/fp_cmp_d.c \
... ...
@@ -1702,6 +1705,7 @@ distclean-compile:
1702 1702
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-macho.Plo@am__quote@
1703 1703
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-ac.Plo@am__quote@
1704 1704
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-bm.Plo@am__quote@
1705
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-byte-comp.Plo@am__quote@
1705 1706
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-hash.Plo@am__quote@
1706 1707
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-pcre.Plo@am__quote@
1707 1708
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher.Plo@am__quote@
... ...
@@ -2882,6 +2886,13 @@ libclamav_la-lzwdec.lo: lzw/lzwdec.c
2882 2882
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
2883 2883
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-lzwdec.lo `test -f 'lzw/lzwdec.c' || echo '$(srcdir)/'`lzw/lzwdec.c
2884 2884
 
2885
+libclamav_la-matcher-byte-comp.lo: matcher-byte-comp.c
2886
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-matcher-byte-comp.lo -MD -MP -MF $(DEPDIR)/libclamav_la-matcher-byte-comp.Tpo -c -o libclamav_la-matcher-byte-comp.lo `test -f 'matcher-byte-comp.c' || echo '$(srcdir)/'`matcher-byte-comp.c
2887
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-matcher-byte-comp.Tpo $(DEPDIR)/libclamav_la-matcher-byte-comp.Plo
2888
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='matcher-byte-comp.c' object='libclamav_la-matcher-byte-comp.lo' libtool=yes @AMDEPBACKSLASH@
2889
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
2890
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-matcher-byte-comp.lo `test -f 'matcher-byte-comp.c' || echo '$(srcdir)/'`matcher-byte-comp.c
2891
+
2885 2892
 libclamav_la-yara_arena.lo: yara_arena.c
2886 2893
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-yara_arena.lo -MD -MP -MF $(DEPDIR)/libclamav_la-yara_arena.Tpo -c -o libclamav_la-yara_arena.lo `test -f 'yara_arena.c' || echo '$(srcdir)/'`yara_arena.c
2887 2894
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-yara_arena.Tpo $(DEPDIR)/libclamav_la-yara_arena.Plo
2888 2895
new file mode 100644
... ...
@@ -0,0 +1,524 @@
0
+/*
1
+ *  Byte comparison matcher support functions
2
+ *
3
+ *  Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4
+ *  All Rights Reserved.
5
+ *
6
+ *  Authors: Mickey Sola
7
+ *
8
+ *  This program is free software; you can redistribute it and/or modify
9
+ *  it under the terms of the GNU General Public License version 2 as
10
+ *  published by the Free Software Foundation.
11
+ *
12
+ *  This program is distributed in the hope that it will be useful,
13
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ *  GNU General Public License for more details.
16
+ *
17
+ *  You should have received a copy of the GNU General Public License
18
+ *  along with this program; if not, write to the Free Software
19
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ *  MA 02110-1301, USA.
21
+ */
22
+
23
+#if HAVE_CONFIG_H
24
+#include "clamav-config.h"
25
+#endif
26
+
27
+#include "clamav.h"
28
+#include "cltypes.h"
29
+#include "others.h"
30
+#include "matcher.h"
31
+#include "matcher-ac.h"
32
+#include "matcher-byte-comp.h"
33
+#include "mpool.h"
34
+#include "readdb.h"
35
+#include "str.h"
36
+
37
+/* DEBUGGING */
38
+//#define MATCHER_BCOMP_DEBUG
39
+#ifdef MATCHER_BCOMP_DEBUG
40
+#  define bcm_dbgmsg(...) cli_dbgmsg( __VA_ARGS__)
41
+#else
42
+#  define bcm_dbgmsg(...)
43
+#endif
44
+#undef MATCHER_BCOMP_DEBUG
45
+
46
+/* BCOMP MATCHER FUNCTIONS */
47
+
48
+
49
+/**
50
+ * @brief function to add the byte compare subsig into the matcher root struct
51
+ *
52
+ * @param root the matcher root struct in question, houses all relevant lsig and subsig info
53
+ * @param virname virusname as given by the signature
54
+ * @param hexsig the raw sub signature buffer itself which we will be checking/parsing
55
+ * @param lsigid the numeric internal reference number which can be used to access this lsig in the root struct
56
+ * @param options additional options for pattern matching, stored as a bitmask
57
+ *
58
+ */
59
+int cli_bcomp_addpatt(struct cli_matcher *root, const char *virname, const char *hexsig, const char *offset, const uint32_t *lsigid, unsigned int options) {
60
+
61
+    if (!hexsig || !(*hexsig) || !root)
62
+        return CL_ENULLARG;
63
+
64
+    size_t len = 0;
65
+    const char *buf_start = NULL;
66
+    const char *buf_end = NULL;
67
+    char *buf = NULL;
68
+    const char *tokens[3];
69
+    size_t toks = 0;
70
+    int16_t ref_subsigid = -1;
71
+    int64_t offset_param = 0;
72
+    size_t byte_length = 0;
73
+    uint32_t comp_val = 0;
74
+    char *hexcpy = NULL;
75
+
76
+    /* we'll be using these to help the root matcher struct keep track of each loaded byte compare pattern */
77
+    struct cli_bcomp_meta **newmetatable; 
78
+    uint32_t bcomp_count = 0;
79
+
80
+    /* zero out our byte compare data struct and tie it to the root struct's mempool instance */
81
+    struct cli_bcomp_meta *bcomp;
82
+    bcomp = (struct cli_bcomp_meta *) mpool_calloc(root->mempool, 1, sizeof(*bcomp));
83
+    if (!bcomp) {
84
+        cli_errmsg("cli_bcomp_addpatt: Unable to allocate memory for new byte compare meta\n");
85
+        return CL_EMEM;
86
+    }
87
+
88
+    /* allocate virname space with the root structure's mempool instance */
89
+    bcomp->virname = (char *) cli_mpool_virname(root->mempool, virname, options & CL_DB_OFFICIAL);
90
+    if(!bcomp->virname) {
91
+        cli_errmsg("cli_bcomp_addpatt: Unable to allocate memory for virname or NULL virname\n");
92
+        cli_bcomp_freemeta(root, bcomp);
93
+        return CL_EMEM;
94
+    }
95
+
96
+    /* bring along the standard lsigid vector, first param marks validity of vector, 2nd is lsigid, 3rd is subsigid */
97
+    if (lsigid) {
98
+        root->ac_lsigtable[lsigid[0]]->virname = bcomp->virname;
99
+
100
+        bcomp->lsigid[0] = 1;
101
+        bcomp->lsigid[1] = lsigid[0];
102
+        bcomp->lsigid[2] = lsigid[1];
103
+    }
104
+    else {
105
+        /* sigtool */
106
+        bcomp->lsigid[0] = 0;
107
+    }
108
+
109
+    /* first need to grab the subsig reference, we'll use this later to determine our offset */
110
+    buf_start = hexsig;
111
+    buf_end = hexsig;
112
+
113
+    ref_subsigid = strtol(buf_start, (char**) &buf_end, 10);
114
+    if (buf_end && buf_end[0] != '(') {
115
+        cli_errmsg("cli_bcomp_addpatt: while byte compare subsig parsing, reference subsig id was invalid or included non-decimal character\n");
116
+        cli_bcomp_freemeta(root, bcomp);
117
+        return CL_EMALFDB;
118
+    }
119
+
120
+    bcomp->ref_subsigid = ref_subsigid;
121
+
122
+    /* use the passed hexsig buffer to find the start and ending parens and store the param length (minus starting paren) */
123
+    buf_start = buf_end;
124
+    if (buf_start[0] == '(') {
125
+        if (buf_end = strchr(buf_start, ')')) {
126
+            len = (size_t) (buf_end - ++buf_start);
127
+        }
128
+        else {
129
+            cli_errmsg("cli_bcomp_addpatt: ending paren not found\n");
130
+            cli_bcomp_freemeta(root, bcomp);
131
+            return CL_EMALFDB;
132
+        }
133
+    }
134
+    else {
135
+            cli_errmsg("cli_bcomp_addpatt: opening paren not found\n");
136
+            cli_bcomp_freemeta(root, bcomp);
137
+            return CL_EMALFDB;
138
+    }
139
+
140
+    /* make a working copy of the param buffer */
141
+    buf = cli_strndup(buf_start, len);
142
+
143
+    /* break up the new param buffer into its component strings and verify we have exactly 3 */
144
+    toks = cli_strtokenize(buf, '#', 3+1, tokens);
145
+    if (3 != toks) {
146
+        cli_errmsg("cli_bcomp_addpatt: %zu (or more) params provided, 3 expected\n", toks);
147
+        free(buf);
148
+        cli_bcomp_freemeta(root, bcomp);
149
+        return CL_EMALFDB;
150
+    }
151
+
152
+    /* since null termination is super guaranteed thanks to strndup and cli_strokenize, we can use strtol to grab the
153
+     * offset params. this has the added benefit of letting us parse hex values too */
154
+    buf_end = NULL;
155
+    buf_start = tokens[0];
156
+    switch (buf_start[0]) {
157
+        case '<':
158
+            if ((++buf_start)[0]  == '<') {
159
+                offset_param = strtol(++buf_start, (char**) &buf_end, 0);
160
+                if (buf_end && buf_end+1 != tokens[1]) {
161
+                    cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), offset parameter included invalid characters\n", tokens[0], tokens[1], tokens[2]);
162
+                    free(buf);
163
+                    cli_bcomp_freemeta(root, bcomp);
164
+                    return CL_EMALFDB;
165
+                }
166
+                /* two's-complement for negative value */
167
+                offset_param = (~offset_param) + 1;
168
+
169
+             } else {
170
+                    cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator not valid\n", tokens[0], tokens[1], tokens[2]);
171
+                    free(buf);
172
+                    cli_bcomp_freemeta(root, bcomp);
173
+                    return CL_EMALFDB;
174
+             }
175
+            break;
176
+
177
+        case '>':
178
+            if ((++buf_start)[0]  == '>') {
179
+                offset_param = strtol(buf_start, (char**) &buf_end, 0);
180
+                if (buf_end && buf_end+1 != tokens[1]) {
181
+                    cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), offset parameter included invalid characters\n", tokens[0], tokens[1], tokens[2]);
182
+                    free(buf);
183
+                    cli_bcomp_freemeta(root, bcomp);
184
+                    return CL_EMALFDB;
185
+                }
186
+                break;
187
+            } else {
188
+                    cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator and/or offset not valid\n", tokens[0], tokens[1], tokens[2]);
189
+                    free(buf);
190
+                    cli_bcomp_freemeta(root, bcomp);
191
+                    return CL_EMALFDB;
192
+            }
193
+        case '0':
194
+        case '\0':
195
+            offset_param = 0;
196
+            break;
197
+
198
+        default:
199
+            cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator included invalid characters\n", tokens[0], tokens[1], tokens[2]);
200
+            free(buf);
201
+            cli_bcomp_freemeta(root, bcomp);
202
+            return CL_EMALFDB;
203
+    }
204
+
205
+    bcomp->offset = offset_param;
206
+
207
+    /* the byte length indicator options are stored in a bitmask--by design each option gets its own nibble */
208
+    buf_start = tokens[1];
209
+
210
+    switch (*buf_start) {
211
+        case 'h': bcomp->options |= CLI_BCOMP_HEX;    break;
212
+        case 'd': bcomp->options |= CLI_BCOMP_DEC;    break;
213
+
214
+        default:
215
+            cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), hex/decimal byte length indicator was found invalid\n", tokens[0], tokens[1], tokens[2]);
216
+            free(buf);
217
+            cli_bcomp_freemeta(root, bcomp);
218
+            return CL_EMALFDB;
219
+    }
220
+
221
+    buf_start++;
222
+    switch (*buf_start) {
223
+        case 'l': bcomp->options |= CLI_BCOMP_LE;    break;
224
+        case 'b': bcomp->options |= CLI_BCOMP_BE;    break;
225
+
226
+        default:
227
+            cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), little/big endian byte length indicator was invalid\n", tokens[0], tokens[1], tokens[2]);
228
+            free(buf);
229
+            cli_bcomp_freemeta(root, bcomp);
230
+            return CL_EMALFDB;
231
+    }
232
+
233
+    /* parse out the byte length parameter */
234
+    buf_start++;
235
+    buf_end = NULL;
236
+    byte_length = strtol(buf_start, (char **) &buf_end, 0);
237
+    if (buf_end && buf_end+1 != tokens[2]) {
238
+        cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), byte length parameter included invalid characters\n", tokens[0], tokens[1], tokens[3]);
239
+        free(buf);
240
+        cli_bcomp_freemeta(root, bcomp);
241
+        return CL_EMALFDB;
242
+    }
243
+
244
+    bcomp->byte_len = byte_length;
245
+
246
+    /* currectly only >, <, and = are supported comparison symbols--this makes parsing very simple */
247
+    buf_start = tokens[2];
248
+    switch (*buf_start) {
249
+        case '<':
250
+        case '>':
251
+        case '=':
252
+            bcomp->comp_symbol = *buf_start;    break;
253
+
254
+        default:
255
+            cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), byte comparison symbol was invalid (>, <, = are supported operators)\n", tokens[0], tokens[1], tokens[2]);
256
+            free(buf);
257
+            cli_bcomp_freemeta(root, bcomp);
258
+            return CL_EMALFDB;
259
+    }
260
+
261
+
262
+    /* no more tokens after this, so we take advantage of strtol and check if the buf_end is null terminated or not */
263
+    buf_start++;
264
+    buf_end = NULL;
265
+    comp_val = strtol(buf_start, (char **) &buf_end, 0);
266
+    if (*buf_end) {
267
+        cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), comparison value contained invalid input\n", tokens[0], tokens[1], tokens[2]);
268
+        free(buf);
269
+        cli_bcomp_freemeta(root, bcomp);
270
+        return CL_EMALFDB;
271
+    }
272
+
273
+    bcomp->comp_value = comp_val;
274
+
275
+    /* manually verify successful pattern parsing */
276
+    bcm_dbgmsg("Matcher Byte Compare: (%s%ld#%c%c%zu#%c%d)\n",
277
+                    bcomp->offset ==  0 ? "" : 
278
+                    (bcomp->offset < 0 ? "<<" : ">>"),
279
+                    bcomp->offset,
280
+                    bcomp->options & CLI_BCOMP_HEX ? 'h' : 'd',
281
+                    bcomp->options & CLI_BCOMP_LE ? 'l' : 'b',
282
+                    bcomp->byte_len,
283
+                    bcomp->comp_symbol,
284
+                    bcomp->comp_value);
285
+
286
+    /* add byte compare info to the root after reallocation */
287
+    bcomp_count = root->bcomp_metas+1;
288
+
289
+    /* allocate space for new meta table to store in root structure and increment number of byte compare patterns added */
290
+    newmetatable = (struct cli_bcomp_meta **) mpool_realloc(root->mempool, root->bcomp_metatable, bcomp_count * sizeof(struct cli_bcomp_meta *));
291
+    if(!newmetatable) {
292
+        cli_errmsg("cli_bcomp_addpatt: Unable to allocate memory for new bcomp meta table\n");
293
+        cli_bcomp_freemeta(root, bcomp);
294
+        return CL_EMEM;
295
+    }
296
+
297
+    newmetatable[bcomp_count-1] = bcomp;
298
+    root->bcomp_metatable = newmetatable;
299
+
300
+    root->bcomp_metas = bcomp_count;
301
+
302
+    /* if everything went well bcomp has been totally populated, which means we can cleanup and exit */
303
+    free(buf);
304
+    return CL_SUCCESS;
305
+}
306
+
307
+/**
308
+ * @brief function to perform all byte compare matching on the file buffer
309
+ *
310
+ * @param map the file map to perform logical byte comparison upon
311
+ * @param res the result structure, primarily used by sigtool
312
+ * @param root the root structure in which all byte compare lsig and subsig information is stored
313
+ * @param mdata the ac data struct which contains offset information from recent subsig matches
314
+ * @param ctx the clamav context struct
315
+ *
316
+ */
317
+int cli_bcomp_scanbuf(fmap_t *map, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx) {
318
+
319
+    int64_t i = 0, rc = 0, ret = CL_SUCCESS;
320
+    uint32_t lsigid, ref_subsigid;
321
+    uint32_t offset = 0;
322
+    uint8_t viruses_found = 0;
323
+    struct cli_bcomp_meta *bcomp = NULL;
324
+
325
+    if (!(root) || !(root->bcomp_metas) || !(root->bcomp_metatable) || !(mdata) || !(mdata->offmatrix) || !(ctx)) {
326
+        return CL_SUCCESS;
327
+    }
328
+
329
+    for(i = 0; i < root->bcomp_metas; i++) {
330
+
331
+        bcomp = root->bcomp_metatable[i];
332
+        lsigid = bcomp->lsigid[1];
333
+        ref_subsigid = bcomp->ref_subsigid;
334
+
335
+        /* ensures the referenced subsig matches as expected, and also ensures mdata has the needed offset */
336
+        if (ret = lsig_sub_matched(root, mdata, lsigid, ref_subsigid, CLI_OFF_NONE, 0)) {
337
+            continue;
338
+        }
339
+
340
+        /* grab the needed offset using from the last matched subsig offset matrix, i.e. the match performed above */
341
+        if (mdata->lsigsuboff_last[lsigid]) {
342
+            offset = mdata->lsigsuboff_last[lsigid][ref_subsigid]; 
343
+        } else {
344
+            ret = CL_SUCCESS;
345
+            continue;
346
+        }
347
+
348
+        /* now we have all the pieces of the puzzle, so lets do our byte compare check */
349
+        ret = cli_bcmp_compare_check(map, offset, bcomp);
350
+
351
+        /* set and append our lsig's virus name if the comparison came back positive */
352
+        if (CL_VIRUS == ret) {
353
+            viruses_found = 1;
354
+
355
+            if (virname) {
356
+                *virname = bcomp->virname;
357
+            }
358
+            /* if we aren't scanning all, let's just exit here */
359
+            if (!SCAN_ALL) {
360
+                break;
361
+            } else {
362
+                ret = cli_append_virus(ctx, (const char *)bcomp->virname);
363
+            }
364
+        }
365
+    }
366
+
367
+    if (ret == CL_SUCCESS && viruses_found) {
368
+        return CL_VIRUS;
369
+    }
370
+    return ret;
371
+}
372
+
373
+/**
374
+ * @brief does a numerical, logical byte comparison on a particular offset given a filemapping and the offset
375
+ *
376
+ * @param map the file buffer we'll be accessing to do our comparison check
377
+ * @param offset the offset of the referenced subsig match from the start of the file buffer
378
+ * @param bm the byte comparison meta data struct, contains all the other info needed to do the comparison
379
+ *
380
+ */
381
+int cli_bcmp_compare_check(fmap_t *map, int offset, struct cli_bcomp_meta *bm)
382
+{
383
+    if (!map || !bm) {
384
+        bcm_dbgmsg("bcmp_compare_check: a param is null\n");
385
+        return CL_ENULLARG;
386
+    }
387
+
388
+    const uint32_t byte_len = bm->byte_len;
389
+    uint32_t length = map->len;
390
+    const unsigned char *buffer = NULL;
391
+    unsigned char *conversion_buf = NULL;
392
+    char opt = (char) bm->options;
393
+    uint32_t value = 0;
394
+    const unsigned char* end_buf = NULL;
395
+
396
+    /* ensure we won't run off the end of the file buffer */
397
+    if (bm->offset > 0) {
398
+        if (!((offset + bm->offset + byte_len <= length))) {
399
+            bcm_dbgmsg("bcmp_compare_check: %u bytes requested at offset %zu would go past file buffer of %u\n", byte_len, (offset + bm->offset), length);
400
+            return CL_CLEAN; 
401
+        }
402
+    } else {
403
+        if (!(offset + bm->offset > 0)) {
404
+            bcm_dbgmsg("bcmp_compare_check: negative offset would underflow buffer\n");
405
+            return CL_CLEAN; 
406
+        }
407
+    }
408
+
409
+    /* jump to byte compare offset, then store off specified bytes into a null terminated buffer */
410
+    offset += bm->offset;
411
+    buffer = fmap_need_off_once(map, offset, byte_len);
412
+    bcm_dbgmsg("bcmp_compare_check: literal extracted bytes before comparison (%s)\n", buffer);
413
+
414
+    /* handle byte length options to convert the string appropriately */
415
+    switch(opt) {
416
+        /*hl*/
417
+        case CLI_BCOMP_HEX | CLI_BCOMP_LE:
418
+            value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 16);
419
+            if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) {
420
+                bcm_dbgmsg("bcmp_compare_check: little endian hex conversion unsuccessful\n");
421
+                return CL_CLEAN;
422
+            }
423
+
424
+            value = le32_to_host(value);
425
+            break;
426
+
427
+        /*hb*/  
428
+        case CLI_BCOMP_HEX | CLI_BCOMP_BE:
429
+            value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 16);
430
+            if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) {
431
+
432
+                bcm_dbgmsg("bcmp_compare_check: big endian hex conversion unsuccessful\n");
433
+                return CL_CLEAN;
434
+            }
435
+
436
+            value = be32_to_host(value);
437
+            break;
438
+
439
+        /*dl*/
440
+        case CLI_BCOMP_DEC | CLI_BCOMP_LE:
441
+            value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 10);
442
+            if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) {
443
+
444
+                bcm_dbgmsg("bcmp_compare_check: little endian decimal conversion unsuccessful\n");
445
+                return CL_CLEAN;
446
+            }
447
+
448
+            value = le32_to_host(value);
449
+            break;
450
+
451
+        /*db*/
452
+        case CLI_BCOMP_DEC | CLI_BCOMP_BE:
453
+            value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 10);
454
+            if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) {
455
+
456
+                bcm_dbgmsg("bcmp_compare_check: big endian decimal conversion unsuccessful\n");
457
+                return CL_CLEAN;
458
+            }
459
+
460
+            value = be32_to_host(value);
461
+            break;
462
+
463
+        default:
464
+            return CL_ENULLARG;
465
+    }
466
+
467
+    /* do the actual comparison */
468
+    switch (bm->comp_symbol) {
469
+
470
+        case '>':
471
+            if (value > bm->comp_value) {
472
+                bcm_dbgmsg("bcmp_compare_check: extracted value (%u) greater than comparison value (%u)\n", value, bm->comp_value);
473
+                return CL_VIRUS;
474
+            }
475
+            break;
476
+
477
+        case '<':
478
+            if (value < bm->comp_value) {
479
+                bcm_dbgmsg("bcmp_compare_check: extracted value (%u) less than comparison value (%u)\n", value, bm->comp_value);
480
+                return CL_VIRUS;
481
+            }
482
+            break;
483
+
484
+        case '=':
485
+            if (value == bm->comp_value) {
486
+                bcm_dbgmsg("bcmp_compare_check: extracted value (%u) equal to comparison value (%u)\n", value, bm->comp_value);
487
+                return CL_VIRUS;
488
+            }
489
+            break;
490
+
491
+        default:
492
+            bcm_dbgmsg("bcmp_compare_check: comparison symbol (%c) invalid\n", bm->comp_symbol);
493
+            return CL_ENULLARG;
494
+    }
495
+
496
+    /* comparison was not successful */
497
+    bcm_dbgmsg("bcmp_compare_check: extracted value was not %c %u\n", bm->comp_symbol, bm->comp_value);
498
+    return CL_CLEAN;
499
+}
500
+
501
+/**
502
+ * @brief cleans up the byte compare data struct
503
+ *
504
+ * @param root the root matcher struct whose mempool instance the bcomp struct has been allocated with
505
+ * @param bm the bcomp struct to be freed
506
+ *
507
+ */
508
+void cli_bcomp_freemeta(struct cli_matcher *root, struct cli_bcomp_meta *bm) {
509
+
510
+    if(!bm) {
511
+        return;
512
+    }
513
+    
514
+    if (bm->virname) {
515
+        mpool_free(root->mempool, bm->virname);
516
+        bm->virname = NULL;
517
+    }
518
+    
519
+    mpool_free(root->mempool, bm);
520
+    bm = NULL;
521
+
522
+    return;
523
+}
0 524
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+/*
1
+ *  Support for matcher using byte compare
2
+ *
3
+ *  Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4
+ *  All Rights Reserved.
5
+ *
6
+ *  Authors: Mickey Sola
7
+ *
8
+ *  This program is free software; you can redistribute it and/or modify
9
+ *  it under the terms of the GNU General Public License version 2 as
10
+ *  published by the Free Software Foundation.
11
+ *
12
+ *  This program is distributed in the hope that it will be useful,
13
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ *  GNU General Public License for more details.
16
+ *
17
+ *  You should have received a copy of the GNU General Public License
18
+ *  along with this program; if not, write to the Free Software
19
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ *  MA 02110-1301, USA.
21
+ */
22
+
23
+#ifndef __MATCHER_BCOMP_H
24
+#define __MATCHER_BCOMP_H
25
+
26
+#if HAVE_CONFIG_H
27
+#include "clamav-config.h"
28
+#endif
29
+
30
+#include <sys/types.h>
31
+
32
+#include "cltypes.h"
33
+#include "dconf.h"
34
+#include "mpool.h"
35
+
36
+#define CLI_BCOMP_HEX 0x0001
37
+#define CLI_BCOMP_DEC 0x0002
38
+#define CLI_BCOMP_LE  0x0010 
39
+#define CLI_BCOMP_BE  0x0020
40
+
41
+struct cli_bcomp_meta {
42
+    char *virname;
43
+    uint16_t ref_subsigid; /* identifies the dependent subsig from which we will do comparisons from */
44
+    uint32_t lsigid[3];
45
+    ssize_t offset; /* offset from the referenced subsig, handled at match-time */
46
+    uint16_t options; /* bitmask */
47
+    size_t byte_len;
48
+    char comp_symbol; /* <, >, = are supported */
49
+    uint32_t comp_value;
50
+};
51
+
52
+int cli_bcomp_addpatt(struct cli_matcher *root, const char *virname, const char* hexsig, const char *offset, const uint32_t *lsigid, unsigned int options);
53
+int cli_pcre_bcmp_compare_check(fmap_t *map, int offset, struct cli_bcomp_meta *bm);
54
+void cli_bcomp_freemeta(struct cli_matcher *root, struct cli_bcomp_meta *bm);
55
+int cli_bcomp_scanbuf(fmap_t *map, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx);
56
+
57
+#endif
... ...
@@ -321,15 +321,11 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char *
321 321
 
322 322
         /* cli_pcre_addoptions handles pcre specific options */
323 323
         while (cli_pcre_addoptions(&(pm->pdata), &opt, 0) != CL_SUCCESS) {
324
-            /* handle matcher specific options here */
324
+            /* it will return here to handle any matcher specific options */
325 325
             switch (*opt) {
326 326
             case 'g':  pm->flags |= CLI_PCRE_GLOBAL;            break;
327 327
             case 'r':  pm->flags |= CLI_PCRE_ROLLING;           break;
328 328
             case 'e':  pm->flags |= CLI_PCRE_ENCOMPASS;         break;
329
-            case 'z':  if(CL_SUCCESS == cli_pcre_bcmp_add_opts(&opt, &pm->bcmp_data)) {
330
-                           pm->flags |= CLI_PCRE_BCOMP;
331
-                           break;
332
-                       }
333 329
             default:
334 330
                 cli_errmsg("cli_pcre_addpatt: unknown/extra pcre option encountered %c\n", *opt);
335 331
                 cli_pcre_freemeta(root, pm);
... ...
@@ -348,18 +344,6 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char *
348 348
         else
349 349
             pm_dbgmsg("Matcher:  NONE\n");
350 350
 
351
-        if (pm->flags && pm->flags & CLI_PCRE_BCOMP) {
352
-            pm_dbgmsg("Matcher Byte Compare: (%zu#%c%c%zu#%c%d)\n",
353
-                      pm->bcmp_data.offset,
354
-                      pm->bcmp_data.options & CLI_PCRE_BCOMP_HEX ? 'h' : 'd',
355
-                      pm->bcmp_data.options & CLI_PCRE_BCOMP_LE ? 'l' : 'b',
356
-                      pm->bcmp_data.byte_len,
357
-                      pm->bcmp_data.comp_symbol,
358
-                      pm->bcmp_data.comp_value);
359
-        }
360
-        else
361
-            pm_dbgmsg("Matcher Byte Compare:  NONE\n");
362
-
363 351
         if (pm->pdata.options) {
364 352
 #if USING_PCRE2
365 353
             pm_dbgmsg("Compiler: %s%s%s%s%s%s%s\n",
... ...
@@ -410,125 +394,6 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char *
410 410
     return CL_SUCCESS;
411 411
 }
412 412
 
413
-int cli_pcre_bcmp_add_opts(const char **opt, struct cli_pcre_bcomp *bcomp) {
414
-
415
-    if (!opt || !(*opt) || !bcomp)
416
-        return CL_ENULLARG;
417
-
418
-    size_t len = 0;
419
-    const char *buf_start = ++(*opt);
420
-    const char *buf_end = NULL;
421
-    char *buf = NULL;
422
-    const char *tokens[3];
423
-    size_t toks = 0;
424
-    uint64_t offset_param = 0;
425
-    size_t byte_length = 0;
426
-    uint32_t comp_val = 0;
427
-
428
-    memset(bcomp, 0, sizeof(struct cli_pcre_bcomp));
429
-
430
-
431
-
432
-    if (**opt == '(') {
433
-        if (buf_end = strchr(buf_start, ')')) {
434
-            len = (size_t) (buf_end - ++buf_start);
435
-        }
436
-        else {
437
-            cli_errmsg("cli_pcre_addbytecomp: ending paren not found\n");
438
-            return CL_EMALFDB;
439
-        }
440
-    }
441
-    else {
442
-            cli_errmsg("cli_pcre_addbytecomp: opening paren not found\n");
443
-            return CL_EMALFDB;
444
-    }
445
-
446
-    buf = cli_strndup(buf_start, len);
447
-    pm_dbgmsg("buf: %s\n", buf);
448
-    *opt += len+1;
449
-    pm_dbgmsg("opt_pos: %c\n", **opt);
450
-
451
-    toks = cli_strtokenize(buf, '#', 3+1, tokens);
452
-    if (3 != toks) {
453
-        cli_errmsg("cli_pcre_addbytecomp: %zu params provided, 3 expected\n", toks);
454
-        free(buf);
455
-        return CL_EMALFDB;
456
-    }
457
-
458
-    buf_end = NULL;
459
-    offset_param = strtol(tokens[0], (char**) &buf_end, 0);
460
-    if (buf_end && buf_end+1 != tokens[1]) {
461
-        cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), offset parameter included invalid characters\n", tokens[0], tokens[1], tokens[2]);
462
-        free(buf);
463
-        return CL_EMALFDB;
464
-    }
465
-
466
-    bcomp->offset = offset_param;
467
-
468
-    buf_start = tokens[1];
469
-
470
-    switch (*buf_start) {
471
-        case 'h': bcomp->options |= CLI_PCRE_BCOMP_HEX;    break;
472
-        case 'd': bcomp->options |= CLI_PCRE_BCOMP_DEC;    break;
473
-
474
-        default:
475
-            cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), hex/decimal byte length indicator was found invalid\n", tokens[0], tokens[1], tokens[2]);
476
-            free(buf);
477
-            return CL_EMALFDB;
478
-    }
479
-
480
-
481
-    buf_start++;
482
-    switch (*buf_start) {
483
-        case 'l': bcomp->options |= CLI_PCRE_BCOMP_LE;    break;
484
-        case 'b': bcomp->options |= CLI_PCRE_BCOMP_BE;    break;
485
-
486
-        default:
487
-            cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), little/big endian byte length indicator was invalid\n", tokens[0], tokens[1], tokens[2]);
488
-            free(buf);
489
-            return CL_EMALFDB;
490
-    }
491
-
492
-    buf_start++;
493
-    buf_end = NULL;
494
-    byte_length = strtol(buf_start, (char **) &buf_end, 0);
495
-    if (buf_end && buf_end+1 != tokens[2]) {
496
-        cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), byte length parameter included invalid characters\n", tokens[0], tokens[1], tokens[3]);
497
-        free(buf);
498
-        return CL_EMALFDB;
499
-    }
500
-
501
-    bcomp->byte_len = byte_length;
502
-
503
-    buf_start = tokens[2];
504
-    pm_dbgmsg("tokens2: %c\n", *tokens[2]);
505
-    switch (*buf_start) {
506
-        case '<':
507
-        case '>':
508
-        case '=':
509
-            bcomp->comp_symbol = *buf_start;    break;
510
-
511
-        default:
512
-            cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), byte comparison symbol was invalid (>, <, = are supported operators)\n", tokens[0], tokens[1], tokens[2]);
513
-            free(buf);
514
-            return CL_EMALFDB;
515
-    }
516
-
517
-    buf_start++;
518
-    buf_end = NULL;
519
-    comp_val = strtol(buf_start, (char **) &buf_end, 0);
520
-    if (*buf_end) {
521
-        cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), comparison value contained invalid input\n", tokens[0], tokens[1], tokens[2]);
522
-        free(buf);
523
-        return CL_EMALFDB;
524
-    }
525
-
526
-    bcomp->comp_value = comp_val;
527
-
528
-    free(buf);
529
-    return CL_SUCCESS;
530
-}
531
-
532 413
 int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit, const struct cli_dconf *dconf)
533 414
 {
534 415
     unsigned int i;
... ...
@@ -738,6 +603,7 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **
738 738
     memset(&p_res, 0, sizeof(p_res));
739 739
 
740 740
     for (i = 0; i < root->pcre_metas; ++i) {
741
+
741 742
         pm = root->pcre_metatable[i];
742 743
         pd = &(pm->pdata);
743 744
 
... ...
@@ -852,13 +718,15 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **
852 852
                 cli_event_count(p_sigevents, pm->sigmatch_id);
853 853
 
854 854
                 /* for logical signature evaluation */
855
+
855 856
                 if (pm->lsigid[0]) {
856 857
                     pm_dbgmsg("cli_pcre_scanbuf: assigning lsigcnt[%d][%d], located @ %d\n",
857 858
                               pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0]);
858 859
 
859 860
                     ret = lsig_sub_matched(root, mdata, pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0], 0);
860
-                    if (ret != CL_SUCCESS)
861
-                        break;
861
+                    if (ret != CL_SUCCESS) {
862
+                            break;
863
+                    }
862 864
                 } else {
863 865
                     /* for raw match data - sigtool only */
864 866
                     if(res) {
... ...
@@ -890,23 +758,18 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **
890 890
             /* move off to the end of the match for next match; offset is relative to adjbuffer
891 891
              * NOTE: misses matches starting within the last match; TODO: start from start of last match? */
892 892
             offset = p_res.match[1];
893
-            
894
-            if(pm->flags & CLI_PCRE_BCOMP) {
895
-                ret = cli_pcre_bcmp_compare_check(buffer, length, offset, pm);
896
-                if (ret != CL_SUCCESS) {
897
-                    break;
898
-                }
899
-            }
900 893
 
901 894
         } while (global && rc > 0 && offset < adjlength);
902 895
 
903 896
         /* handle error code */
904
-        if (rc < 0 && p_res.err != CL_SUCCESS)
897
+        if (rc < 0 && p_res.err != CL_SUCCESS) {
905 898
             ret = p_res.err;
899
+        }
906 900
 
907 901
         /* jumps out of main loop from 'global' loop */
908
-        if (ret != CL_SUCCESS)
902
+        if (ret != CL_SUCCESS) {
909 903
             break;
904
+        }
910 905
     }
911 906
 
912 907
     /* free match results */
... ...
@@ -917,97 +780,6 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **
917 917
     return ret;
918 918
 }
919 919
 
920
-int cli_pcre_bcmp_compare_check(const unsigned char *buffer, uint32_t length, int offset, struct cli_pcre_meta *pm)
921
-{
922
-    if (!buffer || !pm) {
923
-        return CL_ENULLARG;
924
-    }
925
-
926
-    const uint32_t byte_len = pm->bcmp_data.byte_len;
927
-    unsigned char* conversion_buf[byte_len+1];
928
-    char opt = (char) pm->bcmp_data.options;
929
-    uint32_t value = 0;
930
-    const unsigned char* end_buf = NULL;
931
-
932
-    if (!(pm->flags & CLI_PCRE_BCOMP) || !(offset + pm->bcmp_data.offset + pm->bcmp_data.byte_len < length)) {
933
-            return CL_SUCCESS;
934
-            
935
-    }
936
-
937
-    offset += pm->bcmp_data.offset;
938
-    memcpy(conversion_buf, buffer+offset, byte_len);
939
-    conversion_buf[byte_len] = '\0';
940
-
941
-    switch(opt) {
942
-        /*hb*/
943
-        case CLI_PCRE_BCOMP_HEX | CLI_PCRE_BCOMP_LE:
944
-            value = cli_strntoul(buffer+offset, byte_len, &end_buf, 16);
945
-            if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) {
946
-                return CL_SUCCESS;
947
-            }
948
-
949
-            value = le32_to_host(value);
950
-            break;
951
-
952
-        /*hl*/  
953
-        case CLI_PCRE_BCOMP_HEX | CLI_PCRE_BCOMP_BE:
954
-            value = cli_strntoul(buffer+offset, byte_len, &end_buf, 16);
955
-            if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) {
956
-                return CL_SUCCESS;
957
-            }
958
-
959
-            value = be32_to_host(value);
960
-            break;
961
-
962
-        /*dl*/
963
-        case CLI_PCRE_BCOMP_DEC | CLI_PCRE_BCOMP_LE:
964
-            value = cli_strntoul(buffer+offset, byte_len, &end_buf, 10);
965
-            if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) {
966
-                return CL_SUCCESS;
967
-            }
968
-
969
-            value = le32_to_host(value);
970
-            break;
971
-
972
-        /*db*/
973
-        case CLI_PCRE_BCOMP_DEC | CLI_PCRE_BCOMP_BE:
974
-            value = cli_strntoul(buffer+offset, byte_len, &end_buf, 10);
975
-            if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) {
976
-                return CL_SUCCESS;
977
-            }
978
-
979
-            value = be32_to_host(value);
980
-            break;
981
-
982
-        default:
983
-            return CL_ENULLARG;
984
-    }
985
-
986
-    switch (pm->bcmp_data.comp_symbol) {
987
-
988
-        case '>':
989
-            if (value > pm->bcmp_data.comp_value) {
990
-                return CL_VIRUS;
991
-            }
992
-
993
-        case '<':
994
-            if (value < pm->bcmp_data.comp_value) {
995
-                return CL_VIRUS;
996
-            }
997
-
998
-        case '=':
999
-            if (value == pm->bcmp_data.comp_value) {
1000
-                return CL_VIRUS;
1001
-            }
1002
-
1003
-        default:
1004
-            return CL_ENULLARG;
1005
-    }
1006
-
1007
-    return CL_SUCCESS;
1008
-}
1009
-
1010
-
1011 920
 void cli_pcre_freemeta(struct cli_matcher *root, struct cli_pcre_meta *pm)
1012 921
 {
1013 922
     if (!pm)
... ...
@@ -54,25 +54,11 @@ struct cli_pcre_off {
54 54
 
55 55
 #define CLI_PCRE_DISABLED  0x80000000 /* used for dconf or fail to build */
56 56
 
57
-#define CLI_PCRE_BCOMP_HEX 0x10
58
-#define CLI_PCRE_BCOMP_DEC 0x20
59
-#define CLI_PCRE_BCOMP_LE  0x01 
60
-#define CLI_PCRE_BCOMP_BE  0x02
61
-
62
-struct cli_pcre_bcomp {
63
-    size_t offset;
64
-    uint32_t options;
65
-    size_t byte_len;
66
-    char comp_symbol;
67
-    uint32_t comp_value;
68
-};
69
-
70 57
 struct cli_pcre_meta {
71 58
     char *trigger;
72 59
     char *virname;
73 60
     uint32_t lsigid[3]; /* 0=valid, 1=lsigid, 2=subsigid */
74 61
     struct cli_pcre_data pdata;
75
-    struct cli_pcre_bcomp bcmp_data;
76 62
     /* clamav offset data */
77 63
     uint32_t offdata[4];
78 64
     uint32_t offset_min, offset_max;
... ...
@@ -96,8 +82,6 @@ void cli_pcre_freeoff(struct cli_pcre_off *data);
96 96
 int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, const struct cli_pcre_off *data, cli_ctx *ctx);
97 97
 void cli_pcre_freemeta(struct cli_matcher *root, struct cli_pcre_meta *pm);
98 98
 void cli_pcre_freetable(struct cli_matcher *root);
99
-int cli_pcre_bcmp_compare_check(const unsigned char *buffer, uint32_t length, int offset, struct cli_pcre_meta *pm);
100
-int cli_pcre_bcmp_add_opts(const char **opt, struct cli_pcre_bcomp *bcomp);
101 99
 #else
102 100
 /* NO-PCRE DECLARATIONS - defined because encasing everything in '#if' is a pain and because dynamic library mappings are weird */
103 101
 #define PCRE_BYPASS ""
... ...
@@ -180,6 +180,24 @@ static inline int matcher_run(const struct cli_matcher *root,
180 180
             return ret;
181 181
     }
182 182
 
183
+    if (root->bcomp_metas) {
184
+        ret = cli_bcomp_scanbuf(map, virname, acres, root, mdata, ctx);
185
+        if (ret != CL_CLEAN) {
186
+            if (ret == CL_VIRUS) {
187
+                if (SCAN_ALL)
188
+                    viruses_found = 1;
189
+                else {
190
+                    ret = cli_append_virus(ctx, *virname);
191
+                    if (ret != CL_CLEAN)
192
+                        return ret;
193
+                }
194
+            } else if (ret > CL_TYPENO && acmode & AC_SCAN_VIR)
195
+                saved_ret = ret;
196
+            else
197
+                return ret;
198
+        }
199
+    }
200
+
183 201
     /* due to logical triggered, pcres cannot be evaluated until after full subsig matching */
184 202
     /* cannot save pcre execution state without possible evasion; must scan entire buffer */
185 203
     /* however, scanning the whole buffer may require the whole buffer being loaded into memory */
... ...
@@ -228,13 +246,16 @@ static inline int matcher_run(const struct cli_matcher *root,
228 228
 #endif /* HAVE_PCRE */
229 229
     /* end experimental fragment */
230 230
 
231
-    if (ctx && !SCAN_ALLMATCHES && ret == CL_VIRUS)
231
+    if (ctx && !SCAN_ALLMATCHES && ret == CL_VIRUS) {
232 232
         return cli_append_virus(ctx, *virname);
233
-    if (ctx && SCAN_ALLMATCHES && viruses_found)
233
+    }
234
+    if (ctx && SCAN_ALLMATCHES && viruses_found) {
234 235
         return CL_VIRUS;
235
-
236
-    if (saved_ret && ret == CL_CLEAN)
236
+    }
237
+    if (saved_ret && ret == CL_CLEAN) {
237 238
         return saved_ret;
239
+    }
240
+
238 241
     return ret;
239 242
 }
240 243
 
... ...
@@ -1217,6 +1238,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1217 1217
         if(bm_offmode)
1218 1218
             cli_bm_freeoff(&toff);
1219 1219
         cli_pcre_freeoff(&tpoff);
1220
+
1220 1221
     }
1221 1222
 
1222 1223
     if(groot) {
... ...
@@ -1231,10 +1253,16 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1231 1231
 
1232 1232
     cli_hashset_destroy(&info.exeinfo.vinfo);
1233 1233
 
1234
+<<<<<<< HEAD
1234 1235
     if (SCAN_ALLMATCHES && viruses_found)
1236
+=======
1237
+    if (SCAN_ALL && viruses_found) {
1238
+>>>>>>> refactoring byte compare functionality as a subsig; adding loader and matchers for bytecompare subsig
1235 1239
         return CL_VIRUS;
1236
-    if(ret == CL_VIRUS)
1240
+    }
1241
+    if(ret == CL_VIRUS) {
1237 1242
         return CL_VIRUS;
1243
+    }
1238 1244
 
1239 1245
     return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
1240 1246
 }
... ...
@@ -133,6 +133,10 @@ struct cli_matcher {
133 133
     uint32_t pcre_reloff_num, pcre_absoff_num;
134 134
 #endif
135 135
 
136
+    /* Byte Compare */
137
+    uint32_t bcomp_metas;
138
+    struct cli_bcomp_meta **bcomp_metatable;
139
+
136 140
     /* Bytecode Tracker */
137 141
     uint32_t linked_bcs;
138 142
 
... ...
@@ -49,6 +49,7 @@
49 49
 #include "matcher-ac.h"
50 50
 #include "matcher-bm.h"
51 51
 #include "matcher-pcre.h"
52
+#include "matcher-byte-comp.h"
52 53
 #include "matcher-hash.h"
53 54
 #include "matcher.h"
54 55
 #include "others.h"
... ...
@@ -125,7 +126,7 @@ char *cli_virname(const char *virname, unsigned int official)
125 125
 
126 126
 int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options)
127 127
 {
128
-    char *hexcpy, *start, *end;
128
+    char *hexcpy, *start, *end, *mid;
129 129
     unsigned int i;
130 130
     int ret = CL_SUCCESS;
131 131
 
... ...
@@ -192,6 +193,19 @@ int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const cha
192 192
         return ret;
193 193
     }
194 194
 
195
+    /* BCOMP sigopt handling */
196
+    start = strchr(hexcpy, '#');
197
+    end = strrchr(hexcpy, '#');
198
+    mid = strchr(hexcpy, '(');
199
+
200
+    if (start != end && mid && (*(++mid) == '#' ||  !strncmp(mid, ">>", 2) ||
201
+                                    !strncmp(mid, "<<", 2) || !strncmp(mid, "0#", 2))) {
202
+        /* TODO byte compare currently does not have support for sigopts, pass through */
203
+        ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options);
204
+        free(hexcpy);
205
+        return ret;
206
+    }
207
+
195 208
     /* NORMAL HEXSIG sigopt handling */
196 209
     /* FULLWORD sigopt handling - only happens once */
197 210
     if (sigopts & ACPATT_OPTION_FULLWORD) {
... ...
@@ -299,7 +313,7 @@ int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const cha
299 299
 int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options)
300 300
 {
301 301
     struct cli_bm_patt *bm_new;
302
-    char *pt, *hexcpy, *start, *n, l, r;
302
+    char *pt, *hexcpy, *start = NULL, *mid = NULL, *end = NULL, *n, l, r;
303 303
     const char *wild;
304 304
     int ret, asterisk = 0, range;
305 305
     unsigned int i, j, hexlen, nest, parts = 0;
... ...
@@ -582,9 +596,17 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
582 582
 
583 583
             free(pt);
584 584
         }
585
+    } else if((start = strchr(hexsig, '(')) && (mid = strchr(hexsig, '#')) && (end = strrchr(hexsig, '#')) && mid != end) {
586
+
587
+        /* format seems to match byte_compare */
588
+        if ( ret = cli_bcomp_addpatt(root, virname, hexsig, offset, lsigid, options) ) {
589
+            cli_errmsg("cli_parse_add(): Problem adding signature (2b).\n");
590
+            return ret;
591
+        }
592
+
585 593
     } else if(root->ac_only || type || lsigid || sigopts || strpbrk(hexsig, "?([") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ','))) || strstr(offset, "VI") || strchr(offset, '$')) {
586 594
         if((ret = cli_ac_addsig(root, virname, hexsig, sigopts, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) {
587
-            cli_errmsg("cli_parse_add(): Problem adding signature (3).\n");
595
+            cli_errmsg("cli_parse_add(): Problem adding signature (3). %s \n", hexsig);
588 596
             return ret;
589 597
         }
590 598
     } else {