diff --git a/ChangeLog b/ChangeLog index 0c9556c7f..40371b8bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Fri Aug 14 14:37:21 CEST 2009 (tk) +---------------------------------- + * libclamav: improve handling of signature offsets + Tue Aug 11 02:04:54 CEST 2009 (acab) ------------------------------------ * libclamav/7z/Types.h: workaround "Byte" clash in lzma/7z (bb#805 - regression) diff --git a/libclamav/default.h b/libclamav/default.h index 8641fe9bb..24e226d11 100644 --- a/libclamav/default.h +++ b/libclamav/default.h @@ -25,6 +25,11 @@ #define CLI_DEFAULT_AC_MAXDEPTH 3 #define CLI_DEFAULT_AC_TRACKLEN 8 +#define CLI_DEFAULT_MOVETOAC_LEN 8 /* all static sigs shorter than + * this value will automatically + * go to AC instead of BM + */ + #define CLI_DEFAULT_LSIG_BUFSIZE 32768 #define CLI_DEFAULT_DBIO_BUFSIZE CLI_DEFAULT_LSIG_BUFSIZE + 1 diff --git a/libclamav/filetypes.c b/libclamav/filetypes.c index 2f4bcb9f2..cad6db810 100644 --- a/libclamav/filetypes.c +++ b/libclamav/filetypes.c @@ -176,7 +176,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine) if(cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)) return ret; - sret = cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL); + sret = cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, engine->root[0], &mdata, 0, ret, NULL, AC_SCAN_FT, NULL); cli_ac_freedata(&mdata); @@ -188,7 +188,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine) decoded = (unsigned char *) cli_utf16toascii((char *) buff, bread); if(decoded) { - sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, NULL, NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, desc, NULL, AC_SCAN_FT, NULL); + sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, NULL, NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, NULL, AC_SCAN_FT, NULL); free(decoded); if(sret == CL_TYPE_HTML) ret = CL_TYPE_HTML_UTF16; @@ -221,7 +221,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine) return ret; if(out_area.length > 0) { - sret = cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, engine->root[0], &mdata, 0, 0, desc, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */ + sret = cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, engine->root[0], &mdata, 0, 0, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */ if(sret == CL_TYPE_HTML) { cli_dbgmsg("cli_filetype2: detected HTML signature in Unicode file\n"); /* htmlnorm is able to handle any unicode now, since it skips null chars */ diff --git a/libclamav/matcher-ac.c b/libclamav/matcher-ac.c index f78c38e05..7e238e210 100644 --- a/libclamav/matcher-ac.c +++ b/libclamav/matcher-ac.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * @@ -386,8 +386,6 @@ void cli_ac_free(struct cli_matcher *root) patt = root->ac_pattable[i]; mpool_free(root->mempool, patt->prefix ? patt->prefix : patt->pattern); mpool_free(root->mempool, patt->virname); - if(patt->offset) - mpool_free(root->mempool, patt->offset); if(patt->alt) mpool_ac_free_alt(root->mempool, patt); mpool_free(root->mempool, patt); @@ -395,6 +393,9 @@ void cli_ac_free(struct cli_matcher *root) if(root->ac_pattable) mpool_free(root->mempool, root->ac_pattable); + if(root->ac_reloff) + mpool_free(root->mempool, root->ac_reloff); + for(i = 0; i < root->ac_nodes; i++) { if(!IS_LEAF(root->ac_nodetable[i])) mpool_free(root->mempool, root->ac_nodetable[i]->trans); @@ -812,6 +813,31 @@ int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, return CL_SUCCESS; } +int cli_ac_caloff(struct cli_matcher *root, int fd) +{ + int ret; + unsigned int i; + struct cli_ac_patt *patt; + struct cli_target_info info; + + memset(&info, 0, sizeof(info)); + for(i = 0; i < root->ac_reloff_num; i++) { + patt = root->ac_reloff[i]; + if(fd == -1) { + patt->offset_min = CLI_OFF_NONE; + } else if((ret = cli_caloff(NULL, &info, fd, root->type, patt->offdata, &patt->offset_min, &patt->offset_max))) { + cli_errmsg("cli_ac_caloff: Can't calculate relative offset in signature for %s\n", patt->virname); + if(info.exeinfo.section) + free(info.exeinfo.section); + return ret; + } + } + if(info.exeinfo.section) + free(info.exeinfo.section); + + return CL_SUCCESS; +} + void cli_ac_freedata(struct cli_ac_data *data) { uint32_t i; @@ -867,7 +893,7 @@ inline static int ac_addtype(struct cli_matched_type **list, cli_file_t type, of return CL_SUCCESS; } -int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, int fd, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx) +int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx) { struct cli_ac_node *current; struct cli_ac_patt *patt, *pt; @@ -875,11 +901,9 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v uint16_t j; int32_t **offmatrix; uint8_t found; - struct cli_target_info info; int type = CL_CLEAN; struct cli_ac_result *newres; - if(!root->ac_root) return CL_CLEAN; @@ -888,7 +912,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v return CL_ENULLARG; } - memset(&info, 0, sizeof(info)); current = root->ac_root; for(i = 0; i < length; i++) { @@ -902,24 +925,44 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v patt = current->list; while(patt) { bp = i + 1 - patt->depth; - if(ac_findmatch(buffer, bp, length, patt, &matchend)) { - pt = patt; + pt = patt; + /* + while(pt) { + if((pt->type && !(mode & AC_SCAN_FT)) || (!pt->type && !(mode & AC_SCAN_VIR))) { + pt = pt->next_same; + continue; + } + if(pt->offset_min == CLI_OFF_NONE) { + pt = pt->next_same; + continue; + } + realoff = offset + bp - pt->prefix_length; + if(pt->offset_min != CLI_OFF_ANY && (!pt->sigid || pt->partno == 1)) { + if(pt->offset_max > realoff || pt->offset_min < realoff) { + pt = pt->next_same; + continue; + } + } + break; + } + */ + if(pt && ac_findmatch(buffer, bp, length, patt, &matchend)) { while(pt) { - if((pt->type && !(mode & AC_SCAN_FT)) || (!pt->type && !(mode & AC_SCAN_VIR))) { pt = pt->next_same; continue; } - + if(pt->offset_min == CLI_OFF_NONE) { + pt = pt->next_same; + continue; + } realoff = offset + bp - pt->prefix_length; - - if(pt->offset && (!pt->sigid || pt->partno == 1)) { - if(!cli_validatesig(ftype, pt->offset, realoff, &info, fd, pt->virname)) { + if(pt->offset_min != CLI_OFF_ANY && (!pt->sigid || pt->partno == 1)) { + if(pt->offset_max > realoff || pt->offset_min < realoff) { pt = pt->next_same; continue; } } - if(pt->sigid) { /* it's a partial signature */ if(pt->partno != 1 && (!mdata->offmatrix[pt->sigid - 1] || !mdata->offmatrix[pt->sigid - 1][pt->partno - 2][0])) { @@ -931,8 +974,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v mdata->offmatrix[pt->sigid - 1] = cli_malloc(pt->parts * sizeof(int32_t *)); if(!mdata->offmatrix[pt->sigid - 1]) { cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u]\n", pt->sigid - 1); - if(info.exeinfo.section) - free(info.exeinfo.section); return CL_EMEM; } @@ -941,8 +982,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u][0]\n", pt->sigid - 1); free(mdata->offmatrix[pt->sigid - 1]); mdata->offmatrix[pt->sigid - 1] = NULL; - if(info.exeinfo.section) - free(info.exeinfo.section); return CL_EMEM; } memset(mdata->offmatrix[pt->sigid - 1][0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t)); @@ -981,25 +1020,17 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v } else if(found && pt->partno == pt->parts) { if(pt->type) { - if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype)) { - if(info.exeinfo.section) - free(info.exeinfo.section); - + if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype)) return CL_TYPE_IGNORED; - } if((pt->type > type || pt->type >= CL_TYPE_SFX || pt->type == CL_TYPE_MSEXE) && (!pt->rtype || ftype == pt->rtype)) { cli_dbgmsg("Matched signature for file type %s\n", pt->virname); type = pt->type; if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ || type == CL_TYPE_ZIPSFX) && (type >= CL_TYPE_SFX || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE))) { /* FIXME: we don't know which offset of the first part is the correct one */ - for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN && offmatrix[0][j] != -1; j++) { - if(ac_addtype(ftoffset, type, offmatrix[pt->parts - 1][j], ctx)) { - if(info.exeinfo.section) - free(info.exeinfo.section); + for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN && offmatrix[0][j] != -1; j++) + if(ac_addtype(ftoffset, type, offmatrix[pt->parts - 1][j], ctx)) return CL_EMEM; - } - } } memset(offmatrix[0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t)); @@ -1016,11 +1047,8 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v if(res) { newres = (struct cli_ac_result *) malloc(sizeof(struct cli_ac_result)); - if(!newres) { - if(info.exeinfo.section) - free(info.exeinfo.section); + if(!newres) return CL_EMEM; - } newres->virname = pt->virname; newres->customdata = pt->customdata; newres->next = *res; @@ -1033,10 +1061,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v *virname = pt->virname; if(customdata) *customdata = pt->customdata; - - if(info.exeinfo.section) - free(info.exeinfo.section); - return CL_VIRUS; } } @@ -1044,22 +1068,16 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v } else { /* old type signature */ if(pt->type) { - if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype)) { - if(info.exeinfo.section) - free(info.exeinfo.section); - + if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype)) return CL_TYPE_IGNORED; - } + if((pt->type > type || pt->type >= CL_TYPE_SFX || pt->type == CL_TYPE_MSEXE) && (!pt->rtype || ftype == pt->rtype)) { cli_dbgmsg("Matched signature for file type %s at %u\n", pt->virname, realoff); type = pt->type; if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ || type == CL_TYPE_ZIPSFX) && (type >= CL_TYPE_SFX || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE))) { - if(ac_addtype(ftoffset, type, realoff, ctx)) { - if(info.exeinfo.section) - free(info.exeinfo.section); + if(ac_addtype(ftoffset, type, realoff, ctx)) return CL_EMEM; - } } } } else { @@ -1071,11 +1089,8 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v if(res) { newres = (struct cli_ac_result *) malloc(sizeof(struct cli_ac_result)); - if(!newres) { - if(info.exeinfo.section) - free(info.exeinfo.section); + if(!newres) return CL_EMEM; - } newres->virname = pt->virname; newres->customdata = pt->customdata; newres->next = *res; @@ -1088,10 +1103,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v *virname = pt->virname; if(customdata) *customdata = pt->customdata; - - if(info.exeinfo.section) - free(info.exeinfo.section); - return CL_VIRUS; } } @@ -1104,9 +1115,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v } } - if(info.exeinfo.section) - free(info.exeinfo.section); - return (mode & AC_SCAN_FT) ? type : CL_CLEAN; } @@ -1445,26 +1453,32 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex if(new->lsigid[0]) root->ac_lsigtable[new->lsigid[1]]->virname = new->virname; - if(offset) { - new->offset = cli_mpool_strdup(root->mempool, offset); - if(!new->offset) { - mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern); - mpool_ac_free_alt(root->mempool, new); - mpool_free(root->mempool, new->virname); - mpool_free(root->mempool, new); - return CL_EMEM; - } + ret = cli_caloff(offset, NULL, -1, root->type, new->offdata, &new->offset_min, &new->offset_max); + if(ret != CL_SUCCESS) { + mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern); + mpool_ac_free_alt(root->mempool, new); + mpool_free(root->mempool, new->virname); + mpool_free(root->mempool, new); + return ret; } if((ret = cli_ac_addpatt(root, new))) { mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern); mpool_free(root->mempool, new->virname); mpool_ac_free_alt(root->mempool, new); - if(new->offset) - mpool_free(root->mempool, new->offset); mpool_free(root->mempool, new); return ret; } + if(new->offdata[0] != CLI_OFF_ANY && new->offdata[0] != CLI_OFF_ABSOLUTE) { + root->ac_reloff = (struct cli_ac_patt **) mpool_realloc2(root->mempool, root->ac_reloff, (root->ac_reloff_num + 1) * sizeof(struct cli_ac_patt *)); + if(!root->ac_reloff) { + cli_errmsg("cli_ac_addsig: Can't allocate memory for root->ac_reloff\n"); + return CL_EMEM; + } + root->ac_reloff[root->ac_reloff_num] = new; + root->ac_reloff_num++; + } + return CL_SUCCESS; } diff --git a/libclamav/matcher-ac.h b/libclamav/matcher-ac.h index ac55f2d5d..ae4aeae7b 100644 --- a/libclamav/matcher-ac.h +++ b/libclamav/matcher-ac.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * @@ -50,7 +50,7 @@ struct cli_ac_patt { uint32_t sigid; uint32_t lsigid[3]; uint16_t ch[2]; - char *virname, *offset; + char *virname; void *customdata; uint16_t ch_mindist[2]; uint16_t ch_maxdist[2]; @@ -59,6 +59,7 @@ struct cli_ac_patt { struct cli_ac_patt *next, *next_same; uint8_t depth; uint16_t rtype, type; + uint32_t offdata[4], offset_min, offset_max; }; struct cli_ac_node { @@ -81,9 +82,10 @@ int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern); int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen); int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, uint64_t *ids, unsigned int parse_only); void cli_ac_freedata(struct cli_ac_data *data); -int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, int fd, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx); +int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx); int cli_ac_buildtrie(struct cli_matcher *root); int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth); +int cli_ac_caloff(struct cli_matcher *root, int fd); void cli_ac_free(struct cli_matcher *root); int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, 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); diff --git a/libclamav/matcher-bm.c b/libclamav/matcher-bm.c index 5f833d405..dd82ad718 100644 --- a/libclamav/matcher-bm.c +++ b/libclamav/matcher-bm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * @@ -38,11 +38,12 @@ #define BM_BLOCK_SIZE 3 #define HASH(a,b,c) (211 * a + 37 * b + c) -int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern) +int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset) { uint16_t idx, i; const unsigned char *pt = pattern->pattern; struct cli_bm_patt *prev, *next = NULL; + int ret; if(pattern->length < BM_MIN_LENGTH) { @@ -50,6 +51,13 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern) return CL_EMALFDB; } + if((ret = cli_caloff(offset, NULL, -1, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) { + cli_errmsg("cli_bm_addpatt: Can't calculate offset for signature %s\n", pattern->virname); + return ret; + } + if(pattern->offdata[0] != CLI_OFF_ANY && pattern->offdata[0] != CLI_OFF_ABSOLUTE) + root->bm_reloff_num++; + #if BM_MIN_LENGTH == BM_BLOCK_SIZE /* try to load balance bm_suffix (at the cost of bm_shift) */ for(i = 0; i < pattern->length - BM_BLOCK_SIZE + 1; i++) { @@ -137,8 +145,6 @@ void cli_bm_free(struct cli_matcher *root) mpool_free(root->mempool, prev->pattern); if(prev->virname) mpool_free(root->mempool, prev->virname); - if(prev->offset) - mpool_free(root->mempool, prev->offset); mpool_free(root->mempool, prev); } } @@ -146,7 +152,7 @@ void cli_bm_free(struct cli_matcher *root) } } -int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, cli_file_t ftype, int fd) +int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd) { uint32_t i, j, off; uint8_t found, pchain, shift; @@ -154,7 +160,8 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v struct cli_bm_patt *p; const unsigned char *bp, *pt; unsigned char prefix; - struct cli_target_info info; + struct cli_target_info info; + int ret; if(!root || !root->bm_shift) @@ -164,7 +171,6 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v return CL_CLEAN; memset(&info, 0, sizeof(info)); - for(i = BM_MIN_LENGTH - BM_BLOCK_SIZE; i < length - BM_BLOCK_SIZE + 1; ) { idx = HASH(buffer[i], buffer[i + 1], buffer[i + 2]); shift = root->bm_shift[idx]; @@ -214,21 +220,26 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v } if(found && p->length + p->prefix_length == j) { - - if(p->offset) { + if(p->offset_min != CLI_OFF_ANY) { + if(p->offdata[0] != CLI_OFF_ABSOLUTE) { + ret = cli_caloff(NULL, &info, fd, root->type, p->offdata, &p->offset_min, &p->offset_max); + if(ret != CL_SUCCESS) { + cli_errmsg("cli_bm_scanbuff: Can't calculate relative offset in signature for %s\n", p->virname); + if(info.exeinfo.section) + free(info.exeinfo.section); + return ret; + } + } off = offset + i - p->prefix_length - BM_MIN_LENGTH + BM_BLOCK_SIZE; - if(!cli_validatesig(ftype, p->offset, off, &info, fd, p->virname)) { + if(p->offset_max > off || p->offset_min < off) { p = p->next; continue; } } - if(virname) *virname = p->virname; - if(info.exeinfo.section) free(info.exeinfo.section); - return CL_VIRUS; } @@ -243,6 +254,5 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v if(info.exeinfo.section) free(info.exeinfo.section); - return CL_CLEAN; } diff --git a/libclamav/matcher-bm.h b/libclamav/matcher-bm.h index 0deff456c..f4458aede 100644 --- a/libclamav/matcher-bm.h +++ b/libclamav/matcher-bm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * @@ -27,17 +27,17 @@ struct cli_bm_patt { unsigned char *pattern, *prefix; - char *virname, *offset; + char *virname; + uint32_t offdata[4], offset_min, offset_max; struct cli_bm_patt *next; uint16_t length, prefix_length; uint16_t cnt; unsigned char pattern0; - uint8_t target; }; -int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern); +int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset); int cli_bm_init(struct cli_matcher *root); -int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, cli_file_t ftype, int fd); +int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd); void cli_bm_free(struct cli_matcher *root); #endif diff --git a/libclamav/matcher.c b/libclamav/matcher.c index dd2008d00..a13fad89e 100644 --- a/libclamav/matcher.c +++ b/libclamav/matcher.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * @@ -76,8 +76,8 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) return ret; - if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, ftype, -1)) != CL_VIRUS) - ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, -1, NULL, AC_SCAN_VIR, NULL); + if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, -1)) != CL_VIRUS) + ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL); if(!acdata) cli_ac_freedata(&mdata); @@ -89,8 +89,8 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) return ret; - if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, ftype, -1)) != CL_VIRUS) - ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, -1, NULL, AC_SCAN_VIR, NULL); + if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, -1)) != CL_VIRUS) + ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL); if(!acdata) cli_ac_freedata(&mdata); @@ -98,112 +98,188 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, return ret; } -off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret, unsigned int *maxshift) +/* + * offdata[0]: type + * offdata[1]: offset value + * offdata[2]: max shift + * offdata[3]: section number + */ +int cli_caloff(const char *offstr, struct cli_target_info *info, int fd, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max) { int (*einfo)(int, struct cli_exe_info *) = NULL; + char offcpy[65]; unsigned int n, val; - const char *pt; - off_t pos, offset; - - - *ret = 0; + char *pt; + off_t pos; + struct stat sb; - if((pt = strchr(offstr, ','))) - *maxshift = atoi(++pt); - if(isdigit(offstr[0])) - return atoi(offstr); + if(!info) { /* decode offset string */ + if(!offstr) { + cli_errmsg("cli_caloff: offstr == NULL\n"); + return CL_ENULLARG; + } - if(fd == -1) { - *ret = -1; - return 0; - } + if(!strcmp(offstr, "*")) { + offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY; + return CL_SUCCESS; + } - if(!strncmp(offstr, "EP", 2) || offstr[0] == 'S') { + if(strlen(offstr) > 64) { + cli_errmsg("cli_caloff: Offset string too long\n"); + return CL_EMALFDB; + } + strcpy(offcpy, offstr); - if(info->status == -1) { - *ret = -1; - return 0; + if((pt = strchr(offcpy, ','))) { + if(!cli_isnumber(pt + 1)) { + cli_errmsg("cli_caloff: Invalid offset shift value\n"); + return CL_EMALFDB; + } + offdata[2] = atoi(pt + 1); + *pt = 0; + } else { + offdata[2] = 0; + } - } else if(!info->status) { + *offset_max = *offset_min = CLI_OFF_NONE; - if(ftype == CL_TYPE_MSEXE) - einfo = cli_peheader; - else if(ftype == CL_TYPE_ELF) - einfo = cli_elfheader; - else if(ftype == CL_TYPE_MACHO) - einfo = cli_machoheader; + if(!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) { + if(offcpy[2] == '+') + offdata[0] = CLI_OFF_EP_PLUS; + else + offdata[0] = CLI_OFF_EP_MINUS; - if(einfo) { - if((pos = lseek(fd, 0, SEEK_CUR)) == -1) { - cli_dbgmsg("Invalid descriptor\n"); - info->status = *ret = -1; - return 0; + if(!cli_isnumber(&offcpy[3])) { + cli_errmsg("cli_caloff: Invalid offset value\n"); + return CL_EMALFDB; + } + offdata[1] = atoi(&offcpy[3]); + + } else if(offcpy[0] == 'S') { + if(!strncmp(offstr, "SL+", 3)) { + offdata[0] = CLI_OFF_SL_PLUS; + if(!cli_isnumber(&offcpy[3])) { + cli_errmsg("cli_caloff: Invalid offset value\n"); + return CL_EMALFDB; } + offdata[1] = atoi(&offcpy[3]); + + } else if(sscanf(offcpy, "S%u+%u", &n, &val) == 2) { + offdata[0] = CLI_OFF_SX_PLUS; + offdata[1] = val; + offdata[3] = n; + } else { + cli_errmsg("cli_caloff: Invalid offset string\n"); + return CL_EMALFDB; + } - lseek(fd, 0, SEEK_SET); - if(einfo(fd, &info->exeinfo)) { - lseek(fd, pos, SEEK_SET); - info->status = *ret = -1; - return 0; - } - lseek(fd, pos, SEEK_SET); - info->status = 1; + } else if(!strncmp(offcpy, "EOF-", 4)) { + offdata[0] = CLI_OFF_EOF_MINUS; + if(!cli_isnumber(&offcpy[4])) { + cli_errmsg("cli_caloff: Invalid offset value\n"); + return CL_EMALFDB; } + offdata[1] = atoi(&offcpy[4]); + } else { + offdata[0] = CLI_OFF_ABSOLUTE; + if(!cli_isnumber(offcpy)) { + cli_errmsg("cli_caloff: Invalid offset value\n"); + return CL_EMALFDB; + } + *offset_min = offdata[1] = atoi(offcpy); + *offset_max = *offset_min + offdata[2]; } - } - - if(info->status == 1 && (!strncmp(offstr, "EP+", 3) || !strncmp(offstr, "EP-", 3))) { - - if(offstr[2] == '+') - return info->exeinfo.ep + atoi(offstr + 3); - else - return info->exeinfo.ep - atoi(offstr + 3); - } else if(info->status == 1 && offstr[0] == 'S') { + if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE && offdata[0] != CLI_OFF_EOF_MINUS) { + if(target != 1 && target != 6 && target != 9) { + cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target); + return CL_EMALFDB; + } + } - if(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) { + } else { + /* calculate relative offsets */ + if(info->status == -1) { + *offset_min = *offset_max = 0; + return CL_SUCCESS; + } - if(sscanf(offstr, "SL+%u", &val) != 1) { - *ret = -1; - return 0; + if((offdata[0] == CLI_OFF_EOF_MINUS)) { + if(!info->fsize) { + if(fstat(fd, &sb) == -1) { + cli_errmsg("cli_caloff: fstat(%d) failed\n", fd); + return CL_ESTAT; + } + info->fsize = sb.st_size; } - offset = val + info->exeinfo.section[info->exeinfo.nsections - 1].raw; - - } else { + } else if(!info->status) { + if(target == 1) + einfo = cli_peheader; + else if(target == 6) + einfo = cli_elfheader; + else if(target == 9) + einfo = cli_machoheader; - if(sscanf(offstr, "S%u+%u", &n, &val) != 2) { - *ret = -1; - return 0; + if(!einfo) { + cli_errmsg("cli_caloff: Invalid offset/filetype\n"); + return CL_EMALFDB; } - if(n >= info->exeinfo.nsections || !info->exeinfo.section[n].rsz) { - *ret = -1; - return 0; + if((pos = lseek(fd, 0, SEEK_CUR)) == -1) { + cli_errmsg("cli_caloff: lseek(%d) failed\n", fd); + return CL_ESEEK; } - offset = val + info->exeinfo.section[n].raw; + lseek(fd, 0, SEEK_SET); + if(einfo(fd, &info->exeinfo)) { + /* einfo *may* fail */ + lseek(fd, pos, SEEK_SET); + info->status = -1; + *offset_min = *offset_max = 0; + return CL_SUCCESS; + } + lseek(fd, pos, SEEK_SET); + info->status = 1; } - return offset; + switch(offdata[0]) { + case CLI_OFF_EOF_MINUS: + *offset_min = info->fsize - offdata[1]; + break; - } else if(!strncmp(offstr, "EOF-", 4)) { - struct stat sb; + case CLI_OFF_EP_PLUS: + *offset_min = info->exeinfo.ep + offdata[1]; + break; - if(!info->fsize) { - if(fstat(fd, &sb) == -1) { - info->status = *ret = -1; - return 0; - } - info->fsize = sb.st_size; + case CLI_OFF_EP_MINUS: + *offset_min = info->exeinfo.ep - offdata[1]; + break; + + case CLI_OFF_SL_PLUS: + *offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1]; + break; + + case CLI_OFF_SX_PLUS: + if(offdata[3] >= info->exeinfo.nsections) + *offset_min = 0; + else + *offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1]; + break; + + default: + cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]); + return CL_EARG; } - return info->fsize - atoi(offstr + 4); + if(!*offset_min) + *offset_max = 0; + else + *offset_max = *offset_min + offdata[2]; } - *ret = -1; - return 0; + return CL_SUCCESS; } int cli_checkfp(int fd, cli_ctx *ctx) @@ -227,7 +303,7 @@ int cli_checkfp(int fd, cli_ctx *ctx) return 0; } - if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, 0, -1) == CL_VIRUS) { + if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, -1) == CL_VIRUS) { cli_dbgmsg("cli_checkfp(): Found false positive detection (fp sig: %s)\n", virname); free(digest); lseek(fd, pos, SEEK_SET); @@ -240,33 +316,6 @@ int cli_checkfp(int fd, cli_ctx *ctx) return 0; } -int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname) -{ - off_t offset; - int ret; - unsigned int maxshift = 0; - - - if(offstr) { - offset = cli_caloff(offstr, info, desc, ftype, &ret, &maxshift); - - if(ret == -1) - return 0; - - if(maxshift) { - if((fileoff < offset) || (fileoff > offset + (off_t) maxshift)) { - /* cli_dbgmsg("Signature offset: %lu, expected: [%lu..%lu] (%s)\n", (unsigned long int) fileoff, (unsigned long int) offset, (unsigned long int) (offset + maxshift), virname); */ - return 0; - } - } else if(fileoff != offset) { - /* cli_dbgmsg("Signature offset: %lu, expected: %lu (%s)\n", (unsigned long int) fileoff, (unsigned long int) offset, virname); */ - return 0; - } - } - - return 1; -} - int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode) { unsigned char *buffer, *buff, *endbl, *upt; @@ -316,12 +365,16 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc return CL_EMEM; } - if(!ftonly && (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) - return ret; + if(!ftonly) + if((ret = cli_ac_caloff(groot, desc)) || (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) + return ret; if(troot) { - if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) + if((ret = cli_ac_caloff(troot, desc)) || (ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) { + if(!ftonly) + cli_ac_freedata(&gdata); return ret; + } } if(!ftonly && ctx->engine->md5_hdb) @@ -344,8 +397,8 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc length += maxpatlen; if(troot) { - if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, ftype, desc)) != CL_VIRUS) - ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, desc, ftoffset, acmode, NULL); + if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, desc)) != CL_VIRUS) + ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, ftoffset, acmode, NULL); if(ret == CL_VIRUS) { free(buffer); @@ -361,8 +414,8 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc } if(!ftonly) { - if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, ftype, desc)) != CL_VIRUS) - ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, desc, ftoffset, acmode, NULL); + if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, desc)) != CL_VIRUS) + ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, ftoffset, acmode, NULL); if(ret == CL_VIRUS) { free(buffer); @@ -439,7 +492,7 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc if(!ftonly && ctx->engine->md5_hdb) { cli_md5_final(digest, &md5ctx); - if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, 0, -1) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, 0, -1) != CL_VIRUS)) + if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, -1) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, -1) != CL_VIRUS)) return CL_VIRUS; } diff --git a/libclamav/matcher.h b/libclamav/matcher.h index 82d030bc3..e97a52f40 100644 --- a/libclamav/matcher.h +++ b/libclamav/matcher.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * @@ -69,18 +69,22 @@ struct cli_ac_lsig { }; struct cli_matcher { + unsigned int type; + /* Extended Boyer-Moore */ uint8_t *bm_shift; struct cli_bm_patt **bm_suffix; struct cli_hashset md5_sizes_hs; uint32_t *soff, soff_len; /* for PE section sigs */ - uint32_t bm_patterns; + uint32_t bm_patterns, bm_reloff_num; /* Extended Aho-Corasick */ uint32_t ac_partsigs, ac_nodes, ac_patterns, ac_lsigs; struct cli_ac_lsig **ac_lsigtable; struct cli_ac_node *ac_root, **ac_nodetable; struct cli_ac_patt **ac_pattable; + struct cli_ac_patt **ac_reloff; + uint32_t ac_reloff_num; uint8_t ac_mindepth, ac_maxdepth; uint16_t maxpatlen; @@ -124,13 +128,20 @@ struct cli_target_info { int8_t status; /* 0 == not initialised, 1 == initialised OK, -1 == error */ }; +#define CLI_OFF_ANY 0xffffffff +#define CLI_OFF_NONE 0xfffffffe +#define CLI_OFF_ABSOLUTE 1 +#define CLI_OFF_EOF_MINUS 2 +#define CLI_OFF_EP_PLUS 3 +#define CLI_OFF_EP_MINUS 4 +#define CLI_OFF_SL_PLUS 5 +#define CLI_OFF_SX_PLUS 6 + int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata); int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode); -int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname); - -off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret, unsigned int *maxshift); +int cli_caloff(const char *offstr, struct cli_target_info *info, int fd, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max); int cli_checkfp(int fd, cli_ctx *ctx); diff --git a/libclamav/pe.c b/libclamav/pe.c index 1ce963bb2..06b9a26ae 100644 --- a/libclamav/pe.c +++ b/libclamav/pe.c @@ -928,8 +928,8 @@ int cli_scanpe(int desc, cli_ctx *ctx) for(j = 0; j < md5_sect->soff_len && md5_sect->soff[j] <= exe_sections[i].rsz; j++) { if(md5_sect->soff[j] == exe_sections[i].rsz) { unsigned char md5_dig[16]; - if(cli_md5sect(desc, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, 0, -1) == CL_VIRUS) { - if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, 0, -1) != CL_VIRUS) { + if(cli_md5sect(desc, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, -1) == CL_VIRUS) { + if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, -1) != CL_VIRUS) { free(section_hdr); free(exe_sections); diff --git a/libclamav/phishcheck.c b/libclamav/phishcheck.c index fb17476d0..8b5f2410d 100644 --- a/libclamav/phishcheck.c +++ b/libclamav/phishcheck.c @@ -1198,13 +1198,13 @@ static int hash_match(const struct regex_matcher *rlist, const char *host, size_ h[64]='\0'; cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen); if (prefix_matched) { - if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,0,-1) == CL_VIRUS) { + if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,-1) == CL_VIRUS) { cli_dbgmsg("prefix matched\n"); *prefix_matched = 1; } else return CL_SUCCESS; } - if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,0,-1) == CL_VIRUS) { + if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,-1) == CL_VIRUS) { cli_dbgmsg("This hash matched: %s\n", h); switch(*virname) { case 'W': diff --git a/libclamav/readdb.c b/libclamav/readdb.c index 6d2cc1987..f3c696b4c 100644 --- a/libclamav/readdb.c +++ b/libclamav/readdb.c @@ -120,10 +120,11 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex struct cli_bm_patt *bm_new; char *pt, *hexcpy, *start, *n; int ret, asterisk = 0; - unsigned int i, j, len, parts = 0; + unsigned int i, j, hexlen, parts = 0; int mindist = 0, maxdist = 0, error = 0; + hexlen = strlen(hexsig); if(strchr(hexsig, '{')) { root->ac_partsigs++; @@ -131,8 +132,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex if(!(hexcpy = cli_strdup(hexsig))) return CL_EMEM; - len = strlen(hexsig); - for(i = 0; i < len; i++) + for(i = 0; i < hexlen; i++) if(hexsig[i] == '{' || hexsig[i] == '*') parts++; @@ -224,8 +224,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex } else if(strchr(hexsig, '*')) { root->ac_partsigs++; - len = strlen(hexsig); - for(i = 0; i < len; i++) + for(i = 0; i < hexlen; i++) if(hexsig[i] == '*') parts++; @@ -247,7 +246,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex free(pt); } - } else if(root->ac_only || strpbrk(hexsig, "?(") || type || lsigid) { + } else if(root->ac_only || type || lsigid /* || (hexlen / 2 < CLI_DEFAULT_MOVETOAC_LEN) FIXME: unit tests */ || strpbrk(hexsig, "?(")) { if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) { cli_errmsg("cli_parse_add(): Problem adding signature (3).\n"); return ret; @@ -262,7 +261,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex mpool_free(root->mempool, bm_new); return CL_EMALFDB; } - bm_new->length = strlen(hexsig) / 2; + bm_new->length = hexlen / 2; bm_new->virname = cli_mpool_virname(root->mempool, (char *) virname, options & CL_DB_OFFICIAL); if(!bm_new->virname) { @@ -271,22 +270,10 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex return CL_EMEM; } - if(offset) { - bm_new->offset = cli_mpool_strdup(root->mempool, offset); - if(!bm_new->offset) { - mpool_free(root->mempool, bm_new->pattern); - mpool_free(root->mempool, bm_new->virname); - mpool_free(root->mempool, bm_new); - return CL_EMEM; - } - } - - bm_new->target = target; - if(bm_new->length > root->maxpatlen) root->maxpatlen = bm_new->length; - if((ret = cli_bm_addpatt(root, bm_new))) { + if((ret = cli_bm_addpatt(root, bm_new, offset))) { cli_errmsg("cli_parse_add(): Problem adding signature (4).\n"); mpool_free(root->mempool, bm_new->pattern); mpool_free(root->mempool, bm_new->virname); @@ -308,14 +295,14 @@ static int cli_initroots(struct cl_engine *engine, unsigned int options) if(!engine->root[i]) { cli_dbgmsg("Initializing engine->root[%d]\n", i); root = engine->root[i] = (struct cli_matcher *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher)); -#ifdef USE_MPOOL - root->mempool = engine->mempool; -#endif if(!root) { cli_errmsg("cli_initroots: Can't allocate memory for cli_matcher\n"); return CL_EMEM; } - +#ifdef USE_MPOOL + root->mempool = engine->mempool; +#endif + root->type = i; if(cli_mtargets[i].ac_only || engine->ac_only) root->ac_only = 1; @@ -511,7 +498,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, 0, 0, NULL, 0, NULL, options))) { + if((ret = cli_parse_add(root, start, pt, 0, 0, "*", 0, NULL, options))) { ret = CL_EMALFDB; break; } @@ -576,27 +563,6 @@ static int cli_loadpdb(FILE *fs, struct cl_engine *engine, unsigned int *signo, return CL_SUCCESS; } -static int cli_checkoffset(const char *offset, unsigned int type) -{ - unsigned int foo; - const char *pt = offset; - - if(isdigit(*offset)) { - while(*pt++) - if(!strchr("0123456789,", *pt)) - return 1; - return 0; - } - - if(!strncmp(offset, "EOF-", 4)) - return 0; - - if((type == 1 || type == 6 || type == 9) && (!strncmp(offset, "EP+", 3) || !strncmp(offset, "EP-", 3) || (sscanf(offset, "SL+%u", &foo) == 1) || (sscanf(offset, "S%u+%u", &foo, &foo) == 2))) - return 0; - - return 1; -} - #define NDB_TOKENS 6 static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned short sdb, unsigned int options, struct cli_dbio *dbio, const char *dbname) { @@ -680,15 +646,6 @@ static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo, root = engine->root[target]; offset = tokens[2]; - if(!strcmp(offset, "*")) - offset = NULL; - - if(offset && cli_checkoffset(offset, target)) { - cli_errmsg("Incorrect offset '%s' for signature type-%u\n", offset, target); - ret = CL_EMALFDB; - break; - } - sig = tokens[3]; if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, NULL, options))) { @@ -1025,19 +982,11 @@ static int cli_loadldb(FILE *fs, struct cl_engine *engine, unsigned int *signo, *pt = 0; sig = ++pt; offset = tokens[3 + i]; - if(!strcmp(offset, "*")) - offset = NULL; } else { - offset = NULL; + offset = "*"; sig = tokens[3 + i]; } - if(offset && cli_checkoffset(offset, tdb.target[0])) { - cli_errmsg("Incorrect offset '%s' in subsignature id %u for signature type-%u\n", offset, i, tdb.target[0]); - ret = CL_EMALFDB; - break; - } - if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, lsigid, options))) { ret = CL_EMALFDB; break; @@ -1131,7 +1080,7 @@ static int cli_loadftm(FILE *fs, struct cl_engine *engine, unsigned int options, } if(atoi(tokens[0]) == 1) { /* A-C */ - if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], rtype, type, strcmp(tokens[1], "*") ? tokens[1] : NULL, 0, NULL, options))) + if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], rtype, type, tokens[1], 0, NULL, options))) break; } else if(atoi(tokens[0]) == 0) { /* memcmp() */ @@ -1394,7 +1343,7 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo, MD5_DB; } - if((ret = cli_bm_addpatt(db, new))) { + if((ret = cli_bm_addpatt(db, new, "0"))) { cli_errmsg("cli_loadmd5: Error adding BM pattern\n"); mpool_free(engine->mempool, new->pattern); mpool_free(engine->mempool, new->virname); @@ -2203,7 +2152,7 @@ int cl_engine_compile(struct cl_engine *engine) if((root = engine->root[i])) { if((ret = cli_ac_buildtrie(root))) return ret; - cli_dbgmsg("matcher[%u]: %s: AC sigs: %u BM sigs: %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->bm_patterns, root->ac_only ? "(ac_only mode)" : ""); + cli_dbgmsg("matcher[%u]: %s: AC sigs: %u (reloff: %u) BM sigs: %u (reloff: %u) %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->bm_patterns, root->bm_reloff_num, root->ac_only ? "(ac_only mode)" : ""); } } diff --git a/libclamav/readdb.h b/libclamav/readdb.h index 1f9a4a1e2..696e55e08 100644 --- a/libclamav/readdb.h +++ b/libclamav/readdb.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Sourcefire, Inc. + * Copyright (C) 2007-2009 Sourcefire, Inc. * * Authors: Tomasz Kojm * diff --git a/libclamav/regex_list.c b/libclamav/regex_list.c index 802829c8f..9a6f47dd9 100644 --- a/libclamav/regex_list.c +++ b/libclamav/regex_list.c @@ -305,7 +305,7 @@ int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* di * negatives */ return 0; } - rc = cli_ac_scanbuff((const unsigned char*)bufrev,buffer_len, NULL, (void*)®ex, &res, &matcher->suffixes,&mdata,0,0,-1,NULL,AC_SCAN_VIR,NULL); + rc = cli_ac_scanbuff((const unsigned char*)bufrev,buffer_len, NULL, (void*)®ex, &res, &matcher->suffixes,&mdata,0,0,NULL,AC_SCAN_VIR,NULL); free(bufrev); cli_ac_freedata(&mdata); @@ -455,7 +455,7 @@ static int add_hash(struct regex_matcher *matcher, char* pattern, const char fl, if (fl != 'W' && pat->length == 32 && cli_hashset_contains(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)) && - cli_bm_scanbuff(pat->pattern, 32, &vname, &matcher->sha256_hashes,0,0,-1) == CL_VIRUS) { + cli_bm_scanbuff(pat->pattern, 32, &vname, &matcher->sha256_hashes,0,-1) == CL_VIRUS) { if (*vname == 'W') { /* hash is whitelisted in local.gdb */ cli_dbgmsg("Skipping hash %s\n", pattern); @@ -471,7 +471,7 @@ static int add_hash(struct regex_matcher *matcher, char* pattern, const char fl, } *pat->virname = fl; cli_hashset_addkey(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)); - if((rc = cli_bm_addpatt(bm, pat))) { + if((rc = cli_bm_addpatt(bm, pat, "*"))) { cli_errmsg("add_hash: failed to add BM pattern\n"); free(pat->pattern); free(pat->virname); @@ -675,7 +675,7 @@ static int add_newsuffix(struct regex_matcher *matcher, struct regex_list *info, new->partno = 0; new->mindist = 0; new->maxdist = 0; - new->offset = 0; + new->offset_min = CLI_OFF_ANY; new->length = len; new->ch[0] = new->ch[1] |= CLI_MATCH_IGNORE; diff --git a/unit_tests/check_matchers.c b/unit_tests/check_matchers.c index 9fbc12952..170efb31a 100644 --- a/unit_tests/check_matchers.c +++ b/unit_tests/check_matchers.c @@ -69,7 +69,7 @@ START_TEST (test_ac_scanbuff) { fail_unless(ret == CL_SUCCESS, "cli_ac_init() failed"); for(i = 0; ac_testdata[i].data; i++) { - ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, NULL, 0, NULL, 0); + ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); } @@ -80,7 +80,7 @@ START_TEST (test_ac_scanbuff) { fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed"); for(i = 0; ac_testdata[i].data; i++) { - ret = cli_ac_scanbuff(ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, -1, NULL, AC_SCAN_VIR, NULL); + ret = cli_ac_scanbuff(ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL); fail_unless_fmt(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname); fail_unless_fmt(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname); } @@ -109,14 +109,14 @@ 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", 0, 0, NULL, 0, NULL, 0); + ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, NULL, 0, NULL, 0); + ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, NULL, 0, NULL, 0); + ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); - ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, 0, -1); + ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, -1); fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed"); fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n"); cli_bm_free(root);