From 82fa5ba043b119795d7cd5720e326fc4af6afaaa Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Mon, 15 Sep 2014 18:10:11 -0400 Subject: [PATCH] pcre: added disabling mechanism to metas and matcher dconf: added field specific for pcre features dconf: added overall support dconf for pcre --- libclamav/dconf.c | 28 ++++++++++++++++++++++-- libclamav/dconf.h | 4 ++++ libclamav/matcher-pcre.c | 46 ++++++++++++++++++++++++++++++++++------ libclamav/matcher-pcre.h | 7 ++++-- libclamav/matcher.c | 4 ++-- libclamav/readdb.c | 2 +- 6 files changed, 77 insertions(+), 14 deletions(-) diff --git a/libclamav/dconf.c b/libclamav/dconf.c index 1defd3b01..4483de434 100644 --- a/libclamav/dconf.c +++ b/libclamav/dconf.c @@ -136,6 +136,8 @@ static struct dconf_module modules[] = { { "STATS", "DISABLED", DCONF_STATS_DISABLED, 0 }, { "STATS", "PESECTION DISABLED", DCONF_STATS_PE_SECTION_DISABLED, 0 }, + { "PCRE", "SUPPORT", PCRE_CONF_SUPPORT, 1 }, + { NULL, NULL, 0, 0 } }; @@ -189,6 +191,9 @@ struct cli_dconf *cli_dconf_init(void) } else if (!strcmp(modules[i].mname, "STATS")) { if (modules[i].state) dconf->stats |= modules[i].bflag; + } else if (!strcmp(modules[i].mname, "PCRE")) { + if (modules[i].state) + dconf->pcre |= modules[i].bflag; } } @@ -198,7 +203,7 @@ struct cli_dconf *cli_dconf_init(void) void cli_dconf_print(struct cli_dconf *dconf) { unsigned int pe = 0, elf = 0, macho = 0, arch = 0, doc = 0, mail = 0; - unsigned int other = 0, phishing = 0, i, bytecode=0, stats=0; + unsigned int other = 0, phishing = 0, i, bytecode=0, stats=0, pcre=0; cli_dbgmsg("Dynamic engine configuration settings:\n"); @@ -292,7 +297,17 @@ void cli_dconf_print(struct cli_dconf *dconf) } if (dconf->stats) - cli_dbgmsg(" * Submodule %10s:\t%s\n", modules[i].sname, (dconf->stats & modules[i].bflag) ? "On" : "** Off **"); + cli_dbgmsg(" * Submodule %10s:\t%s\n", modules[i].sname, (dconf->stats & modules[i].bflag) ? "On" : "** Off **"); + else + continue; + } else if (!strcmp(modules[i].mname, "PCRE")) { + if (!pcre) { + cli_dbgmsg("Module PCRE %s\n", dconf->pcre ? "On" : "Off"); + stats = 1; + } + + if (dconf->pcre) + cli_dbgmsg(" * Submodule %10s:\t%s\n", modules[i].sname, (dconf->pcre & modules[i].bflag) ? "On" : "** Off **"); else continue; } @@ -437,6 +452,15 @@ int cli_dconf_load(FILE *fs, struct cl_engine *engine, unsigned int options, str break; } } + + if(!strncmp(buffer, "PCRE:", 5) && chkflevel(buffer, 2)) { + if(sscanf(buffer + 5, "0x%x", &val) == 1) { + engine->dconf->pcre = val; + } else { + ret = CL_EMALFDB; + break; + } + } } if(ret) { diff --git a/libclamav/dconf.h b/libclamav/dconf.h index 900f6226b..3bc4aac99 100644 --- a/libclamav/dconf.h +++ b/libclamav/dconf.h @@ -42,6 +42,7 @@ struct cli_dconf { uint32_t phishing; uint32_t bytecode; uint32_t stats; + uint32_t pcre; }; /* PE flags */ @@ -129,6 +130,9 @@ struct cli_dconf { #define DCONF_STATS_DISABLED 0x1 #define DCONF_STATS_PE_SECTION_DISABLED 0x2 +/* PCRE flags */ +#define PCRE_CONF_SUPPORT 0x1 + #define BYTECODE_ENGINE_MASK (BYTECODE_INTERPRETER | BYTECODE_JIT_X86 | BYTECODE_JIT_PPC | BYTECODE_JIT_ARM) #ifdef USE_MPOOL diff --git a/libclamav/matcher-pcre.c b/libclamav/matcher-pcre.c index 257aeaccd..a6e827486 100644 --- a/libclamav/matcher-pcre.c +++ b/libclamav/matcher-pcre.c @@ -29,6 +29,7 @@ #if HAVE_PCRE #include "clamav.h" #include "cltypes.h" +#include "dconf.h" #include "others.h" #include "matcher.h" #include "matcher-pcre.h" @@ -142,7 +143,8 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char * } opt++; } - + /* TODO - better debug? */ + /* cli_dbgmsg("PCRE_CASELESS %08x\n", PCRE_CASELESS); cli_dbgmsg("PCRE_DOTALL %08x\n", PCRE_DOTALL); cli_dbgmsg("PCRE_MULTILINE %08x\n", PCRE_MULTILINE); @@ -153,6 +155,7 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char * cli_dbgmsg("PCRE_UNGREEDY %08x\n", PCRE_UNGREEDY); cli_dbgmsg("PCRE_OPTIONS %08x\n", pm->pdata.options); + */ } /* add pcre data to root after reallocation */ @@ -181,15 +184,27 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char * return CL_SUCCESS; } -int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit) + int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit, const struct cli_dconf *dconf) { unsigned int i; int ret; struct cli_pcre_meta *pm = NULL; + int disable_all = !(dconf->pcre & PCRE_CONF_SUPPORT); for (i = 0; i < root->pcre_metas; ++i) { pm = root->pcre_metatable[i]; + /* for safety, disable all pcre */ + if (disable_all) { + pm->flags |= CLI_PCRE_DISABLED; + continue; + } + + if (pm->flags & CLI_PCRE_DISABLED) { + cli_dbgmsg("cli_pcre_build: Skip compiling regex: %s (disabled)\n", pm->pdata.expression); + continue; + } + if (!pm) { cli_errmsg("cli_pcre_build: metadata for pcre %d is missing\n", i); return CL_ENULLARG; @@ -204,7 +219,8 @@ int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, lon /* parse the regex, no options override *wink* */ if ((ret = cli_pcre_compile(&(pm->pdata), match_limit, recmatch_limit, 0, 0)) != CL_SUCCESS) { - cli_errmsg("cli_pcre_build: failed to parse pcre regex\n"); + cli_errmsg("cli_pcre_build: failed to build pcre regex\n"); + pm->flags |= CLI_PCRE_DISABLED; /* disable the pcre */ return ret; } } @@ -212,7 +228,7 @@ int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, lon return CL_SUCCESS; } -int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struct cli_target_info *info) +int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struct cli_target_info *info, cli_ctx *ctx) { /* TANGENT: maintain relative offset data in cli_ac_data? */ int ret; @@ -223,7 +239,8 @@ int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struc if (!data) { return CL_ENULLARG; } - if (!root || !root->pcre_metatable || !info) { + + if (!(ctx->dconf->pcre & PCRE_CONF_SUPPORT) || !root || !root->pcre_metatable || !info) { data->shift = NULL; data->offset = NULL; return CL_SUCCESS; @@ -246,6 +263,13 @@ int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struc for (i = 0; i < root->pcre_metas; ++i) { pm = root->pcre_metatable[i]; + /* skip broken pcres, not getting executed always */ + if (pm->flags & CLI_PCRE_DISABLED) { + data->offset[i] = CLI_OFF_NONE; + data->shift[i] = CLI_OFF_NONE; + continue; + } + if (pm->offdata[0] == CLI_OFF_ANY) { data->offset[i] = 0; data->shift[i] = 0; @@ -269,6 +293,8 @@ int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struc data->shift[i] = endoff-(data->offset[i]); } + /* TODO: better debug? */ + /* cli_dbgmsg("info->fsize: %lu\n", (long unsigned)info->fsize); if (pm->offdata[0]>9) cli_dbgmsg("offdata[0] type: %x\n", pm->offdata[0]); @@ -279,7 +305,7 @@ int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struc cli_dbgmsg("offdata[3] section: %u\n", pm->offdata[3]); cli_dbgmsg("offset_min: %u\n", pm->offset_min); cli_dbgmsg("offset_max: %u\n", pm->offset_max); - + */ } for (i = 0; i < root->pcre_metas; ++i) { @@ -360,7 +386,7 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct uint32_t global, encompass; int rc, offset, ovector[OVECCOUNT]; - if (!root->pcre_metatable) { + if (!(ctx->dconf->pcre & PCRE_CONF_SUPPORT) || (!root->pcre_metatable)) { return CL_SUCCESS; } @@ -368,6 +394,12 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct pm = root->pcre_metatable[i]; pd = &(pm->pdata); + /* skip checking and running disabled pcres */ + if (pm->flags & CLI_PCRE_DISABLED) { + cli_dbgmsg("cli_pcre_scanbuf: skipping disabled regex /%s/\n", pd->expression); + continue; + } + /* check the evaluation of the trigger */ if (pm->lsigid[0]) { cli_dbgmsg("cli_pcre_scanbuf: checking %s; running regex /%s/\n", pm->trigger, pd->expression); diff --git a/libclamav/matcher-pcre.h b/libclamav/matcher-pcre.h index 7065174cd..522e4acd2 100644 --- a/libclamav/matcher-pcre.h +++ b/libclamav/matcher-pcre.h @@ -33,6 +33,7 @@ #include #include "cltypes.h" +#include "dconf.h" #include "mpool.h" #include "regex_pcre.h" @@ -40,6 +41,8 @@ #define CLI_PCRE_GLOBAL 0x00000001 /* g */ #define CLI_PCRE_ENCOMPASS 0x00000002 /* e */ +#define CLI_PCRE_DISABLED 0x80000000 /* used for dconf or fail to build */ + struct cli_pcre_meta { char *trigger; uint32_t lsigid[3]; /* 0=valid, 1=lsigid, 2=subsigid */ @@ -57,8 +60,8 @@ struct cli_pcre_off { }; int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *pattern, const char *cflags, const char *offset, const uint32_t *lsigid); -int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit); -int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struct cli_target_info *info); +int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit, const struct cli_dconf *dconf); +int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struct cli_target_info *info, cli_ctx *ctx); void cli_pcre_freeoff(struct cli_pcre_off *data); int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, struct cli_ac_result **res, const struct cli_pcre_off *data, cli_ctx *ctx); void cli_pcre_freemeta(struct cli_pcre_meta *pm); diff --git a/libclamav/matcher.c b/libclamav/matcher.c index e5ff23d03..0f8ebc0c7 100644 --- a/libclamav/matcher.c +++ b/libclamav/matcher.c @@ -967,7 +967,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli struct cli_pcre_off poff; /* calculate the relative offsets */ - ret = cli_pcre_recaloff(groot, &poff, &info); + ret = cli_pcre_recaloff(groot, &poff, &info, ctx); if (ret != CL_SUCCESS) { cli_ac_freedata(&gdata); cli_ac_freedata(&tdata); @@ -1009,7 +1009,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli struct cli_pcre_off poff; /* calculate the relative offsets */ - ret = cli_pcre_recaloff(troot, &poff, &info); + ret = cli_pcre_recaloff(troot, &poff, &info, ctx); if (ret != CL_SUCCESS) { cli_ac_freedata(&gdata); cli_ac_freedata(&tdata); diff --git a/libclamav/readdb.c b/libclamav/readdb.c index 6d3ac8dbe..abc89e7f9 100644 --- a/libclamav/readdb.c +++ b/libclamav/readdb.c @@ -3505,7 +3505,7 @@ int cl_engine_compile(struct cl_engine *engine) if((ret = cli_ac_buildtrie(root))) return ret; #if HAVE_PCRE - if((ret = cli_pcre_build(root, engine->pcre_match_limit, engine->pcre_recmatch_limit))) + if((ret = cli_pcre_build(root, engine->pcre_match_limit, engine->pcre_recmatch_limit, engine->dconf))) return ret; cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) PCREs: %u (reloff: %u, absoff: %u) maxpatlen %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->pcre_metas, root->pcre_reloff_num, root->pcre_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : "");