END_TEST START_TEST (test_ac_scanbuff_allscan) { struct cli_ac_data mdata; struct cli_matcher *root; unsigned int i; int ret; root = ctx.engine->root[0]; fail_unless(root != NULL, "root == NULL"); root->ac_only = 1; #ifdef USE_MPOOL root->mempool = mpool_create(); #endif ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1); 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, 0, "*", 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); } ret = cli_ac_buildtrie(root); fail_unless(ret == CL_SUCCESS, "cli_ac_buildtrie() failed"); ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN); fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed"); ctx.options |= CL_SCAN_ALLMATCHES; for(i = 0; ac_testdata[i].data; i++) { ret = cli_ac_scanbuff((const unsigned char*)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); ret = cli_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), 0, &ctx, 0, NULL); fail_unless_fmt(ret == CL_VIRUS, "cli_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); if (ctx.num_viruses) ctx.num_viruses = 0; } cli_ac_freedata(&mdata); }
END_TEST START_TEST (test_ac_scanbuff_ex) { struct cli_ac_data mdata; struct cli_matcher *root; unsigned int i; int ret; root = ctx.engine->root[0]; fail_unless(root != NULL, "root == NULL"); root->ac_only = 1; #ifdef USE_MPOOL root->mempool = mpool_create(); #endif ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1); fail_unless(ret == CL_SUCCESS, "[ac_ex] cli_ac_init() failed"); for(i = 0; ac_sigopts_testdata[i].data; i++) { ret = cli_sigopts_handler(root, ac_sigopts_testdata[i].virname, ac_sigopts_testdata[i].hexsig, ac_sigopts_testdata[i].sigopts, 0, 0, ac_sigopts_testdata[i].offset, 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "[ac_ex] cli_sigopts_handler() failed"); } ret = cli_ac_buildtrie(root); fail_unless(ret == CL_SUCCESS, "[ac_ex] cli_ac_buildtrie() failed"); ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN); fail_unless(ret == CL_SUCCESS, "[ac_ex] cli_ac_initdata() failed"); for(i = 0; ac_sigopts_testdata[i].data; i++) { ret = cli_ac_scanbuff((const unsigned char*)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL); fail_unless_fmt(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result); if (ac_sigopts_testdata[i].expected_result == CL_VIRUS) fail_unless_fmt(!strncmp(virname, ac_sigopts_testdata[i].virname, strlen(ac_sigopts_testdata[i].virname)), "[ac_ex] Dataset %u matched with %s", i, virname); ret = cli_scanbuff((const unsigned char*)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, 0, &ctx, 0, NULL); fail_unless_fmt(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result); } cli_ac_freedata(&mdata); }
static inline int matcher_run(const struct cli_matcher *root, const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_data *mdata, uint32_t offset, const struct cli_target_info *tinfo, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int acmode, unsigned int pcremode, struct cli_ac_result **acres, fmap_t *map, struct cli_bm_off *offdata, struct cli_pcre_off *poffdata, cli_ctx *ctx) { int ret, saved_ret = CL_CLEAN; int32_t pos = 0; struct filter_match_info info; uint32_t orig_length, orig_offset; const unsigned char* orig_buffer; unsigned int viruses_found = 0; if (root->filter) { if(filter_search_ext(root->filter, buffer, length, &info) == -1) { /* for safety always scan last maxpatlen bytes */ pos = length - root->maxpatlen - 1; if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } else { /* must not cut buffer for 64[4-4]6161, because we must be able to check * 64! */ pos = info.first_match - root->maxpatlen - 1; if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } } else { PERF_LOG_FILTER(0, length, root->type); } orig_length = length; orig_buffer = buffer; orig_offset = offset; length -= pos; buffer += pos; offset += pos; if (!root->ac_only) { PERF_LOG_TRIES(0, 1, length); if (root->bm_offmode) { /* Don't use prefiltering for BM offset mode, since BM keeps tracks * of offsets itself, and doesn't work if we skip chunks of input * data */ ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, ctx); } else { ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, ctx); } if (ret != CL_CLEAN) { if (ret != CL_VIRUS) return ret; /* else (ret == CL_VIRUS) */ if (SCAN_ALL) viruses_found = 1; else { cli_append_virus(ctx, *virname); return ret; } } } PERF_LOG_TRIES(acmode, 0, length); ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, ctx); if (ret != CL_CLEAN) { if (ret == CL_VIRUS) { if (SCAN_ALL) viruses_found = 1; else { cli_append_virus(ctx, *virname); return ret; } } else if (ret > CL_TYPENO && acmode & AC_SCAN_VIR) saved_ret = ret; else return ret; } /* due to logical triggered, pcres cannot be evaluated until after full subsig matching */ /* cannot save pcre execution state without possible evasion; must scan entire buffer */ /* however, scanning the whole buffer may require the whole buffer being loaded into memory */ #if HAVE_PCRE if (root->pcre_metas) { int rc; uint64_t maxfilesize; if (map && (pcremode == PCRE_SCAN_FMAP)) { if (offset+length >= map->len) { /* check that scanned map does not exceed pcre maxfilesize limit */ maxfilesize = (uint64_t)cl_engine_get_num(ctx->engine, CL_ENGINE_PCRE_MAX_FILESIZE, &rc); if (rc != CL_SUCCESS) return rc; if (maxfilesize && (map->len > maxfilesize)) { cli_dbgmsg("matcher_run: pcre max filesize (map) exceeded (limit: %llu, needed: %llu)\n", (long long unsigned)maxfilesize, (long long unsigned)map->len); return CL_EMAXSIZE; } cli_dbgmsg("matcher_run: performing regex matching on full map: %u+%u(%u) >= %zu\n", offset, length, offset+length, map->len); buffer = fmap_need_off_once(map, 0, map->len); if (!buffer) return CL_EMEM; /* scan the full buffer */ ret = cli_pcre_scanbuf(buffer, map->len, virname, acres, root, mdata, poffdata, ctx); } } else if (pcremode == PCRE_SCAN_BUFF) { /* check that scanned buffer does not exceed pcre maxfilesize limit */ maxfilesize = (uint64_t)cl_engine_get_num(ctx->engine, CL_ENGINE_PCRE_MAX_FILESIZE, &rc); if (rc != CL_SUCCESS) return rc; if (maxfilesize && (length > maxfilesize)) { cli_dbgmsg("matcher_run: pcre max filesize (buf) exceeded (limit: %llu, needed: %u)\n", (long long unsigned)maxfilesize, length); return CL_EMAXSIZE; } cli_dbgmsg("matcher_run: performing regex matching on buffer with no map: %u+%u(%u)\n", offset, length, offset+length); /* scan the specified buffer */ ret = cli_pcre_scanbuf(buffer, length, virname, acres, root, mdata, poffdata, ctx); } } #endif /* HAVE_PCRE */ /* end experimental fragment */ if (ctx && !SCAN_ALL && ret == CL_VIRUS) cli_append_virus(ctx, *virname); if (ctx && SCAN_ALL && viruses_found) return CL_VIRUS; if (saved_ret && ret == CL_CLEAN) return saved_ret; return ret; }
static inline int matcher_run(const struct cli_matcher *root, const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_data *mdata, uint32_t offset, const struct cli_target_info *tinfo, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, fmap_t *map, struct cli_bm_off *offdata, uint32_t *viroffset, cli_ctx *ctx) { int ret; int32_t pos = 0; struct filter_match_info info; uint32_t orig_length, orig_offset; const unsigned char* orig_buffer; unsigned int viruses_found = 0; if (root->filter) { if(filter_search_ext(root->filter, buffer, length, &info) == -1) { /* for safety always scan last maxpatlen bytes */ pos = length - root->maxpatlen - 1; if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } else { /* must not cut buffer for 64[4-4]6161, because we must be able to check * 64! */ pos = info.first_match - root->maxpatlen - 1; if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } } else { PERF_LOG_FILTER(0, length, root->type); } orig_length = length; orig_buffer = buffer; orig_offset = offset; length -= pos; buffer += pos; offset += pos; if (!root->ac_only) { PERF_LOG_TRIES(0, 1, length); if (root->bm_offmode) { /* Don't use prefiltering for BM offset mode, since BM keeps tracks * of offsets itself, and doesn't work if we skip chunks of input * data */ ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset); } else { ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset); } if (ret == CL_VIRUS) { if (ctx) { cli_append_virus(ctx, *virname); if (SCAN_ALL) viruses_found++; else return ret; } } } PERF_LOG_TRIES(acmode, 0, length); ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, ctx); if (ctx && !SCAN_ALL && ret == CL_VIRUS) cli_append_virus(ctx, *virname); if (ctx && SCAN_ALL && viruses_found) return CL_VIRUS; return ret; }
static inline int matcher_run(const struct cli_matcher *root, const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_data *mdata, uint32_t offset, const struct cli_target_info *tinfo, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, fmap_t *map, struct cli_bm_off *offdata, uint32_t *viroffset, cli_ctx *ctx) { cli_infomsg(NULL,"DEBUG: in matcher_run\n");//CHR int ret; int32_t pos = 0; struct filter_match_info info; uint32_t orig_length, orig_offset; const unsigned char* orig_buffer; unsigned int viruses_found = 0; if (root->filter) { cli_infomsg(NULL,"DEBUG: has filter\n");//CHR // CHR function filter_search_ext will do pre-matchon prefix for a given pattern if(filter_search_ext(root->filter, buffer, length, &info) == -1) { cli_infomsg(NULL,"DEBUG: filter and in if\n");//CHR /* for safety always scan last maxpatlen bytes */ pos = length - root->maxpatlen - 1; if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } else { // CHR FSM match cli_infomsg(NULL,"DEBUG: filter and in else\n");//CHR /* must not cut buffer for 64[4-4]6161, because we must be able to check * 64! */ //CHR if first_match is far more beyond max pattern length //CHR we need to move forward a little bit to speed up the following scan pos = info.first_match - root->maxpatlen - 1; cli_infomsg(NULL,"DEBUG: pos=%d\n",pos);//CHR if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } } else { PERF_LOG_FILTER(0, length, root->type); } orig_length = length; orig_buffer = buffer; orig_offset = offset; //CHR pos is 0 in this case length -= pos; buffer += pos; offset += pos; if (!root->ac_only) { cli_infomsg(NULL,"DEBUG: !ac_only, bm scan first\n");//CHR PERF_LOG_TRIES(0, 1, length); if (root->bm_offmode) { /* Don't use prefiltering for BM offset mode, since BM keeps tracks * of offsets itself, and doesn't work if we skip chunks of input * data */ cli_infomsg(NULL,"DEBUG: scan in bm_offmode=1 mode\n"); //CHR ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset); } else { cli_infomsg(NULL,"DEBUG: scan in bm_offmode=0 mode\n"); //CHR cli_infomsg(NULL,"DEBUG: pass into cli_bm_scanbuff with length=%d,offset=%d\n",length,offset);//CHR ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset); } if (ret == CL_VIRUS) { cli_infomsg(NULL,"DEBUG: bm scan find virus, won't do ac scan\n");//CHR if (ctx) { cli_append_virus(ctx, *virname); if (SCAN_ALL) viruses_found++; else return ret; } } } PERF_LOG_TRIES(acmode, 0, length); cli_infomsg(NULL,"DEBUG: ac scan\n");//CHR ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL); if (ctx && ret == CL_VIRUS) cli_append_virus(ctx, *virname); if (ctx && SCAN_ALL && viruses_found) return CL_VIRUS; return ret; }
cli_file_t cli_filetype2(int desc, const struct cl_engine *engine) { unsigned char smallbuff[MAGIC_BUFFER_SIZE + 1], *decoded, *bigbuff; int bread, sret; cli_file_t ret = CL_TYPE_UNKNOWN_DATA; struct cli_matcher *root; struct cli_ac_data mdata; memset(smallbuff, 0, sizeof(smallbuff)); if((bread = read(desc, smallbuff, MAGIC_BUFFER_SIZE)) > 0) ret = cli_filetype(smallbuff, bread); if(engine && ret == CL_TYPE_UNKNOWN_TEXT) { root = engine->root[0]; if(!root) return ret; if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN)) return ret; sret = cli_ac_scanbuff(smallbuff, bread, NULL, engine->root[0], &mdata, 1, 0, 0, -1, NULL); cli_ac_freedata(&mdata); if(sret >= CL_TYPENO) { ret = sret; } else { if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN)) return ret; decoded = (unsigned char *) cli_utf16toascii((char *) smallbuff, bread); if(decoded) { sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, engine->root[0], &mdata, 1, 0, 0, -1, NULL); free(decoded); if(sret == CL_TYPE_HTML) ret = CL_TYPE_HTML_UTF16; } cli_ac_freedata(&mdata); if((((struct cli_dconf*) engine->dconf)->phishing & PHISHING_CONF_ENTCONV) && ret != CL_TYPE_HTML_UTF16) { struct entity_conv conv; const size_t conv_size = 2*bread < 256 ? 256 : 2*bread; if(init_entity_converter(&conv,UNKNOWN,conv_size) == 0) { int end = 0; m_area_t area; area.buffer = (unsigned char *) smallbuff; area.length = bread; area.offset = 0; while(!end) { if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN)) return ret; decoded = encoding_norm_readline(&conv, NULL, &area, bread); if(decoded) { sret = cli_ac_scanbuff(decoded, strlen((const char *) decoded), NULL, engine->root[0], &mdata, 1, 0, 0, -1, NULL); free(decoded); if(sret == CL_TYPE_HTML) { ret = CL_TYPE_HTML; end = 1; } } else end = 1; cli_ac_freedata(&mdata); } entity_norm_done(&conv); } else { cli_warnmsg("cli_filetype2: Error initializing entity converter\n"); } } } } if(ret == CL_TYPE_UNKNOWN_DATA || ret == CL_TYPE_UNKNOWN_TEXT) { if(!(bigbuff = (unsigned char *) cli_calloc(37638 + 1, sizeof(unsigned char)))) return ret; lseek(desc, 0, SEEK_SET); if((bread = read(desc, bigbuff, 37638)) > 0) { bigbuff[bread] = 0; switch(is_tar(bigbuff, bread)) { case 1: ret = CL_TYPE_OLD_TAR; cli_dbgmsg("Recognized old fashioned tar file\n"); break; case 2: ret = CL_TYPE_POSIX_TAR; cli_dbgmsg("Recognized POSIX tar file\n"); break; } } if(ret == CL_TYPE_UNKNOWN_DATA || ret == CL_TYPE_UNKNOWN_TEXT) { if(!memcmp(bigbuff + 32769, "CD001" , 5) || !memcmp(bigbuff + 37633, "CD001" , 5)) { cli_dbgmsg("Recognized ISO 9660 CD-ROM data\n"); ret = CL_TYPE_DATA; } else if(!memcmp(bigbuff + 32776, "CDROM" , 5)) { cli_dbgmsg("Recognized High Sierra CD-ROM data\n"); ret = CL_TYPE_DATA; } } free(bigbuff); } return ret; }