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