1 //--------------------------------------------------------------------------
2 // Copyright (C) 2016-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // search_tool_test.cc author Steve Chew <stechew@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 // Change private to public to give access to private members.
26 #define private public
27 #include "search_engines/search_tool.h"
28 #undef private
29
30 #include <cstring>
31
32 #include "detection/fp_config.h"
33 #include "framework/base_api.h"
34 #include "framework/mpse.h"
35 #include "framework/mpse_batch.h"
36 #include "main/snort_config.h"
37 #include "managers/mpse_manager.h"
38
39 // must appear after snort_config.h to avoid broken c++ map include
40 #include <CppUTest/CommandLineTestRunner.h>
41 #include <CppUTest/TestHarness.h>
42
43 using namespace snort;
44
45 //-------------------------------------------------------------------------
46 // base stuff
47 //-------------------------------------------------------------------------
48
49 namespace snort
50 {
51 SnortConfig s_conf;
52
53 THREAD_LOCAL SnortConfig* snort_conf = &s_conf;
54
55 static std::vector<void *> s_state;
56
SnortConfig(const SnortConfig * const,const char *)57 SnortConfig::SnortConfig(const SnortConfig* const, const char*)
58 {
59 state = &s_state;
60 num_slots = 1;
61 fast_pattern_config = nullptr;
62 }
63
64 SnortConfig::~SnortConfig() = default;
65
get_conf()66 const SnortConfig* SnortConfig::get_conf()
67 { return snort_conf; }
68
get_instance_id()69 unsigned get_instance_id()
70 { return 0; }
71
LogValue(const char *,const char *,FILE *)72 void LogValue(const char*, const char*, FILE*) { }
LogMessage(const char *,...)73 void LogMessage(const char*, ...) { }
FatalError(const char *,...)74 [[noreturn]] void FatalError(const char*,...) { exit(1); }
LogCount(char const *,uint64_t,FILE *)75 void LogCount(char const*, uint64_t, FILE*) { }
LogStat(const char *,double,FILE *)76 void LogStat(const char*, double, FILE*) { }
77
78 static void* s_tree = (void*)"tree";
79 static void* s_list = (void*)"list";
80
81 static MpseAgent s_agent =
82 {
83 [](struct SnortConfig* sc, void*, void** ppt)
__anon529a470f0102() 84 {
85 CHECK(sc == nullptr);
86 *ppt = s_tree;
87 return 0;
88 },
89 [](void*, void** ppl)
__anon529a470f0202() 90 {
91 *ppl = s_list;
92 return 0;
93 },
94
__anon529a470f0302() 95 [](void*) { },
__anon529a470f0402() 96 [](void** ppt) { CHECK(*ppt == s_tree); },
__anon529a470f0502() 97 [](void** ppl) { CHECK(*ppl == s_list); }
98 };
99
Mpse(const char *)100 Mpse::Mpse(const char*) { }
101
search(const unsigned char * T,int n,MpseMatch match,void * context,int * current_state)102 int Mpse::search(
103 const unsigned char* T, int n, MpseMatch match,
104 void* context, int* current_state)
105 {
106 return _search(T, n, match, context, current_state);
107 }
108
search_all(const unsigned char * T,int n,MpseMatch match,void * context,int * current_state)109 int Mpse::search_all(
110 const unsigned char* T, int n, MpseMatch match,
111 void* context, int* current_state)
112 {
113 return _search(T, n, match, context, current_state);
114 }
115
search(MpseBatch &,MpseType)116 void Mpse::search(MpseBatch&, MpseType) { }
_search(MpseBatch &,MpseType)117 void Mpse::_search(MpseBatch&, MpseType) { }
118
119 }
120
get_search_method()121 const char* FastPatternConfig::get_search_method()
122 { return "ac_bnfa"; }
123
124 extern const BaseApi* se_ac_bnfa;
125 extern const BaseApi* se_ac_full;
126 Mpse* mpse = nullptr;
127
delete_search_engine(Mpse * eng)128 void MpseManager::delete_search_engine(Mpse* eng)
129 {
130 const MpseApi* api = eng->get_api();
131 api->dtor(eng);
132 }
133
~MpseGroup()134 MpseGroup::~MpseGroup()
135 {
136 if (normal_mpse)
137 {
138 MpseManager::delete_search_engine(normal_mpse);
139 normal_mpse = nullptr;
140 }
141 if (offload_mpse)
142 {
143 MpseManager::delete_search_engine(offload_mpse);
144 offload_mpse = nullptr;
145 }
146 }
147
create_normal_mpse(const SnortConfig *,const char * type)148 bool MpseGroup::create_normal_mpse(const SnortConfig*, const char* type)
149 {
150 const MpseApi* api;
151
152 if ( !strcmp(type, "ac_bnfa") )
153 api = (const MpseApi*) se_ac_bnfa;
154
155 else if ( !strcmp(type, "ac_full") )
156 api = (const MpseApi*) se_ac_full;
157
158 else
159 return false;
160
161 api->init();
162 mpse = api->ctor(snort_conf, nullptr, &s_agent);
163
164 CHECK(mpse);
165
166 mpse->set_api(api);
167 normal_mpse = mpse;
168
169 return true;
170 }
171
create_offload_mpse(const SnortConfig *)172 bool MpseGroup::create_offload_mpse(const SnortConfig*)
173 {
174 offload_mpse = nullptr;
175 return false;
176 }
177
178 struct ExpectedMatch
179 {
180 int id;
181 int offset;
182 };
183
184 static const ExpectedMatch* s_expect = nullptr;
185 static int s_found = 0;
186
Test_SearchStrFound(void * pid,void *,int index,void *,void *)187 static int Test_SearchStrFound(
188 void* pid, void* /*tree*/, int index, void* /*context*/, void* /*neg_list*/)
189 {
190 auto id = reinterpret_cast<std::uintptr_t>(pid);
191
192 if ( s_expect and s_found >= 0 and
193 s_expect[s_found].id == (int)id and
194 s_expect[s_found].offset == index )
195 {
196 ++s_found;
197 }
198 else s_found = -1;
199
200 return s_found == -1;
201 }
202
203 //-------------------------------------------------------------------------
204 // ac_bnfa tests
205 //-------------------------------------------------------------------------
206
TEST_GROUP(search_tool_bnfa)207 TEST_GROUP(search_tool_bnfa)
208 {
209 SearchTool* stool;
210
211 void setup() override
212 {
213 CHECK(se_ac_bnfa);
214 SearchTool::set_conf(snort_conf);
215 stool = new SearchTool("ac_bnfa");
216 SearchTool::set_conf(nullptr);
217
218 CHECK(stool->mpsegrp->normal_mpse);
219
220 int pattern_id = 1;
221 stool->add("the", 3, pattern_id);
222 CHECK(stool->max_len == 3);
223
224 pattern_id = 77;
225 stool->add("tuba", 4, pattern_id);
226 CHECK(stool->max_len == 4);
227
228 pattern_id = 78;
229 stool->add("uba", 3, pattern_id);
230 CHECK(stool->max_len == 4);
231
232 pattern_id = 2112;
233 stool->add("away", 4, pattern_id);
234 CHECK(stool->max_len == 4);
235
236 pattern_id = 1000;
237 stool->add("nothere", 7, pattern_id);
238 CHECK(stool->max_len == 7);
239
240 stool->prep();
241
242 }
243 void teardown() override
244 {
245 delete stool;
246 }
247 };
248
TEST(search_tool_bnfa,search)249 TEST(search_tool_bnfa, search)
250 {
251 // 0 1 2 3
252 // 0123456789012345678901234567890
253 const char* datastr = "the tuba ran away with the tuna";
254 const ExpectedMatch xm[] =
255 {
256 { 1, 3 },
257 { 78, 8 },
258 { 2112, 17 },
259 { 1, 26 },
260 { 0, 0 }
261 };
262
263 s_expect = xm;
264 s_found = 0;
265
266 int result = stool->find(datastr, strlen(datastr), Test_SearchStrFound);
267
268 CHECK(result == 4);
269 CHECK(s_found == 4);
270 }
271
TEST(search_tool_bnfa,search_all)272 TEST(search_tool_bnfa, search_all)
273 {
274 // 0 1 2 3
275 // 0123456789012345678901234567890
276 const char* datastr = "the tuba ran away with the tuna";
277 const ExpectedMatch xm[] =
278 {
279 { 1, 3 },
280 { 78, 8 },
281 { 2112, 17 },
282 { 1, 26 },
283 { 0, 0 }
284 };
285
286 s_expect = xm;
287 s_found = 0;
288
289 int result = stool->find_all(datastr, strlen(datastr), Test_SearchStrFound);
290
291 CHECK(result == 4);
292 CHECK(s_found == 4);
293 }
294
295 //-------------------------------------------------------------------------
296 // ac_full tests
297 //-------------------------------------------------------------------------
298
TEST_GROUP(search_tool_full)299 TEST_GROUP(search_tool_full)
300 {
301 SearchTool* stool;
302
303 void setup() override
304 {
305 CHECK(se_ac_full);
306 SearchTool::set_conf(snort_conf);
307 stool = new SearchTool("ac_full", true);
308 SearchTool::set_conf(nullptr);
309
310 CHECK(stool->mpsegrp->normal_mpse);
311
312 int pattern_id = 1;
313 stool->add("the", 3, pattern_id);
314 CHECK(stool->max_len == 3);
315
316 pattern_id = 77;
317 stool->add("tuba", 4, pattern_id);
318 CHECK(stool->max_len == 4);
319
320 pattern_id = 78;
321 stool->add("uba", 3, pattern_id);
322 CHECK(stool->max_len == 4);
323
324 pattern_id = 2112;
325 stool->add("away", 4, pattern_id);
326 CHECK(stool->max_len == 4);
327
328 pattern_id = 1000;
329 stool->add("nothere", 7, pattern_id);
330 CHECK(stool->max_len == 7);
331
332 stool->prep();
333
334 }
335 void teardown() override
336 {
337 delete stool;
338 }
339 };
340
TEST(search_tool_full,search)341 TEST(search_tool_full, search)
342 {
343 // 0 1 2 3
344 // 0123456789012345678901234567890
345 const char* datastr = "the tuba ran away with the tuna";
346 const ExpectedMatch xm[] =
347 {
348 { 1, 3 },
349 { 78, 8 },
350 { 2112, 17 },
351 { 1, 26 },
352 { 0, 0 }
353 };
354
355 s_expect = xm;
356 s_found = 0;
357
358 int result = stool->find(datastr, strlen(datastr), Test_SearchStrFound);
359
360 CHECK(result == 4);
361 CHECK(s_found == 4);
362 }
363
TEST(search_tool_full,search_all)364 TEST(search_tool_full, search_all)
365 {
366 // 0 1 2 3
367 // 0123456789012345678901234567890
368 const char* datastr = "the tuba ran away with the tuna";
369 const ExpectedMatch xm[] =
370 {
371 { 1, 3 },
372 { 78, 8 },
373 { 77, 8 },
374 { 2112, 17 },
375 { 1, 26 },
376 { 0, 0 }
377 };
378
379 s_expect = xm;
380 s_found = 0;
381
382 int result = stool->find_all(datastr, strlen(datastr), Test_SearchStrFound);
383
384 CHECK(result == 5);
385 CHECK(s_found == 5);
386 }
387
388 //-------------------------------------------------------------------------
389 // main
390 //-------------------------------------------------------------------------
391
main(int argc,char ** argv)392 int main(int argc, char** argv)
393 {
394 return CommandLineTestRunner::RunAllTests(argc, argv);
395 }
396
397