2
* Unit tests for bytecode functions.
4
* Copyright (C) 2009 Sourcefire, Inc.
6
* Authors: Tƶrƶk Edvin
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.
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.
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,
23
#include "clamav-config.h"
34
#include "../libclamav/clamav.h"
35
#include "../libclamav/others.h"
36
#include "../libclamav/bytecode.h"
38
#include "../libclamav/dconf.h"
39
#include "../libclamav/bytecode_priv.h"
40
#include "../libclamav/pe.h"
45
static void runtest(const char *file, uint64_t expected, int fail, int nojit,
46
const char *infile, struct cli_pe_hook_data *pedata,
47
struct cli_exe_section *sections, const char *expectedvirname,
52
int fd = open_testfile(file);
56
struct cli_bc_ctx *ctx;
57
struct cli_all_bc bcs;
59
struct cl_engine *engine;
62
memset(&cctx, 0, sizeof(cctx));
63
cctx.engine = engine = cl_engine_new();
64
fail_unless(!!cctx.engine, "cannot create engine");
65
rc = cl_engine_compile(engine);
66
fail_unless(!rc, "cannot compile engine");
67
cctx.fmap = cli_calloc(sizeof(fmap_t*), engine->maxreclevel + 2);
68
fail_unless(!!cctx.fmap, "cannot allocate fmap");
70
fail_unless(fd >= 0, "retmagic open failed");
72
fail_unless(!!f, "retmagic fdopen failed");
77
rc = cli_bytecode_init(&bcs);
78
fail_unless(rc == CL_SUCCESS, "cli_bytecode_init failed");
86
rc = cli_bytecode_load(&bc, f, NULL, 1);
87
fail_unless(rc == CL_SUCCESS, "cli_bytecode_load failed");
90
if (testmode && have_clamjit)
91
engine->bytecode_mode = CL_BYTECODE_MODE_TEST;
93
rc = cli_bytecode_prepare2(engine, &bcs, BYTECODE_ENGINE_MASK);
94
fail_unless(rc == CL_SUCCESS, "cli_bytecode_prepare failed");
96
if (have_clamjit && !nojit && nojit != -1 && !testmode) {
97
fail_unless(bc.state == bc_jit, "preparing for JIT failed");
100
ctx = cli_bytecode_context_alloc();
101
ctx->bytecode_timeout = fail == CL_ETIMEOUT ? 10 : 10000;
102
fail_unless(!!ctx, "cli_bytecode_context_alloc failed");
106
fdin = open(infile, O_RDONLY);
107
if (fdin < 0 && errno == ENOENT)
108
fdin = open_testfile(infile);
109
fail_unless(fdin >= 0, "failed to open infile");
110
map = fmap(fdin, 0, 0);
111
fail_unless(!!map, "unable to fmap infile");
113
ctx->hooks.pedata = pedata;
114
ctx->sections = sections;
115
cli_bytecode_context_setfile(ctx, map);
118
cli_bytecode_context_setfuncid(ctx, &bc, 0);
119
rc = cli_bytecode_run(&bcs, &bc, ctx);
120
fail_unless_fmt(rc == fail, "cli_bytecode_run failed, expected: %u, have: %u\n",
123
if (rc == CL_SUCCESS) {
124
v = cli_bytecode_context_getresult_int(ctx);
125
fail_unless_fmt(v == expected, "Invalid return value from bytecode run, expected: %llx, have: %llx\n",
128
if (infile && expectedvirname) {
129
fail_unless(ctx->virname &&
130
!strcmp(ctx->virname, expectedvirname),
131
"Invalid virname, expected: %s\n", expectedvirname);
133
cli_bytecode_context_destroy(ctx);
136
cli_bytecode_destroy(&bc);
137
cli_bytecode_done(&bcs);
139
cl_engine_free(engine);
144
START_TEST (test_retmagic_jit)
146
cl_init(CL_INIT_DEFAULT);
147
runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
148
runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 1);
152
START_TEST (test_retmagic_int)
154
cl_init(CL_INIT_DEFAULT);
155
runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
159
START_TEST (test_arith_jit)
161
cl_init(CL_INIT_DEFAULT);
162
runtest("input/arith.cbc", 0xd5555555, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
166
START_TEST (test_arith_int)
168
cl_init(CL_INIT_DEFAULT);
169
runtest("input/arith.cbc", 0xd5555555, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
173
START_TEST (test_apicalls_jit)
175
cl_init(CL_INIT_DEFAULT);
176
runtest("input/apicalls.cbc", 0xf00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
180
START_TEST (test_apicalls_int)
182
runtest("input/apicalls.cbc", 0xf00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
186
START_TEST (test_apicalls2_jit)
188
cl_init(CL_INIT_DEFAULT);
189
runtest("input/apicalls2.cbc", 0xf00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
193
START_TEST (test_apicalls2_int)
195
cl_init(CL_INIT_DEFAULT);
196
runtest("input/apicalls2.cbc", 0xf00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
200
START_TEST (test_div0_jit)
202
cl_init(CL_INIT_DEFAULT);
203
/* must not crash on div#0 but catch it */
204
runtest("input/div0.cbc", 0, CL_EBYTECODE, 0, NULL, NULL, NULL, NULL, 0);
208
START_TEST (test_div0_int)
210
cl_init(CL_INIT_DEFAULT);
211
runtest("input/div0.cbc", 0, CL_EBYTECODE, 1, NULL, NULL, NULL, NULL, 0);
215
START_TEST (test_lsig_jit)
217
cl_init(CL_INIT_DEFAULT);
218
runtest("input/lsig.cbc", 0, 0, 0, NULL, NULL, NULL, NULL, 0);
222
START_TEST (test_lsig_int)
224
runtest("input/lsig.cbc", 0, 0, 1, NULL, NULL, NULL, NULL, 0);
228
START_TEST (test_inf_jit)
230
cl_init(CL_INIT_DEFAULT);
231
runtest("input/inf.cbc", 0, CL_ETIMEOUT, 0, NULL, NULL, NULL, NULL, 0);
235
START_TEST (test_inf_int)
237
cl_init(CL_INIT_DEFAULT);
238
runtest("input/inf.cbc", 0, CL_ETIMEOUT, 1, NULL, NULL, NULL, NULL, 0);
242
START_TEST (test_matchwithread_jit)
244
struct cli_exe_section sect;
245
struct cli_pe_hook_data pedata;
246
cl_init(CL_INIT_DEFAULT);
247
memset(&pedata, 0, sizeof(pedata));
249
cli_writeint32(&pedata.opt32.ImageBase, 0x400000);
250
pedata.hdr_size = 0x400;
251
pedata.nsections = 1;
260
runtest("input/matchwithread.cbc", 0, 0, 0, "../test/clam.exe", &pedata,
261
§, "ClamAV-Test-File-detected-via-bytecode", 0);
265
START_TEST (test_matchwithread_int)
267
struct cli_exe_section sect;
268
struct cli_pe_hook_data pedata;
269
cl_init(CL_INIT_DEFAULT);
270
memset(&pedata, 0, sizeof(pedata));
272
cli_writeint32(&pedata.opt32.ImageBase, 0x400000);
273
pedata.hdr_size = 0x400;
274
pedata.nsections = 1;
283
runtest("input/matchwithread.cbc", 0, 0, 1, "../test/clam.exe", &pedata,
284
§, "ClamAV-Test-File-detected-via-bytecode", 0);
289
START_TEST (test_pdf_jit)
291
cl_init(CL_INIT_DEFAULT);
292
runtest("input/pdf.cbc", 0, 0, 0, NULL, NULL, NULL, NULL, 0);
296
START_TEST (test_pdf_int)
298
cl_init(CL_INIT_DEFAULT);
299
runtest("input/pdf.cbc", 0, 0, 1, NULL, NULL, NULL, NULL, 0);
303
START_TEST (test_bswap_jit)
305
cl_init(CL_INIT_DEFAULT);
306
runtest("input/bswap.cbc", 0xbeef, 0, 0, NULL, NULL, NULL, NULL, 0);
310
START_TEST (test_bswap_int)
312
cl_init(CL_INIT_DEFAULT);
313
runtest("input/bswap.cbc", 0xbeef, 0, 1, NULL, NULL, NULL, NULL, 0);
317
START_TEST (test_inflate_jit)
319
cl_init(CL_INIT_DEFAULT);
320
runtest("input/inflate.cbc", 0xbeef, 0, 1, NULL, NULL, NULL, NULL, 0);
324
START_TEST (test_inflate_int)
326
cl_init(CL_INIT_DEFAULT);
327
runtest("input/inflate.cbc", 0xbeef, 0, 0, NULL, NULL, NULL, NULL, 0);
331
START_TEST (test_api_extract_jit)
333
cl_init(CL_INIT_DEFAULT);
334
runtest("input/api_extract_7.cbc", 0xf00d, 0, 0, "input/apitestfile", NULL, NULL, NULL, 0);
338
START_TEST (test_api_files_jit)
340
cl_init(CL_INIT_DEFAULT);
341
runtest("input/api_files_7.cbc", 0xf00d, 0, 0, "input/apitestfile", NULL, NULL, NULL, 0);
345
START_TEST (test_apicalls2_7_jit)
347
cl_init(CL_INIT_DEFAULT);
348
runtest("input/apicalls2_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
352
START_TEST (test_apicalls_7_jit)
354
cl_init(CL_INIT_DEFAULT);
355
runtest("input/apicalls_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
359
START_TEST (test_arith_7_jit)
361
cl_init(CL_INIT_DEFAULT);
362
runtest("input/arith_7.cbc", 0xd55555dd, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
366
START_TEST (test_debug_jit)
368
cl_init(CL_INIT_DEFAULT);
369
runtest("input/debug_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
373
START_TEST (test_inf_7_jit)
375
cl_init(CL_INIT_DEFAULT);
376
runtest("input/inf_7.cbc", 0, CL_ETIMEOUT, 0, NULL, NULL, NULL, NULL, 0);
380
START_TEST (test_lsig_7_jit)
382
cl_init(CL_INIT_DEFAULT);
383
runtest("input/lsig_7.cbc", 0, 0, 0, NULL, NULL, NULL, NULL, 0);
387
START_TEST (test_retmagic_7_jit)
389
cl_init(CL_INIT_DEFAULT);
390
runtest("input/retmagic_7.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
394
START_TEST (test_testadt_jit)
396
cl_init(CL_INIT_DEFAULT);
397
runtest("input/testadt_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
401
START_TEST (test_api_extract_int)
403
cl_init(CL_INIT_DEFAULT);
404
runtest("input/api_extract_7.cbc", 0xf00d, 0, 1, "input/apitestfile", NULL, NULL, NULL, 0);
408
START_TEST (test_api_files_int)
410
cl_init(CL_INIT_DEFAULT);
411
runtest("input/api_files_7.cbc", 0xf00d, 0, 1, "input/apitestfile", NULL, NULL, NULL, 0);
415
START_TEST (test_apicalls2_7_int)
417
cl_init(CL_INIT_DEFAULT);
418
runtest("input/apicalls2_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
422
START_TEST (test_apicalls_7_int)
424
cl_init(CL_INIT_DEFAULT);
425
runtest("input/apicalls_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
429
START_TEST (test_arith_7_int)
431
cl_init(CL_INIT_DEFAULT);
432
runtest("input/arith_7.cbc", 0xd55555dd, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
436
START_TEST (test_debug_int)
438
cl_init(CL_INIT_DEFAULT);
439
runtest("input/debug_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
443
START_TEST (test_inf_7_int)
445
cl_init(CL_INIT_DEFAULT);
446
runtest("input/inf_7.cbc", 0, CL_ETIMEOUT, 1, NULL, NULL, NULL, NULL, 0);
450
START_TEST (test_lsig_7_int)
452
cl_init(CL_INIT_DEFAULT);
453
runtest("input/lsig_7.cbc", 0, 0, 1, NULL, NULL, NULL, NULL, 0);
457
START_TEST (test_retmagic_7_int)
459
cl_init(CL_INIT_DEFAULT);
460
runtest("input/retmagic_7.cbc", 0x1234f00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
464
START_TEST (test_testadt_int)
466
cl_init(CL_INIT_DEFAULT);
467
runtest("input/testadt_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
472
static void runload(const char *dbname, struct cl_engine* engine, unsigned signoexp)
474
const char * srcdir = getenv("srcdir");
479
/* when run from automake srcdir is set, but if run manually then not */
482
str = cli_malloc(strlen(dbname)+strlen(srcdir)+2);
483
fail_unless(!!str, "cli_malloc");
484
sprintf(str, "%s/%s", srcdir, dbname);
486
rc = cl_load(str, engine, &signo, CL_DB_STDOPT);
487
fail_unless_fmt(rc == CL_SUCCESS, "failed to load %s: %s\n",
488
dbname, cl_strerror(rc));
489
fail_unless_fmt(signo == signoexp, "different number of signatures loaded, expected %u, got %u\n",
493
rc = cl_engine_compile(engine);
494
fail_unless_fmt(rc == CL_SUCCESS, "failed to load %s: %s\n",
495
dbname, cl_strerror(rc));
498
START_TEST (test_load_bytecode_jit)
500
struct cl_engine *engine;
501
cl_init(CL_INIT_DEFAULT);
502
engine = cl_engine_new();
503
fail_unless(!!engine, "failed to create engine\n");
505
runload("input/bytecode.cvd", engine, 5);
507
cl_engine_free(engine);
511
START_TEST (test_load_bytecode_int)
513
struct cl_engine *engine;
514
cl_init(CL_INIT_DEFAULT);
515
engine = cl_engine_new();
516
engine->dconf->bytecode = BYTECODE_INTERPRETER;
517
fail_unless(!!engine, "failed to create engine\n");
519
runload("input/bytecode.cvd", engine, 5);
521
cl_engine_free(engine);
525
#if defined(CL_THREAD_SAFE) && defined(C_LINUX) && ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= (2 << 16) + 4)
530
static pthread_barrier_t barrier;
531
static void* thread(void *arg)
533
struct cl_engine *engine;
534
engine = cl_engine_new();
535
fail_unless(!!engine, "failed to create engine\n");
536
/* run all cl_load at once, to maximize chance of a crash
537
* in case of a race condition */
538
pthread_barrier_wait(&barrier);
539
runload("input/bytecode.cvd", engine, 5);
540
cl_engine_free(engine);
544
START_TEST (test_parallel_load)
547
pthread_t threads[N];
550
cl_init(CL_INIT_DEFAULT);
551
pthread_barrier_init(&barrier, NULL, N);
553
pthread_create(&threads[i], NULL, thread, NULL);
556
pthread_join(threads[i], NULL);
558
/* DB load used to crash due to 'static' variable in cache.c,
559
* and also due to something wrong in LLVM 2.7.
560
* Enabled the mutex around codegen in bytecode2llvm.cpp, and this test is
561
* here to make sure it doesn't crash */
566
Suite *test_bytecode_suite(void)
568
Suite *s = suite_create("bytecode");
569
TCase *tc_cli_arith = tcase_create("arithmetic");
570
suite_add_tcase(s, tc_cli_arith);
571
tcase_set_timeout(tc_cli_arith, 20);
572
tcase_add_test(tc_cli_arith, test_retmagic_jit);
573
tcase_add_test(tc_cli_arith, test_arith_jit);
574
tcase_add_test(tc_cli_arith, test_apicalls_jit);
575
tcase_add_test(tc_cli_arith, test_apicalls2_jit);
576
tcase_add_test(tc_cli_arith, test_div0_jit);
577
tcase_add_test(tc_cli_arith, test_lsig_jit);
578
tcase_add_test(tc_cli_arith, test_inf_jit);
579
tcase_add_test(tc_cli_arith, test_matchwithread_jit);
580
tcase_add_test(tc_cli_arith, test_pdf_jit);
581
tcase_add_test(tc_cli_arith, test_bswap_jit);
582
tcase_add_test(tc_cli_arith, test_inflate_jit);
584
tcase_add_test(tc_cli_arith, test_arith_int);
585
tcase_add_test(tc_cli_arith, test_apicalls_int);
586
tcase_add_test(tc_cli_arith, test_apicalls2_int);
587
tcase_add_test(tc_cli_arith, test_div0_int);
588
tcase_add_test(tc_cli_arith, test_lsig_int);
589
tcase_add_test(tc_cli_arith, test_inf_int);
590
tcase_add_test(tc_cli_arith, test_matchwithread_int);
591
tcase_add_test(tc_cli_arith, test_pdf_int);
592
tcase_add_test(tc_cli_arith, test_bswap_int);
593
tcase_add_test(tc_cli_arith, test_inflate_int);
594
tcase_add_test(tc_cli_arith, test_retmagic_int);
596
tcase_add_test(tc_cli_arith, test_api_extract_jit);
597
tcase_add_test(tc_cli_arith, test_api_files_jit);
598
tcase_add_test(tc_cli_arith, test_apicalls2_7_jit);
599
tcase_add_test(tc_cli_arith, test_apicalls_7_jit);
600
tcase_add_test(tc_cli_arith, test_apicalls_7_jit);
601
tcase_add_test(tc_cli_arith, test_arith_7_jit);
602
tcase_add_test(tc_cli_arith, test_debug_jit);
603
tcase_add_test(tc_cli_arith, test_inf_7_jit);
604
tcase_add_test(tc_cli_arith, test_lsig_7_jit);
605
tcase_add_test(tc_cli_arith, test_retmagic_7_jit);
606
tcase_add_test(tc_cli_arith, test_testadt_jit);
608
tcase_add_test(tc_cli_arith, test_api_extract_int);
609
tcase_add_test(tc_cli_arith, test_api_files_int);
610
tcase_add_test(tc_cli_arith, test_apicalls2_7_int);
611
tcase_add_test(tc_cli_arith, test_apicalls_7_int);
612
tcase_add_test(tc_cli_arith, test_apicalls_7_int);
613
tcase_add_test(tc_cli_arith, test_arith_7_int);
614
tcase_add_test(tc_cli_arith, test_debug_int);
615
tcase_add_test(tc_cli_arith, test_inf_7_int);
616
tcase_add_test(tc_cli_arith, test_lsig_7_int);
617
tcase_add_test(tc_cli_arith, test_retmagic_int);
618
tcase_add_test(tc_cli_arith, test_testadt_int);
620
tcase_add_test(tc_cli_arith, test_load_bytecode_jit);
621
tcase_add_test(tc_cli_arith, test_load_bytecode_int);
623
tcase_add_test(tc_cli_arith, test_parallel_load);