... | ... |
@@ -123,8 +123,9 @@ static int sigopts_handler(struct cli_matcher *root, const char *virname, const |
123 | 123 |
char *hexcpy, *start, *end; |
124 | 124 |
int i, ret = CL_SUCCESS; |
125 | 125 |
|
126 |
- /* prevent cyclic loops with cli_parse_add on same hexsig |
|
127 |
- * cyclic loops should be impossible though |
|
126 |
+ /* |
|
127 |
+ * cyclic loops with cli_parse_add are impossible now as cli_parse_add |
|
128 |
+ * no longer calls sigopts_handler; leaving here for safety |
|
128 | 129 |
*/ |
129 | 130 |
if (sigopts & ACPATT_OPTION_ONCE) { |
130 | 131 |
cli_errmsg("sigopts_handler: invalidly called multiple times!\n"); |
... | ... |
@@ -351,7 +352,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex |
351 | 351 |
return CL_SUCCESS; |
352 | 352 |
} |
353 | 353 |
if (strrchr(hexsig, '/')) { |
354 |
- char *start, *end, *sub; |
|
354 |
+ char *start, *end; |
|
355 | 355 |
|
356 | 356 |
/* get copied */ |
357 | 357 |
hexcpy = cli_strdup(hexsig); |
... | ... |
@@ -362,75 +363,41 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex |
362 | 362 |
start = strchr(hexcpy, '/'); |
363 | 363 |
end = strrchr(hexcpy, '/'); |
364 | 364 |
|
365 |
- /* get plus-ed (modifiers) */ |
|
366 |
- sub = strchr(end, '+'); |
|
367 |
- if (sub && start == end) |
|
368 |
- *end = '\0'; |
|
369 |
- |
|
370 | 365 |
/* get pcre-ed */ |
371 |
- if (!sub && start != end) { |
|
366 |
+ if (start == end) { |
|
367 |
+ cli_errmsg("cli_parseadd(): PCRE subsig mismatched '/' delimiter\n"); |
|
368 |
+ return CL_EMALFDB; |
|
369 |
+ } |
|
372 | 370 |
#if HAVE_PCRE |
373 |
- /* expected format => ^offset:trigger/regex/[cflags]$ */ |
|
374 |
- const char *trigger, *pattern, *cflags; |
|
371 |
+ /* expected format => ^offset:trigger/regex/[cflags]$ */ |
|
372 |
+ const char *trigger, *pattern, *cflags; |
|
375 | 373 |
|
376 |
- /* get checked */ |
|
377 |
- if (hexsig[0] == '/') { |
|
378 |
- cli_errmsg("cli_parseadd(): PCRE subsig must contain logical trigger\n"); |
|
379 |
- return CL_EMALFDB; |
|
380 |
- } |
|
374 |
+ /* get checked */ |
|
375 |
+ if (hexsig[0] == '/') { |
|
376 |
+ cli_errmsg("cli_parseadd(): PCRE subsig must contain logical trigger\n"); |
|
377 |
+ return CL_EMALFDB; |
|
378 |
+ } |
|
381 | 379 |
|
382 |
- /* get NULL-ed */ |
|
383 |
- *start = '\0'; |
|
384 |
- *end = '\0'; |
|
380 |
+ /* get NULL-ed */ |
|
381 |
+ *start = '\0'; |
|
382 |
+ *end = '\0'; |
|
385 | 383 |
|
386 |
- /* get tokens-ed */ |
|
387 |
- trigger = hexcpy; |
|
388 |
- pattern = start+1; |
|
389 |
- cflags = end+1; |
|
390 |
- if (*cflags == '\0') /* get compat-ed */ |
|
391 |
- cflags = NULL; |
|
384 |
+ /* get tokens-ed */ |
|
385 |
+ trigger = hexcpy; |
|
386 |
+ pattern = start+1; |
|
387 |
+ cflags = end+1; |
|
388 |
+ if (*cflags == '\0') /* get compat-ed */ |
|
389 |
+ cflags = NULL; |
|
392 | 390 |
|
393 |
- /* normal trigger, get added */ |
|
394 |
- ret = cli_pcre_addpatt(root, virname, trigger, pattern, cflags, offset, lsigid, options); |
|
395 |
- free(hexcpy); |
|
396 |
- return ret; |
|
391 |
+ /* normal trigger, get added */ |
|
392 |
+ ret = cli_pcre_addpatt(root, virname, trigger, pattern, cflags, offset, lsigid, options); |
|
393 |
+ free(hexcpy); |
|
394 |
+ return ret; |
|
397 | 395 |
#else |
398 |
- free(hexcpy); |
|
399 |
- cli_errmsg("cli_parseadd(): cannot parse PCRE subsig without PCRE support\n"); |
|
400 |
- return CL_EPARSE; |
|
396 |
+ free(hexcpy); |
|
397 |
+ cli_errmsg("cli_parseadd(): cannot parse PCRE subsig without PCRE support\n"); |
|
398 |
+ return CL_EPARSE; |
|
401 | 399 |
#endif |
402 |
- } else { /* get option-ed */ |
|
403 |
- /* get NULL-ed */ |
|
404 |
- char *opt = sub ? sub : end; |
|
405 |
- uint8_t sigopts = 0; |
|
406 |
- |
|
407 |
- *opt++ = '\0'; |
|
408 |
- while (*opt != '\0') { |
|
409 |
- switch (*opt) { |
|
410 |
- case 'i': |
|
411 |
- sigopts |= ACPATT_OPTION_NOCASE; |
|
412 |
- break; |
|
413 |
- case 'f': |
|
414 |
- sigopts |= ACPATT_OPTION_FULLWORD; |
|
415 |
- break; |
|
416 |
- case 'w': |
|
417 |
- sigopts |= ACPATT_OPTION_WIDE; |
|
418 |
- break; |
|
419 |
- case 'a': |
|
420 |
- sigopts |= ACPATT_OPTION_ASCII; |
|
421 |
- break; |
|
422 |
- default: |
|
423 |
- cli_errmsg("cli_parse_add: Signature for %s uses invalid option: %02x\n", virname, *opt); |
|
424 |
- return CL_EMALFDB; |
|
425 |
- } |
|
426 |
- |
|
427 |
- opt++; |
|
428 |
- } |
|
429 |
- |
|
430 |
- ret = sigopts_handler(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options); |
|
431 |
- free(hexcpy); |
|
432 |
- return ret; |
|
433 |
- } |
|
434 | 400 |
} |
435 | 401 |
else if((wild = strchr(hexsig, '{'))) { |
436 | 402 |
if(sscanf(wild, "%c%u%c", &l, &range, &r) == 3 && l == '{' && r == '}' && range > 0 && range < 128) { |
... | ... |
@@ -1610,25 +1577,55 @@ static inline int init_tdb(struct cli_lsig_tdb *tdb, struct cl_engine *engine, c |
1610 | 1610 |
} |
1611 | 1611 |
|
1612 | 1612 |
/* 0 1 2 3 4 5 ... (max 66) |
1613 |
- * VirusName:Attributes:Logic:SubSig1[:SubSig2[:SubSig3 ... ]] |
|
1613 |
+ * VirusName;Attributes;Logic;SubSig1[;SubSig2[;SubSig3 ... ]] |
|
1614 | 1614 |
* NOTE: Maximum of 64(see MAX_LDB_SUBSIGS) subsignatures (last would be token 66) |
1615 | 1615 |
*/ |
1616 | 1616 |
#define LDB_TOKENS 67 |
1617 |
+static int ldb_tokenize(char *buffer, const char **tokens) |
|
1618 |
+{ |
|
1619 |
+ const size_t token_count = LDB_TOKENS + 1; |
|
1620 |
+ size_t tokens_found, i; |
|
1621 |
+ int within_pcre = 0; |
|
1622 |
+ |
|
1623 |
+ for(tokens_found = 0; tokens_found < token_count; ) { |
|
1624 |
+ tokens[tokens_found++] = buffer; |
|
1625 |
+ |
|
1626 |
+ while (*buffer != '\0') { |
|
1627 |
+ if (!within_pcre && (*buffer == ';')) |
|
1628 |
+ break; |
|
1629 |
+ else if ((tokens_found > 2) && (*buffer == '/')) |
|
1630 |
+ within_pcre = !within_pcre; |
|
1631 |
+ buffer++; |
|
1632 |
+ } |
|
1633 |
+ |
|
1634 |
+ if(*buffer != '\0') { |
|
1635 |
+ *buffer++ = '\0'; |
|
1636 |
+ } else { |
|
1637 |
+ i = tokens_found; |
|
1638 |
+ while(i < token_count) |
|
1639 |
+ tokens[i++] = NULL; |
|
1640 |
+ return tokens_found; |
|
1641 |
+ } |
|
1642 |
+ } |
|
1643 |
+ return tokens_found; |
|
1644 |
+} |
|
1645 |
+ |
|
1617 | 1646 |
static int load_oneldb(char *buffer, int chkpua, struct cl_engine *engine, unsigned int options, const char *dbname, unsigned int line, unsigned int *sigs, unsigned bc_idx, const char *buffer_cpy, int *skip) |
1618 | 1647 |
{ |
1619 | 1648 |
const char *sig, *virname, *offset, *logic; |
1620 | 1649 |
struct cli_ac_lsig **newtable, *lsig; |
1621 |
- char *tokens[LDB_TOKENS+1], *pt, *pt2; |
|
1650 |
+ char *tokens[LDB_TOKENS+1], *pt, *lsl, *rsl; |
|
1622 | 1651 |
int i, subsigs, tokens_count; |
1623 | 1652 |
unsigned short target = 0; |
1624 | 1653 |
struct cli_matcher *root; |
1625 | 1654 |
struct cli_lsig_tdb tdb; |
1626 | 1655 |
uint32_t lsigid[2]; |
1656 |
+ uint8_t subsig_opts; |
|
1627 | 1657 |
int ret; |
1628 | 1658 |
|
1629 | 1659 |
UNUSEDPARAM(dbname); |
1630 | 1660 |
|
1631 |
- tokens_count = cli_strtokenize(buffer, ';', LDB_TOKENS + 1, (const char **) tokens); |
|
1661 |
+ tokens_count = ldb_tokenize(buffer, (const char **) tokens); |
|
1632 | 1662 |
if(tokens_count < 4) { |
1633 | 1663 |
return CL_EMALFDB; |
1634 | 1664 |
} |
... | ... |
@@ -1737,22 +1734,59 @@ static int load_oneldb(char *buffer, int chkpua, struct cl_engine *engine, unsig |
1737 | 1737 |
tdb.subsigs = subsigs; |
1738 | 1738 |
|
1739 | 1739 |
for(i = 0; i < subsigs; i++) { |
1740 |
+ subsig_opts = 0; |
|
1741 |
+ |
|
1740 | 1742 |
lsigid[1] = i; |
1743 |
+ offset = "*"; |
|
1741 | 1744 |
sig = tokens[3 + i]; |
1742 | 1745 |
|
1743 |
- pt2 = strchr(tokens[3 + i], '/'); |
|
1744 |
- pt = strchr(tokens[3 + i], ':'); |
|
1745 |
- if(pt && (!pt2 || (pt < pt2))) { |
|
1746 |
- *pt = 0; |
|
1747 |
- sig = ++pt; |
|
1748 |
- offset = tokens[3 + i]; |
|
1749 |
- } else { |
|
1750 |
- offset = "*"; |
|
1751 |
- sig = tokens[3 + i]; |
|
1746 |
+ /* check for offset and subsig modifiers */ |
|
1747 |
+ pt = tokens[3 + i]; |
|
1748 |
+ lsl = strchr(tokens[3 + i], '/'); |
|
1749 |
+ rsl = strrchr(tokens[3 + i], '/'); |
|
1750 |
+ while((pt = strchr(pt, ':'))) { |
|
1751 |
+ /* pcre subsig expression */ |
|
1752 |
+ if((lsl && rsl) && (lsl < pt) && (pt < rsl)) { |
|
1753 |
+ pt++; |
|
1754 |
+ continue; |
|
1755 |
+ } |
|
1756 |
+ |
|
1757 |
+ *pt++ = 0; |
|
1758 |
+ if(*pt == ':') { /* signature modifiers */ |
|
1759 |
+ *pt++ = 0; |
|
1760 |
+ while(*pt != '\0') { |
|
1761 |
+ switch(*pt) { |
|
1762 |
+ case 'i': |
|
1763 |
+ subsig_opts |= ACPATT_OPTION_NOCASE; |
|
1764 |
+ break; |
|
1765 |
+ case 'f': |
|
1766 |
+ subsig_opts |= ACPATT_OPTION_FULLWORD; |
|
1767 |
+ break; |
|
1768 |
+ case 'w': |
|
1769 |
+ subsig_opts |= ACPATT_OPTION_WIDE; |
|
1770 |
+ break; |
|
1771 |
+ case 'a': |
|
1772 |
+ subsig_opts |= ACPATT_OPTION_ASCII; |
|
1773 |
+ break; |
|
1774 |
+ default: |
|
1775 |
+ cli_errmsg("cli_loadldb: Signature for %s uses invalid option: %02x\n", virname, *pt); |
|
1776 |
+ return CL_EMALFDB; |
|
1777 |
+ } |
|
1778 |
+ |
|
1779 |
+ pt++; |
|
1780 |
+ } |
|
1781 |
+ } else { |
|
1782 |
+ sig = pt; |
|
1783 |
+ offset = tokens[3 + i]; |
|
1784 |
+ } |
|
1752 | 1785 |
} |
1753 | 1786 |
|
1787 |
+ if(subsig_opts) |
|
1788 |
+ ret = sigopts_handler(root, virname, sig, subsig_opts, 0, 0, offset, target, lsigid, options); |
|
1789 |
+ else |
|
1790 |
+ ret = cli_parse_add(root, virname, sig, 0, 0, 0, offset, target, lsigid, options); |
|
1754 | 1791 |
|
1755 |
- if((ret = cli_parse_add(root, virname, sig, 0, 0, 0, offset, target, lsigid, options))) |
|
1792 |
+ if(ret) |
|
1756 | 1793 |
return ret; |
1757 | 1794 |
|
1758 | 1795 |
if(sig[0] == '$' && i) { |