From dc70379a09dd69258e25e62476778d4ad2a8517d Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 20 Feb 2015 18:13:28 -0500 Subject: [PATCH] converted sigopts from char string to uint8_t --- libclamav/matcher-ac.c | 32 ++++--------- libclamav/matcher-ac.h | 13 +++-- libclamav/readdb.c | 94 ++++++++++++++++++++++--------------- libclamav/readdb.h | 2 +- unit_tests/check_matchers.c | 16 +++---- 5 files changed, 82 insertions(+), 75 deletions(-) diff --git a/libclamav/matcher-ac.c b/libclamav/matcher-ac.c index b175d3b19..6cbe0695f 100644 --- a/libclamav/matcher-ac.c +++ b/libclamav/matcher-ac.c @@ -260,7 +260,7 @@ static int cli_ac_addpatt_recursive(struct cli_matcher *root, struct cli_ac_patt /* if pattern is nocase, we need to enumerate all the combinations if applicable * it's why this function was re-written to be recursive */ - if(pattern->nocase && isalpha(pattern->pattern[i] & 0xff)) { + if((pattern->sigopts & ACPATT_OPTION_NOCASE) && isalpha(pattern->pattern[i] & 0xff)) { next = pt->trans[cli_nocasei((unsigned char) (pattern->pattern[i] & 0xff))]; if(!next) next = add_new_node(root, i, len); @@ -1637,12 +1637,12 @@ static int qcompare(const void *a, const void *b) } /* FIXME: clean up the code */ -int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, const char *sigopts, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options) +int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options) { struct cli_ac_patt *new; char *pt, *pt2, *hex = NULL, *hexcpy = NULL; uint16_t i, j, ppos = 0, pend, *dec, nzpos = 0; - uint8_t wprefix = 0, zprefix = 1, plen = 0, nzplen = 0, nocase = 0; + uint8_t wprefix = 0, zprefix = 1, plen = 0, nzplen = 0; struct cli_ac_special *newspecial, *specialpt, **newtable; int ret, error = CL_SUCCESS; @@ -1657,22 +1657,6 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex return CL_EMALFDB; } - if (sigopts) { - i = 0; - while (sigopts[i] != '\0') { - switch (sigopts[i]) { - case 'i': - nocase = 1; - break; - default: - cli_errmsg("cli_ac_addsig: Signature for %s uses invalid option: %02x\n", virname, sigopts[i]); - return CL_EMALFDB; - } - - i++; - } - } - if((new = (struct cli_ac_patt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_patt))) == NULL) return CL_EMEM; @@ -1741,7 +1725,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex break; } - if(nocase && ((*dec & CLI_MATCH_METADATA) == CLI_MATCH_CHAR)) + if((sigopts & ACPATT_OPTION_NOCASE) && ((*dec & CLI_MATCH_METADATA) == CLI_MATCH_CHAR)) new->ch[i] = cli_nocase(*dec) | CLI_MATCH_NOCASE; else new->ch[i] = *dec; @@ -1757,7 +1741,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex break; } - if(nocase && ((*dec & CLI_MATCH_METADATA) == CLI_MATCH_CHAR)) + if((sigopts & ACPATT_OPTION_NOCASE) && ((*dec & CLI_MATCH_METADATA) == CLI_MATCH_CHAR)) new->ch[i] = cli_nocase(*dec) | CLI_MATCH_NOCASE; else new->ch[i] = *dec; @@ -1997,9 +1981,9 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex new->length = strlen(hex ? hex : hexsig) / 2; free(hex); - /* setting nocase match; TODO - move this to cli_realhex2ui and adjust for nocase, alter MATCH_CHAR too */ - if (nocase) { - new->nocase = 1; + new->sigopts = sigopts; + /* setting nocase match; TODO - move this to cli_realhex2ui and adjust for nocase */ + if (sigopts & ACPATT_OPTION_NOCASE) { for (i = 0; i < new->length; ++i) if ((new->pattern[i] & CLI_MATCH_METADATA) == CLI_MATCH_CHAR) { new->pattern[i] = cli_nocase(new->pattern[i] & 0xff); diff --git a/libclamav/matcher-ac.h b/libclamav/matcher-ac.h index 3aaf30068..349ae4156 100644 --- a/libclamav/matcher-ac.h +++ b/libclamav/matcher-ac.h @@ -34,9 +34,12 @@ #define AC_SCAN_VIR 1 #define AC_SCAN_FT 2 -/* AC trie options */ -#define AC_OPTION_NOOPTS 0x0 -#define AC_OPTION_NOCASE 0x1 +/* Pattern options */ +#define ACPATT_OPTION_NOOPTS 0x00 +#define ACPATT_OPTION_NOCASE 0x01 +#define ACPATT_OPTION_FULLWORD 0x02 +#define ACPATT_OPTION_WIDE 0x04 +#define ACPATT_OPTION_ASCII 0x08 struct cli_ac_data { int32_t ***offmatrix; @@ -73,7 +76,7 @@ struct cli_ac_patt { uint32_t offdata[4], offset_min, offset_max; uint32_t boundary; uint8_t depth; - uint8_t nocase; + uint8_t sigopts; }; struct cli_ac_list { @@ -109,6 +112,6 @@ int cli_ac_buildtrie(struct cli_matcher *root); int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth, uint8_t dconf_prefiltering); int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, const struct cli_target_info *info); void cli_ac_free(struct cli_matcher *root); -int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, const char *sigopts, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options); +int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options); #endif diff --git a/libclamav/readdb.c b/libclamav/readdb.c index a29084c43..114482735 100644 --- a/libclamav/readdb.c +++ b/libclamav/readdb.c @@ -116,7 +116,7 @@ char *cli_virname(const char *virname, unsigned int official) } #define PCRE_TOKENS 4 -int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, const char *sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options) +int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options) { struct cli_bm_patt *bm_new; char *pt, *hexcpy, *start, *n, l, r; @@ -224,10 +224,37 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex #endif } else { /* get option-ed */ /* get NULL-ed */ + char *opt = end+1; + uint8_t sigopts = 0; + *end = '\0'; + while (*opt != '\0') { + switch (*opt) { + case 'i': + sigopts |= ACPATT_OPTION_NOCASE; + break; + case 'f': + sigopts |= ACPATT_OPTION_FULLWORD; + break; + case 'w': + sigopts |= ACPATT_OPTION_WIDE; + break; + case 'a': + sigopts |= ACPATT_OPTION_ASCII; + break; + default: + cli_errmsg("cli_parse_add: Signature for %s uses invalid option: %02x\n", virname, *opt); + return CL_EMALFDB; + } + + opt++; + } + + /* TODO - other option handling */ + /* get called */ - ret = cli_parse_add(root, virname, hexcpy, end+1, rtype, type, offset, target, lsigid, options); + ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options); free(hexcpy); return ret; } @@ -663,7 +690,7 @@ static int cli_loaddb(FILE *fs, struct cl_engine *engine, unsigned int *signo, u if(*pt == '=') continue; - if((ret = cli_parse_add(root, start, pt, NULL, 0, 0, "*", 0, NULL, options))) { + if((ret = cli_parse_add(root, start, pt, 0, 0, 0, "*", 0, NULL, options))) { cli_dbgmsg("cli_loaddb: cli_parse_add failed on line %d\n", line); ret = CL_EMALFDB; break; @@ -1063,7 +1090,7 @@ static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo, offset = tokens[2]; sig = tokens[3]; - if((ret = cli_parse_add(root, virname, sig, NULL, 0, 0, offset, target, NULL, options))) { + if((ret = cli_parse_add(root, virname, sig, 0, 0, 0, offset, target, NULL, options))) { ret = CL_EMALFDB; break; } @@ -1520,7 +1547,7 @@ static int load_oneldb(char *buffer, int chkpua, struct cl_engine *engine, unsig sig = tokens[3 + i]; } - if((ret = cli_parse_add(root, virname, sig, NULL, 0, 0, offset, target, lsigid, options))) + if((ret = cli_parse_add(root, virname, sig, 0, 0, 0, offset, target, lsigid, options))) return ret; if(sig[0] == '$' && i) { @@ -1798,7 +1825,7 @@ static int cli_loadftm(FILE *fs, struct cl_engine *engine, unsigned int options, magictype = atoi(tokens[0]); if(magictype == 1) { /* A-C */ - if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], NULL, rtype, type, tokens[1], 0, NULL, options))) + if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], 0, rtype, type, tokens[1], 0, NULL, options))) break; } else if ((magictype == 0) || (magictype == 4)) { /* memcmp() */ @@ -2863,7 +2890,7 @@ static inline void free_yararule(YR_RULE *rule) struct cli_ytable_entry { char *offset; char *hexstr; - char *sigopts; + uint8_t sigopts; }; struct cli_ytable { @@ -2896,22 +2923,23 @@ static int ytable_add_attrib(struct cli_ytable *ytable, const char *hexsig, cons } if (type) { - /* append to existing */ - if (!ytable->table[lookup]->sigopts) { - ytable->table[lookup]->sigopts = cli_strdup(value); - if (!ytable->table[lookup]->sigopts) { - cli_yaramsg("ytable_add_attrib: ran out of memory for sigopts\n"); - return CL_EMEM; - } - } else { - size_t len = strlen(ytable->table[lookup]->sigopts); - size_t newsize = strlen(value) + len + 1; - ytable->table[lookup]->sigopts = cli_realloc(ytable->table[lookup]->sigopts, newsize); - if (!ytable->table[lookup]->sigopts) { - cli_yaramsg("ytable_add_attrib: ran out of memory for sigopts\n"); - return CL_EMEM; - } - snprintf(ytable->table[lookup]->sigopts+len, newsize-len, "%s", value); + /* add to sigopts */ + switch (*value) { + case 'i': + ytable->table[lookup]->sigopts |= ACPATT_OPTION_NOCASE; + break; + case 'f': + ytable->table[lookup]->sigopts |= ACPATT_OPTION_FULLWORD; + break; + case 'w': + ytable->table[lookup]->sigopts |= ACPATT_OPTION_WIDE; + break; + case 'a': + ytable->table[lookup]->sigopts |= ACPATT_OPTION_ASCII; + break; + default: + cli_yaramsg("ytable_add_attrib: invalid sigopt %02x\n", *value); + return CL_EARG; } } else { @@ -2987,7 +3015,6 @@ static void ytable_delete(struct cli_ytable *ytable) for (i = 0; i < ytable->tbl_cnt; ++i) { free(ytable->table[i]->offset); free(ytable->table[i]->hexstr); - free(ytable->table[i]->sigopts); free(ytable->table[i]); } free(ytable->table); @@ -3184,34 +3211,27 @@ static int load_oneyara(YR_RULE *rule, struct cl_engine *engine, unsigned int op } if (STRING_IS_ASCII(string)) { cli_yaramsg("STRING_IS_ASCII %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); - /* what is ascii, but another way to state the same? */ + if ((ret = ytable_add_attrib(&ytable, NULL, "a", 1)) != CL_SUCCESS) { + cli_yaramsg("load_oneyara: failed to add 'ascii' sigopt\n"); + str_error++; + break; + } } if (STRING_IS_WIDE(string)) { - /* support is not implemented, caught by cli_ac_addsig() */ - /* might want to redefine the string here or something */ cli_yaramsg("STRING_IS_WIDE %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); -#ifdef YARA_FINISHED if ((ret = ytable_add_attrib(&ytable, NULL, "w", 1)) != CL_SUCCESS) { cli_yaramsg("load_oneyara: failed to add 'wide' sigopt\n"); str_error++; break; } -#else - cli_warnmsg("load_oneyara: yara support is incomplete, 'wide' keyword is unsupported\n"); -#endif } if (STRING_IS_FULL_WORD(string)) { - /* support is not implemented, caught by cli_ac_addsig() */ cli_yaramsg("STRING_IS_FULL_WORD %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); -#ifdef YARA_FINISHED if ((ret = ytable_add_attrib(&ytable, NULL, "f", 1)) != CL_SUCCESS) { cli_yaramsg("load_oneyara: failed to add 'fullword' sigopt\n"); str_error++; break; } -#else - cli_warnmsg("load_oneyara: yara support is incomplete, 'fullword' keyword is unsupported\n"); -#endif } #ifdef YARA_FINISHED @@ -3379,7 +3399,7 @@ static int load_oneyara(YR_RULE *rule, struct cl_engine *engine, unsigned int op for (i = 0; i < ytable.tbl_cnt; ++i) { lsigid[1] = i; - cli_yaramsg("%d: [%s] [%s] [%s]\n", i, ytable.table[i]->hexstr, ytable.table[i]->offset, ytable.table[i]->sigopts); + cli_yaramsg("%d: [%s] [%s] [%x]\n", i, ytable.table[i]->hexstr, ytable.table[i]->offset, ytable.table[i]->sigopts); if((ret = cli_parse_add(root, rule->id, ytable.table[i]->hexstr, ytable.table[i]->sigopts, 0, 0, ytable.table[i]->offset, target, lsigid, options)) != CL_SUCCESS) { yara_malform++; diff --git a/libclamav/readdb.h b/libclamav/readdb.h index 4cc1fed4f..603b2ea61 100644 --- a/libclamav/readdb.h +++ b/libclamav/readdb.h @@ -69,7 +69,7 @@ char *cli_virname(const char *virname, unsigned int official); -int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, const char *sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options); +int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options); int cli_load(const char *filename, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio); diff --git a/unit_tests/check_matchers.c b/unit_tests/check_matchers.c index 310781cd5..00f13e89a 100644 --- a/unit_tests/check_matchers.c +++ b/unit_tests/check_matchers.c @@ -99,7 +99,7 @@ START_TEST (test_ac_scanbuff) { for(i = 0; ac_testdata[i].data; i++) { - ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); } @@ -138,11 +138,11 @@ START_TEST (test_bm_scanbuff) { ret = cli_bm_init(root); fail_unless(ret == CL_SUCCESS, "cli_bm_init() failed"); - ret = cli_parse_add(root, "Sig1", "deadbabe", NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_parse_add(root, "Sig2", "deadbeef", NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_parse_add(root, "Sig3", "babedead", NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL); @@ -169,7 +169,7 @@ START_TEST (test_ac_scanbuff_allscan) { for(i = 0; ac_testdata[i].data; i++) { - ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); } @@ -214,11 +214,11 @@ START_TEST (test_bm_scanbuff_allscan) { ret = cli_bm_init(root); fail_unless(ret == CL_SUCCESS, "cli_bm_init() failed"); - ret = cli_parse_add(root, "Sig1", "deadbabe", NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_parse_add(root, "Sig2", "deadbeef", NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_parse_add(root, "Sig3", "babedead", NULL, 0, 0, "*", 0, NULL, 0); + ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);