1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2008-2013 Sourcefire, Inc.
4 *
5 * Authors: Tomasz Kojm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21 #if HAVE_CONFIG_H
22 #include "clamav-config.h"
23 #endif
24
25 #include <check.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 // libclamav
30 #include "clamav.h"
31 #include "readdb.h"
32 #include "matcher.h"
33 #include "matcher-ac.h"
34 #include "matcher-bm.h"
35 #include "matcher-pcre.h"
36 #include "others.h"
37 #include "default.h"
38
39 #include "checks.h"
40
41 static const struct ac_testdata_s {
42 const char *data;
43 const char *hexsig;
44 const char *virname;
45 } ac_testdata[] = {
46 /* IMPORTANT: ac_testdata[i].hexsig should only match ac_testdata[i].data */
47 {"daaaaaaaaddbbbbbcce", "64[4-4]61616161{2}6262[3-6]65", "Test_1: anchored and ranged wildcard"},
48 {"ebbbbbbbbeecccccddf", "6262(6162|6364|6265|6465){2}6363", "Test_2: multi-byte fixed alternate w/ ranged wild"},
49 {"aaaabbbbcccccdddddeeee", "616161*63636363*6565", "Test_3: unbounded wildcards"},
50 {"oprstuwxy", "6f??727374????7879", "Test_4: nibble wildcards"},
51 {"abdcabcddabccadbbdbacb", "6463{2-3}64646162(63|64|65)6361*6462????6261{-1}6362", "Test_5: various wildcard combinations w/ alternate"},
52 {"abcdefghijkabcdefghijk", "62????65666768*696a6b6162{2-3}656667[1-3]6b", "Test_6: various wildcard combinations"},
53 {"abcadbabcadbabcacb", "6?6164?26?62{3}?26162?361", "Test_7: nibble and ranged wildcards"},
54 /* testcase for filter bug: it was checking only first 32 chars, and last
55 * maxpatlen */
56 {"\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1dddddddddddddddddddd5\1\1\1\1\1\1\1\1\1\1\1\1\1", "6464646464646464646464646464646464646464(35|36)", "Test_8: filter bug"},
57
58 /* altbyte */
59 {"aabaa", "6161(62|63|64)6161", "Ac_Altstr_Test_1"}, /* control */
60 {"aacaa", "6161(62|63|64)6161", "Ac_Altstr_Test_1"}, /* control */
61 {"aadaa", "6161(62|63|64)6161", "Ac_Altstr_Test_1"}, /* control */
62
63 /* alt-fstr */
64 {"aabbbaa", "6161(626262|636363|646464)6161", "Ac_Altstr_Test_2"}, /* control */
65 {"aacccaa", "6161(626262|636363|646464)6161", "Ac_Altstr_Test_2"}, /* control */
66 {"aadddaa", "6161(626262|636363|646464)6161", "Ac_Altstr_Test_2"}, /* control */
67
68 /* alt-vstr */
69 {"aabbaa", "6161(6262|63636363|6464646464)6161", "Ac_Altstr_Test_3"}, /* control */
70 {"aaccccaa", "6161(6262|63636363|6464646464)6161", "Ac_Altstr_Test_3"}, /* control */
71 {"aadddddaa", "6161(6262|63636363|6464646464)6161", "Ac_Altstr_Test_3"}, /* control */
72
73 /* alt-embed */
74 {"aajjaa", "6161(6a6a|66(6767|6868)66|6969)6161", "Ac_Altstr_Test_4"}, /* control */
75 {"aafggfaa", "6161(6a6a|66(6767|6868)66|6969)6161", "Ac_Altstr_Test_4"}, /* control */
76 {"aafhhfaa", "6161(6a6a|66(6767|6868)66|6969)6161", "Ac_Altstr_Test_4"}, /* control */
77 {"aaiiaa", "6161(6a6a|66(6767|6868)66|6969)6161", "Ac_Altstr_Test_4"}, /* control */
78
79 {NULL, NULL, NULL}};
80
81 static const struct ac_sigopts_testdata_s {
82 const char *data;
83 uint32_t dlength;
84 const char *hexsig;
85 const char *offset;
86 const uint16_t sigopts;
87 const char *virname;
88 const uint8_t expected_result;
89 } ac_sigopts_testdata[] = {
90 /* nocase */
91 {"aaaaa", 5, "6161616161", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_1", CL_VIRUS}, /* control */
92 {"bBbBb", 5, "6262626262", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_2", CL_CLEAN}, /* nocase control */
93 {"cCcCc", 5, "6363636363", "*", ACPATT_OPTION_NOCASE, "AC_Sigopts_Test_3", CL_VIRUS}, /* nocase test */
94
95 /* fullword */
96 {"ddddd&e", 7, "6464646464", "*", ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_4", CL_VIRUS}, /* fullword start */
97 {"s&eeeee&e", 9, "6565656565", "*", ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_5", CL_VIRUS}, /* fullword middle */
98 {"s&fffff", 7, "6666666666", "*", ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_6", CL_VIRUS}, /* fullword end */
99 {"sggggg", 6, "6767676767", "*", ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_7", CL_CLEAN}, /* fullword fail start */
100 {"hhhhhe", 6, "6868686868", "*", ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_8", CL_CLEAN}, /* fullword fail end */
101
102 {"iiiii", 5, "(W)6969696969", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_9", CL_VIRUS}, /* fullword class start */
103 {"jjj&jj", 6, "6a6a6a(W)6a6a", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_10", CL_VIRUS}, /* fullword class middle */
104 {"kkkkk", 5, "6b6b6b6b6b(W)", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_11", CL_VIRUS}, /* fullword class end */
105 {"slllll", 6, "(W)6c6c6c6c6c", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_12", CL_CLEAN}, /* fullword fail start */
106 {"mmmmme", 6, "6d6d6d6d6d(W)", "*", ACPATT_OPTION_NOOPTS, "AC_Sigopts_Test_13", CL_CLEAN}, /* fullword class end */
107
108 {"nNnNn", 5, "6e6e6e6e6e", "*", ACPATT_OPTION_NOCASE | ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_14", CL_VIRUS}, /* nocase fullword */
109 {"soOoOo", 6, "6f6f6f6f6f", "*", ACPATT_OPTION_NOCASE | ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_15", CL_CLEAN}, /* nocase fullword start fail */
110 {"pPpPpe", 6, "7070707070", "*", ACPATT_OPTION_NOCASE | ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_16", CL_CLEAN}, /* nocase fullword end fail */
111
112 /* wide */
113 {"q\0q\0q\0q\0q\0", 10, "7171717171", "*", ACPATT_OPTION_WIDE, "AC_Sigopts_Test_17", CL_VIRUS}, /* control */
114 {"r\0R\0r\0R\0r\0", 10, "7272727272", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_NOCASE, "AC_Sigopts_Test_18", CL_VIRUS}, /* control */
115 {"s\0s\0s\0s\0s\0", 10, "7373737373", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_19", CL_VIRUS}, /* control */
116
117 {"t\0t\0t\0t\0t\0", 10, "7474747474", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_ASCII, "AC_Sigopts_Test_20", CL_VIRUS}, /* control */
118
119 {"u\0u\0u\0u\0u\0", 10, "7575757575", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_NOCASE | ACPATT_OPTION_FULLWORD, "AC_Sigopts_Test_21", CL_VIRUS}, /* control */
120 {"v\0v\0v\0v\0v\0", 10, "7676767676", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_NOCASE | ACPATT_OPTION_ASCII, "AC_Sigopts_Test_22", CL_VIRUS}, /* control */
121
122 {"w\0w\0w\0w\0w\0", 10, "7777777777", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_FULLWORD | ACPATT_OPTION_ASCII, "AC_Sigopts_Test_23", CL_VIRUS}, /* control */
123 {"x\0x\0x\0x\0x\0", 10, "7878787878", "*", ACPATT_OPTION_WIDE | ACPATT_OPTION_NOCASE | ACPATT_OPTION_FULLWORD | ACPATT_OPTION_ASCII, "AC_Sigopts_Test_24", CL_VIRUS}, /* control */
124
125 {NULL, 0, NULL, NULL, ACPATT_OPTION_NOOPTS, NULL, CL_CLEAN}};
126
127 #if HAVE_PCRE
128
129 static const struct pcre_testdata_s {
130 const char *data;
131 const char *hexsig;
132 const char *offset;
133 const uint16_t sigopts;
134 const char *virname;
135 const uint8_t expected_result;
136 } pcre_testdata[] = {
137 {"clamav", "/clamav/", "*", ACPATT_OPTION_NOOPTS, "Test_1: simple string", CL_VIRUS},
138 {"cla:mav", "/cla:mav/", "*", ACPATT_OPTION_NOOPTS, "Test_2: embedded colon", CL_VIRUS},
139
140 {"notbasic", "/basic/r", "0", ACPATT_OPTION_NOOPTS, "Test_3: rolling option", CL_VIRUS},
141 {"nottrue", "/true/", "0", ACPATT_OPTION_NOOPTS, "Test4: rolling(off) option", CL_SUCCESS},
142
143 {"not12345678truly", "/12345678/e", "3,8", ACPATT_OPTION_NOOPTS, "Test_5: encompass option", CL_VIRUS},
144 {"not23456789truly", "/23456789/e", "4,8", ACPATT_OPTION_NOOPTS, "Test6: encompass option (low end)", CL_SUCCESS},
145 {"not34567890truly", "/34567890/e", "3,7", ACPATT_OPTION_NOOPTS, "Test7: encompass option (high end)", CL_SUCCESS},
146
147 {"notapietruly", "/apie/re", "2,2", ACPATT_OPTION_NOOPTS, "Test8: rolling encompass", CL_SUCCESS},
148 {"notafigtruly", "/afig/e", "2,2", ACPATT_OPTION_NOOPTS, "Test9: rolling(off) encompass", CL_SUCCESS},
149 {"notatretruly", "/atre/re", "2,6", ACPATT_OPTION_NOOPTS, "Test10: rolling encompass", CL_VIRUS},
150 {"notasadtruly", "/asad/e", "2,6", ACPATT_OPTION_NOOPTS, "Test11: rolling(off) encompass", CL_VIRUS},
151
152 {NULL, NULL, NULL, ACPATT_OPTION_NOOPTS, NULL, CL_CLEAN}};
153
154 #endif /* HAVE_PCRE */
155
156 static cli_ctx ctx;
157 static struct cl_scan_options options;
158
159 static fmap_t thefmap;
160 static const char *virname = NULL;
setup(void)161 static void setup(void)
162 {
163 struct cli_matcher *root;
164 virname = NULL;
165
166 memset(&thefmap, 0, sizeof(thefmap));
167
168 memset(&ctx, 0, sizeof(ctx));
169 memset(&options, 0, sizeof(struct cl_scan_options));
170 ctx.options = &options;
171
172 ctx.virname = &virname;
173 ctx.engine = cl_engine_new();
174 ck_assert_msg(!!ctx.engine, "cl_engine_new() failed");
175
176 ctx.dconf = ctx.engine->dconf;
177
178 ctx.recursion_stack_size = ctx.engine->max_recursion_level;
179 ctx.recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx.recursion_stack_size);
180 ck_assert_msg(!!ctx.recursion_stack, "cli_calloc() for recursion_stack failed");
181
182 // ctx was memset, so recursion_level starts at 0.
183 ctx.recursion_stack[ctx.recursion_level].fmap = &thefmap;
184
185 ctx.fmap = ctx.recursion_stack[ctx.recursion_level].fmap;
186
187 root = (struct cli_matcher *)MPOOL_CALLOC(ctx.engine->mempool, 1, sizeof(struct cli_matcher));
188 ck_assert_msg(root != NULL, "root == NULL");
189 #ifdef USE_MPOOL
190 root->mempool = ctx.engine->mempool;
191 #endif
192
193 ctx.engine->root[0] = root;
194 }
195
teardown(void)196 static void teardown(void)
197 {
198 cl_engine_free((struct cl_engine *)ctx.engine);
199 free(ctx.recursion_stack);
200 }
201
START_TEST(test_ac_scanbuff)202 START_TEST(test_ac_scanbuff)
203 {
204 struct cli_ac_data mdata;
205 struct cli_matcher *root;
206 unsigned int i;
207 int ret;
208
209 root = ctx.engine->root[0];
210 ck_assert_msg(root != NULL, "root == NULL");
211 root->ac_only = 1;
212
213 #ifdef USE_MPOOL
214 root->mempool = mpool_create();
215 #endif
216 ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1);
217 ck_assert_msg(ret == CL_SUCCESS, "cli_ac_init() failed");
218
219 for (i = 0; ac_testdata[i].data; i++) {
220 ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, 0, "*", 0, NULL, 0);
221 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
222 }
223
224 ret = cli_ac_buildtrie(root);
225 ck_assert_msg(ret == CL_SUCCESS, "cli_ac_buildtrie() failed");
226
227 ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
228 ck_assert_msg(ret == CL_SUCCESS, "cli_ac_initdata() failed");
229
230 ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
231 for (i = 0; ac_testdata[i].data; i++) {
232 ret = cli_ac_scanbuff((const unsigned char *)ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
233 ck_assert_msg(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname);
234 ck_assert_msg(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
235
236 ret = cli_scan_buff((const unsigned char *)ac_testdata[i].data, strlen(ac_testdata[i].data), 0, &ctx, 0, NULL);
237 ck_assert_msg(ret == CL_VIRUS, "cli_scan_buff() failed for %s", ac_testdata[i].virname);
238 ck_assert_msg(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
239 }
240
241 cli_ac_freedata(&mdata);
242 }
243 END_TEST
244
START_TEST(test_ac_scanbuff_allscan)245 START_TEST(test_ac_scanbuff_allscan)
246 {
247 struct cli_ac_data mdata;
248 struct cli_matcher *root;
249 unsigned int i;
250 int ret;
251
252 root = ctx.engine->root[0];
253 ck_assert_msg(root != NULL, "root == NULL");
254 root->ac_only = 1;
255
256 #ifdef USE_MPOOL
257 root->mempool = mpool_create();
258 #endif
259 ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1);
260 ck_assert_msg(ret == CL_SUCCESS, "cli_ac_init() failed");
261
262 for (i = 0; ac_testdata[i].data; i++) {
263 ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, 0, "*", 0, NULL, 0);
264 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
265 }
266
267 ret = cli_ac_buildtrie(root);
268 ck_assert_msg(ret == CL_SUCCESS, "cli_ac_buildtrie() failed");
269
270 ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
271 ck_assert_msg(ret == CL_SUCCESS, "cli_ac_initdata() failed");
272
273 ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
274 for (i = 0; ac_testdata[i].data; i++) {
275 ret = cli_ac_scanbuff((const unsigned char *)ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
276 ck_assert_msg(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname);
277 ck_assert_msg(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
278
279 ret = cli_scan_buff((const unsigned char *)ac_testdata[i].data, strlen(ac_testdata[i].data), 0, &ctx, 0, NULL);
280 ck_assert_msg(ret == CL_VIRUS, "cli_scan_buff() failed for %s", ac_testdata[i].virname);
281 ck_assert_msg(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
282 if (ctx.num_viruses)
283 ctx.num_viruses = 0;
284 }
285
286 cli_ac_freedata(&mdata);
287 }
288 END_TEST
289
START_TEST(test_ac_scanbuff_ex)290 START_TEST(test_ac_scanbuff_ex)
291 {
292 struct cli_ac_data mdata;
293 struct cli_matcher *root;
294 unsigned int i;
295 int ret;
296
297 root = ctx.engine->root[0];
298 ck_assert_msg(root != NULL, "root == NULL");
299 root->ac_only = 1;
300
301 #ifdef USE_MPOOL
302 root->mempool = mpool_create();
303 #endif
304 ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1);
305 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_ac_init() failed");
306
307 for (i = 0; ac_sigopts_testdata[i].data; i++) {
308 ret = cli_sigopts_handler(root, ac_sigopts_testdata[i].virname, ac_sigopts_testdata[i].hexsig, ac_sigopts_testdata[i].sigopts, 0, 0, ac_sigopts_testdata[i].offset, 0, NULL, 0);
309 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_sigopts_handler() failed");
310 }
311
312 ret = cli_ac_buildtrie(root);
313 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_ac_buildtrie() failed");
314
315 ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
316 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_ac_initdata() failed");
317
318 ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
319 for (i = 0; ac_sigopts_testdata[i].data; i++) {
320 ret = cli_ac_scanbuff((const unsigned char *)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
321 ck_assert_msg(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result);
322 if (ac_sigopts_testdata[i].expected_result == CL_VIRUS)
323 ck_assert_msg(!strncmp(virname, ac_sigopts_testdata[i].virname, strlen(ac_sigopts_testdata[i].virname)), "[ac_ex] Dataset %u matched with %s", i, virname);
324
325 ret = cli_scan_buff((const unsigned char *)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, 0, &ctx, 0, NULL);
326 ck_assert_msg(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result);
327 }
328
329 cli_ac_freedata(&mdata);
330 }
331 END_TEST
332
START_TEST(test_ac_scanbuff_allscan_ex)333 START_TEST(test_ac_scanbuff_allscan_ex)
334 {
335 struct cli_ac_data mdata;
336 struct cli_matcher *root;
337 unsigned int i;
338 int ret;
339
340 root = ctx.engine->root[0];
341 ck_assert_msg(root != NULL, "root == NULL");
342 root->ac_only = 1;
343
344 #ifdef USE_MPOOL
345 root->mempool = mpool_create();
346 #endif
347 ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1);
348 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_ac_init() failed");
349
350 for (i = 0; ac_sigopts_testdata[i].data; i++) {
351 ret = cli_sigopts_handler(root, ac_sigopts_testdata[i].virname, ac_sigopts_testdata[i].hexsig, ac_sigopts_testdata[i].sigopts, 0, 0, ac_sigopts_testdata[i].offset, 0, NULL, 0);
352 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_sigopts_handler() failed");
353 }
354
355 ret = cli_ac_buildtrie(root);
356 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_ac_buildtrie() failed");
357
358 ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
359 ck_assert_msg(ret == CL_SUCCESS, "[ac_ex] cli_ac_initdata() failed");
360
361 ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
362 for (i = 0; ac_sigopts_testdata[i].data; i++) {
363 ret = cli_ac_scanbuff((const unsigned char *)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
364 ck_assert_msg(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result);
365 if (ac_sigopts_testdata[i].expected_result == CL_VIRUS)
366 ck_assert_msg(!strncmp(virname, ac_sigopts_testdata[i].virname, strlen(ac_sigopts_testdata[i].virname)), "[ac_ex] Dataset %u matched with %s", i, virname);
367
368 ret = cli_scan_buff((const unsigned char *)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, 0, &ctx, 0, NULL);
369 ck_assert_msg(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result);
370 if (ctx.num_viruses)
371 ctx.num_viruses = 0;
372 }
373
374 cli_ac_freedata(&mdata);
375 }
376 END_TEST
377
START_TEST(test_bm_scanbuff)378 START_TEST(test_bm_scanbuff)
379 {
380 struct cli_matcher *root;
381 const char *virname = NULL;
382 int ret;
383
384 root = ctx.engine->root[0];
385 ck_assert_msg(root != NULL, "root == NULL");
386
387 #ifdef USE_MPOOL
388 root->mempool = mpool_create();
389 #endif
390 ret = cli_bm_init(root);
391 ck_assert_msg(ret == CL_SUCCESS, "cli_bm_init() failed");
392
393 ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, 0, "*", 0, NULL, 0);
394 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
395 ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, 0, "*", 0, NULL, 0);
396 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
397 ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, 0, "*", 0, NULL, 0);
398 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
399
400 ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
401 ret = cli_bm_scanbuff((const unsigned char *)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
402 ck_assert_msg(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
403 ck_assert_msg(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
404 }
405 END_TEST
406
START_TEST(test_bm_scanbuff_allscan)407 START_TEST(test_bm_scanbuff_allscan)
408 {
409 struct cli_matcher *root;
410 const char *virname = NULL;
411 int ret;
412
413 root = ctx.engine->root[0];
414 ck_assert_msg(root != NULL, "root == NULL");
415
416 #ifdef USE_MPOOL
417 root->mempool = mpool_create();
418 #endif
419 ret = cli_bm_init(root);
420 ck_assert_msg(ret == CL_SUCCESS, "cli_bm_init() failed");
421
422 ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, 0, "*", 0, NULL, 0);
423 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
424 ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, 0, "*", 0, NULL, 0);
425 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
426 ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, 0, "*", 0, NULL, 0);
427 ck_assert_msg(ret == CL_SUCCESS, "cli_parse_add() failed");
428
429 ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
430 ret = cli_bm_scanbuff((const unsigned char *)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
431 ck_assert_msg(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
432 ck_assert_msg(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
433 }
434 END_TEST
435
436 #if HAVE_PCRE
437
START_TEST(test_pcre_scanbuff)438 START_TEST(test_pcre_scanbuff)
439 {
440 struct cli_ac_data mdata;
441 struct cli_matcher *root;
442 char *hexsig;
443 unsigned int i, hexlen;
444 int ret;
445
446 root = ctx.engine->root[0];
447 ck_assert_msg(root != NULL, "root == NULL");
448
449 #ifdef USE_MPOOL
450 root->mempool = mpool_create();
451 #endif
452 ret = cli_pcre_init();
453 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_pcre_init() failed");
454
455 for (i = 0; pcre_testdata[i].data; i++) {
456 hexlen = strlen(PCRE_BYPASS) + strlen(pcre_testdata[i].hexsig) + 1;
457
458 hexsig = cli_calloc(hexlen, sizeof(char));
459 ck_assert_msg(hexsig != NULL, "[pcre] failed to prepend bypass (out-of-memory)");
460
461 strncat(hexsig, PCRE_BYPASS, hexlen);
462 strncat(hexsig, pcre_testdata[i].hexsig, hexlen);
463
464 ret = cli_parse_add(root, pcre_testdata[i].virname, hexsig, pcre_testdata[i].sigopts, 0, 0, pcre_testdata[i].offset, 0, NULL, 0);
465 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_parse_add() failed");
466 free(hexsig);
467 }
468
469 ret = cli_pcre_build(root, CLI_DEFAULT_PCRE_MATCH_LIMIT, CLI_DEFAULT_PCRE_RECMATCH_LIMIT, NULL);
470 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_pcre_build() failed");
471
472 // recomputate offsets
473
474 ret = cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
475 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_ac_initdata() failed");
476
477 ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
478 for (i = 0; pcre_testdata[i].data; i++) {
479 ret = cli_pcre_scanbuf((const unsigned char *)pcre_testdata[i].data, strlen(pcre_testdata[i].data), &virname, NULL, root, NULL, NULL, NULL);
480 ck_assert_msg(ret == pcre_testdata[i].expected_result, "[pcre] cli_pcre_scanbuff() failed for %s (%d != %d)", pcre_testdata[i].virname, ret, pcre_testdata[i].expected_result);
481 if (pcre_testdata[i].expected_result == CL_VIRUS)
482 ck_assert_msg(!strncmp(virname, pcre_testdata[i].virname, strlen(pcre_testdata[i].virname)), "[pcre] Dataset %u matched with %s", i, virname);
483
484 ret = cli_scan_buff((const unsigned char *)pcre_testdata[i].data, strlen(pcre_testdata[i].data), 0, &ctx, 0, NULL);
485 ck_assert_msg(ret == pcre_testdata[i].expected_result, "[pcre] cli_scan_buff() failed for %s", pcre_testdata[i].virname);
486 }
487
488 cli_ac_freedata(&mdata);
489 }
490 END_TEST
491
START_TEST(test_pcre_scanbuff_allscan)492 START_TEST(test_pcre_scanbuff_allscan)
493 {
494 struct cli_ac_data mdata;
495 struct cli_matcher *root;
496 char *hexsig;
497 unsigned int i, hexlen;
498 int ret;
499
500 root = ctx.engine->root[0];
501 ck_assert_msg(root != NULL, "root == NULL");
502
503 #ifdef USE_MPOOL
504 root->mempool = mpool_create();
505 #endif
506 ret = cli_pcre_init();
507 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_pcre_init() failed");
508
509 for (i = 0; pcre_testdata[i].data; i++) {
510 hexlen = strlen(PCRE_BYPASS) + strlen(pcre_testdata[i].hexsig) + 1;
511
512 hexsig = cli_calloc(hexlen, sizeof(char));
513 ck_assert_msg(hexsig != NULL, "[pcre] failed to prepend bypass (out-of-memory)");
514
515 strncat(hexsig, PCRE_BYPASS, hexlen);
516 strncat(hexsig, pcre_testdata[i].hexsig, hexlen);
517
518 ret = cli_parse_add(root, pcre_testdata[i].virname, hexsig, 0, 0, 0, pcre_testdata[i].offset, 0, NULL, 0);
519 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_parse_add() failed");
520 free(hexsig);
521 }
522
523 ret = cli_pcre_build(root, CLI_DEFAULT_PCRE_MATCH_LIMIT, CLI_DEFAULT_PCRE_RECMATCH_LIMIT, NULL);
524 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_pcre_build() failed");
525
526 // recomputate offsets
527
528 ret = cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
529 ck_assert_msg(ret == CL_SUCCESS, "[pcre] cli_ac_initdata() failed");
530
531 ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
532 for (i = 0; pcre_testdata[i].data; i++) {
533 ret = cli_pcre_scanbuf((const unsigned char *)pcre_testdata[i].data, strlen(pcre_testdata[i].data), &virname, NULL, root, NULL, NULL, NULL);
534 ck_assert_msg(ret == pcre_testdata[i].expected_result, "[pcre] cli_pcre_scanbuff() failed for %s (%d != %d)", pcre_testdata[i].virname, ret, pcre_testdata[i].expected_result);
535 if (pcre_testdata[i].expected_result == CL_VIRUS)
536 ck_assert_msg(!strncmp(virname, pcre_testdata[i].virname, strlen(pcre_testdata[i].virname)), "[pcre] Dataset %u matched with %s", i, virname);
537
538 ret = cli_scan_buff((const unsigned char *)pcre_testdata[i].data, strlen(pcre_testdata[i].data), 0, &ctx, 0, NULL);
539 ck_assert_msg(ret == pcre_testdata[i].expected_result, "[pcre] cli_scan_buff() failed for %s", pcre_testdata[i].virname);
540 /* num_virus field add to test case struct */
541 if (ctx.num_viruses)
542 ctx.num_viruses = 0;
543 }
544
545 cli_ac_freedata(&mdata);
546 }
547 END_TEST
548
549 #endif /* HAVE_PCRE */
550
test_matchers_suite(void)551 Suite *test_matchers_suite(void)
552 {
553 Suite *s = suite_create("matchers");
554 TCase *tc_matchers;
555 tc_matchers = tcase_create("matchers");
556 suite_add_tcase(s, tc_matchers);
557 tcase_add_checked_fixture(tc_matchers, setup, teardown);
558 tcase_add_test(tc_matchers, test_ac_scanbuff);
559 tcase_add_test(tc_matchers, test_ac_scanbuff_ex);
560 tcase_add_test(tc_matchers, test_bm_scanbuff);
561 #if HAVE_PCRE
562 tcase_add_test(tc_matchers, test_pcre_scanbuff);
563 #endif
564 tcase_add_test(tc_matchers, test_ac_scanbuff_allscan);
565 tcase_add_test(tc_matchers, test_ac_scanbuff_allscan_ex);
566 tcase_add_test(tc_matchers, test_bm_scanbuff_allscan);
567 #if HAVE_PCRE
568 tcase_add_test(tc_matchers, test_pcre_scanbuff_allscan);
569 #endif
570 return s;
571 }
572