... | ... |
@@ -465,7 +465,7 @@ Example |
465 | 465 |
# Default: TrustSigned |
466 | 466 |
#BytecodeSecurity TrustSigned |
467 | 467 |
|
468 |
-# Set bytecode timeout in microseconds. |
|
468 |
+# Set bytecode timeout in miliseconds. |
|
469 | 469 |
# |
470 |
-# Default: 5000000 |
|
471 |
-#BytecodeTimeout 5000000 |
|
470 |
+# Default: 5000 |
|
471 |
+# BytecodeTimeout 5000 |
... | ... |
@@ -379,7 +379,6 @@ public: |
379 | 379 |
|
380 | 380 |
|
381 | 381 |
virtual bool runOnFunction(Function &F) { |
382 |
- bool Changed = false; |
|
383 | 382 |
BBSetTy BackedgeTargets; |
384 | 383 |
if (!F.isDeclaration()) { |
385 | 384 |
// Get the common backedge targets. |
... | ... |
@@ -491,7 +490,6 @@ public: |
491 | 491 |
TerminatorInst *TI = BB->getTerminator(); |
492 | 492 |
BranchInst::Create(AbrtBB, newBB, Cond, TI); |
493 | 493 |
TI->eraseFromParent(); |
494 |
- BB->dump(); |
|
495 | 494 |
// Update dominator info |
496 | 495 |
DomTreeNode *N = DT.getNode(AbrtBB); |
497 | 496 |
if (!N) { |
... | ... |
@@ -503,8 +501,7 @@ public: |
503 | 503 |
} |
504 | 504 |
DEBUG(errs() << *I << "\n"); |
505 | 505 |
} |
506 |
- F.dump(); |
|
507 |
- verifyFunction(F); |
|
506 |
+ //verifyFunction(F); |
|
508 | 507 |
return true; |
509 | 508 |
} |
510 | 509 |
|
... | ... |
@@ -1497,15 +1494,31 @@ static void addFunctionProtos(struct CommonFunctions *CF, ExecutionEngine *EE, M |
1497 | 1497 |
|
1498 | 1498 |
} |
1499 | 1499 |
|
1500 |
-struct bc_thread { |
|
1501 |
- void *code; |
|
1502 |
- struct cli_bc_ctx *ctx; |
|
1500 |
+struct bc_watchdog { |
|
1501 |
+ volatile uint8_t* timeout; |
|
1502 |
+ struct timespec * abstimeout; |
|
1503 |
+ pthread_mutex_t mutex; |
|
1504 |
+ pthread_cond_t cond; |
|
1503 | 1505 |
int finished; |
1504 |
- pthread_mutex_t mutex; |
|
1505 |
- pthread_cond_t cond; |
|
1506 | 1506 |
}; |
1507 | 1507 |
|
1508 |
-static int bytecode_thread_execute(intptr_t code, struct cli_bc_ctx *ctx) |
|
1508 |
+static void *bytecode_watchdog(void *arg) |
|
1509 |
+{ |
|
1510 |
+ int ret = 0; |
|
1511 |
+ struct bc_watchdog *w = (struct bc_watchdog*)arg; |
|
1512 |
+ pthread_mutex_lock(&w->mutex); |
|
1513 |
+ while (!w->finished && ret != ETIMEDOUT) { |
|
1514 |
+ ret = pthread_cond_timedwait(&w->cond, &w->mutex, w->abstimeout); |
|
1515 |
+ } |
|
1516 |
+ pthread_mutex_unlock(&w->mutex); |
|
1517 |
+ if (ret == ETIMEDOUT) { |
|
1518 |
+ *w->timeout = 1; |
|
1519 |
+ errs() << "Bytecode run timed out, timeout flag set\n"; |
|
1520 |
+ } |
|
1521 |
+ return NULL; |
|
1522 |
+} |
|
1523 |
+ |
|
1524 |
+static int bytecode_execute(intptr_t code, struct cli_bc_ctx *ctx) |
|
1509 | 1525 |
{ |
1510 | 1526 |
jmp_buf env; |
1511 | 1527 |
// execute; |
... | ... |
@@ -1520,33 +1533,17 @@ static int bytecode_thread_execute(intptr_t code, struct cli_bc_ctx *ctx) |
1520 | 1520 |
errs().changeColor(raw_ostream::RED, true) << MODULE |
1521 | 1521 |
<< "*** JITed code intercepted runtime error!\n"; |
1522 | 1522 |
errs().resetColor(); |
1523 |
- return 1; |
|
1523 |
+ return CL_EBYTECODE; |
|
1524 | 1524 |
} |
1525 | 1525 |
|
1526 |
-static void* bytecode_thread(void* dummy) |
|
1527 |
-{ |
|
1528 |
- int ret; |
|
1529 |
- struct bc_thread *thr = (struct bc_thread*)dummy; |
|
1530 |
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
|
1531 |
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); |
|
1532 |
- ret = bytecode_thread_execute((intptr_t)thr->code, thr->ctx); |
|
1533 |
- pthread_mutex_lock(&thr->mutex); |
|
1534 |
- thr->finished = 1; |
|
1535 |
- pthread_cond_signal(&thr->cond); |
|
1536 |
- pthread_mutex_unlock(&thr->mutex); |
|
1537 |
- return ret ? dummy : NULL; |
|
1538 |
-} |
|
1539 | 1526 |
extern "C" const char *cli_strerror(int errnum, char* buf, size_t len); |
1540 | 1527 |
int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx, |
1541 | 1528 |
const struct cli_bc_func *func) |
1542 | 1529 |
{ |
1543 | 1530 |
char buf[1024]; |
1544 | 1531 |
int ret; |
1545 |
- void *threadret; |
|
1546 | 1532 |
pthread_t thread; |
1547 | 1533 |
struct timeval tv0, tv1; |
1548 |
- struct timespec abstimeout; |
|
1549 |
- int timedout = 0; |
|
1550 | 1534 |
uint32_t timeoutus; |
1551 | 1535 |
// no locks needed here, since LLVM automatically acquires a JIT lock |
1552 | 1536 |
// if needed. |
... | ... |
@@ -1558,54 +1555,43 @@ int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx, |
1558 | 1558 |
<< (unsigned)func->numArgs << " arguments, it must have 0 to be called as entrypoint\n"; |
1559 | 1559 |
return CL_EBYTECODE; |
1560 | 1560 |
} |
1561 |
- struct bc_thread bcthr = { |
|
1562 |
- code, ctx, 0, |
|
1563 |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER |
|
1564 |
- }; |
|
1565 |
- ctx->timeout = 0; |
|
1566 | 1561 |
gettimeofday(&tv0, NULL); |
1567 |
- pthread_mutex_lock(&bcthr.mutex); |
|
1568 |
- ret = pthread_create(&thread, NULL, bytecode_thread, &bcthr); |
|
1569 |
- if (ret) { |
|
1562 |
+ struct timespec abstime; |
|
1563 |
+ |
|
1564 |
+ timeoutus = (ctx->bytecode_timeout%1000)*1000 + tv0.tv_usec; |
|
1565 |
+ abstime.tv_sec = tv0.tv_sec + ctx->bytecode_timeout/1000 + timeoutus/1000000; |
|
1566 |
+ abstime.tv_nsec = 1000*(timeoutus%1000000); |
|
1567 |
+ ctx->timeout = 0; |
|
1568 |
+ |
|
1569 |
+ struct bc_watchdog w = { |
|
1570 |
+ &ctx->timeout, |
|
1571 |
+ &abstime, |
|
1572 |
+ PTHREAD_MUTEX_INITIALIZER, |
|
1573 |
+ PTHREAD_COND_INITIALIZER, |
|
1574 |
+ 0 |
|
1575 |
+ }; |
|
1576 |
+ |
|
1577 |
+ if ((ret = pthread_create(&thread, NULL, bytecode_watchdog, &w))) { |
|
1570 | 1578 |
errs() << "Bytecode: failed to create new thread!"; |
1571 | 1579 |
errs() << cli_strerror(ret, buf, sizeof(buf)); |
1572 | 1580 |
errs() << "\n"; |
1573 | 1581 |
return CL_EBYTECODE; |
1574 | 1582 |
} |
1575 | 1583 |
|
1576 |
- timeoutus = ctx->bytecode_timeout + tv0.tv_usec; |
|
1577 |
- abstimeout.tv_nsec = 1000*(timeoutus%1000000); |
|
1578 |
- abstimeout.tv_sec = tv0.tv_sec + timeoutus/1000000; |
|
1579 |
- do { |
|
1580 |
- ret = pthread_cond_timedwait(&bcthr.cond, &bcthr.mutex, &abstimeout); |
|
1581 |
- } while (!bcthr.finished && ret != ETIMEDOUT); |
|
1582 |
- pthread_mutex_unlock(&bcthr.mutex); |
|
1583 |
- if (ret == ETIMEDOUT) { |
|
1584 |
- errs() << "Bytecode run timed out, canceling thread\n"; |
|
1585 |
- timedout = 1; |
|
1586 |
- ctx->timeout = 1; |
|
1587 |
-#if 0 |
|
1588 |
- ret = pthread_cancel(thread); |
|
1589 |
- if (ret) { |
|
1590 |
- errs() << "Bytecode: failed to create new thread!"; |
|
1591 |
- errs() << cli_strerror(ret, buf, sizeof(buf)); |
|
1592 |
- errs() << "\n"; |
|
1593 |
- } |
|
1594 |
-#endif |
|
1595 |
- } |
|
1596 |
- ret = pthread_join(thread, &threadret); |
|
1597 |
- if (ret) { |
|
1598 |
- errs() << "Bytecode: failed to create new thread!"; |
|
1599 |
- errs() << cli_strerror(ret, buf, sizeof(buf)); |
|
1600 |
- errs() << "\n"; |
|
1601 |
- } |
|
1584 |
+ ret = bytecode_execute((intptr_t)code, ctx); |
|
1585 |
+ pthread_mutex_lock(&w.mutex); |
|
1586 |
+ w.finished = 1; |
|
1587 |
+ pthread_cond_signal(&w.cond); |
|
1588 |
+ pthread_mutex_unlock(&w.mutex); |
|
1589 |
+ pthread_join(thread, NULL); |
|
1590 |
+ |
|
1602 | 1591 |
if (cli_debug_flag) { |
1603 | 1592 |
gettimeofday(&tv1, NULL); |
1604 | 1593 |
tv1.tv_sec -= tv0.tv_sec; |
1605 | 1594 |
tv1.tv_usec -= tv0.tv_usec; |
1606 | 1595 |
errs() << "bytecode finished in " << (tv1.tv_sec*1000000 + tv1.tv_usec) << "us\n"; |
1607 | 1596 |
} |
1608 |
- return timedout ? CL_ETIMEOUT : (threadret ? CL_EBYTECODE : CL_SUCCESS); |
|
1597 |
+ return ctx->timeout ? CL_ETIMEOUT : ret; |
|
1609 | 1598 |
} |
1610 | 1599 |
|
1611 | 1600 |
static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253 }; |
... | ... |
@@ -250,8 +250,8 @@ const struct clam_option __clam_options[] = { |
250 | 250 |
{ "Bytecode", "bytecode", 0, TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "With this option enabled ClamAV will load bytecode from the database. It is highly recommended you keep this option on, otherwise you'll miss detections for many new viruses.", "yes" }, |
251 | 251 |
{ "BytecodeSecurity", NULL, 0, TYPE_STRING, "^(None|TrustSigned|Paranoid)$", -1, "TrustSigned", 0, OPT_CLAMD, |
252 | 252 |
"Set bytecode security level.\nPossible values:\n\tNone - no security at all, meant for debugging. DO NOT USE THIS ON PRODUCTION SYSTEMS\n\tTrustSigned - trust bytecode loaded from signed .c[lv]d files,\n\t\t insert runtime safety checks for bytecode loaded from other sources\n\tParanoid - don't trust any bytecode, insert runtime checks for all\nRecommended: TrustSigned, because bytecode in .cvd files already has these checks\n","TrustSigned"}, |
253 |
- { "BytecodeTimeout", "bytecode-timeout", 0, TYPE_NUMBER, MATCH_NUMBER, 5000000, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, |
|
254 |
- "Set bytecode timeout in microseconds.\n","5000000"}, |
|
253 |
+ { "BytecodeTimeout", "bytecode-timeout", 0, TYPE_NUMBER, MATCH_NUMBER, 5000, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, |
|
254 |
+ "Set bytecode timeout in miliseconds.\n","5000"}, |
|
255 | 255 |
{ "DetectPUA", "detect-pua", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Detect Potentially Unwanted Applications.", "yes" }, |
256 | 256 |
|
257 | 257 |
{ "ExcludePUA", "exclude-pua", 0, TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD | OPT_CLAMSCAN, "Exclude a specific PUA category. This directive can be used multiple times.\nSee http://www.clamav.net/support/pua for the complete list of PUA\ncategories.", "NetTool\nPWTool" }, |
... | ... |
@@ -75,7 +75,7 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit) |
75 | 75 |
|
76 | 76 |
ctx = cli_bytecode_context_alloc(); |
77 | 77 |
/* small timeout, these bytecodes are fast! */ |
78 |
- ctx->bytecode_timeout = 100000; |
|
78 |
+ ctx->bytecode_timeout = 10; |
|
79 | 79 |
fail_unless(!!ctx, "cli_bytecode_context_alloc failed"); |
80 | 80 |
|
81 | 81 |
cli_bytecode_context_setfuncid(ctx, &bc, 0); |