[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b
Török Edvin
edwin at clamav.net
Sun Apr 4 01:19:10 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit ab893605831b2f1026b1b791b2f43c78c63ce6a6
Author: Török Edvin <edwin at clamav.net>
Date: Mon Feb 8 13:45:03 2010 +0200
Support for macros in logical subsignatures (bb #164).
In the LDB there is (one or more) special subsignature ${min-max}MACROID$,
which means:
must match any signature from group MACROID (for current filetype),
and the match must occur at a distance of min-max from the start(!) of the
previous logical subsignature match.
It also has the sideeffect of making the previous subsignature considered a
match only if both that and the macro matches. The offset of first match for
the previous logical subsig will be the offset where the {min-max} distance is
satisfied.
The macro logical subsignature will have a count of 0 (if it didn't match
together with the previous subsig), or a count of 1 if it did.
The matches can occur anywhere (even in
different ac scan buffers), since I don't call cli_ac_scanbuff I just use the
offset of first match (which we have for the bytecode anyway).
There can be at most 32 macro groups, signatures are added to a macro group by
using $MACROID$ as offset.
For example pdb entries could be converted to PDB:3:$0:<hexsig of domainname>
if we assign macro id 0 to PDB (and we can assign 31 more macro ids to
whatever).
Example:
test.ldb:
TestMacro;Target:0;0&1;616161;${3-4}12$
test.ndb:
D:0:$12:6262
D:0:$12:6363
D:0:$11:6262
test.dat:
aaaaxccdd
test-nomatch.dat:
aaaaxxxccdd
diff --git a/libclamav/matcher-ac.c b/libclamav/matcher-ac.c
index 50e92ab..f01014d 100644
--- a/libclamav/matcher-ac.c
+++ b/libclamav/matcher-ac.c
@@ -952,6 +952,8 @@ int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs,
data->lsigsuboff[i][j] = CLI_OFF_NONE;
}
}
+ for (i=0;i<32;i++)
+ data->macro_lastmatch[i] = CLI_OFF_NONE;
return CL_SUCCESS;
}
@@ -1052,6 +1054,62 @@ inline static int ac_addtype(struct cli_matched_type **list, cli_file_t type, of
return CL_SUCCESS;
}
+static inline void lsig_sub_matched(const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t lsigid1, uint32_t lsigid2, uint32_t realoff)
+{
+ if(mdata->lsigsuboff[lsigid1][lsigid2] == CLI_OFF_NONE)
+ mdata->lsigsuboff[lsigid1][lsigid2] = realoff;
+ else if (mdata->lsigcnt[lsigid1][lsigid2] == 1) {
+ /* Check that the previous match had a macro match following it at the
+ * correct distance. This check is only done after the 1st match.*/
+ const struct cli_lsig_tdb *tdb = &root->ac_lsigtable[lsigid1]->tdb;
+ const struct cli_ac_patt *macropt;
+ uint32_t id, last_macro_match, smin, smax, last_macroprev_match;
+ if (!tdb->macro_ptids)
+ return;
+ id = tdb->macro_ptids[lsigid2];
+ if (!id)
+ return;
+ macropt = root->ac_pattable[id];
+ smin = macropt->ch_mindist[0];
+ smax = macropt->ch_maxdist[0];
+ /* start of last macro match */
+ last_macro_match = mdata->macro_lastmatch[macropt->sigid];
+ /* start of previous lsig subsig match */
+ last_macroprev_match = mdata->lsigsuboff[lsigid1][lsigid2];
+ if (last_macro_match != CLI_OFF_NONE)
+ cli_dbgmsg("Checking macro match: %u + (%u - %u) == %u\n",
+ last_macroprev_match, smin, smax, last_macro_match);
+ if (last_macro_match == CLI_OFF_NONE ||
+ last_macroprev_match + smin > last_macro_match ||
+ last_macroprev_match + smax < last_macro_match) {
+ cli_dbgmsg("Canceled false lsig macro match\n");
+ /* Previous match was false, cancel it and make this match the first
+ * one.*/
+ mdata->lsigcnt[lsigid1][lsigid2] = 0;
+ mdata->lsigsuboff[lsigid1][lsigid2] = realoff;
+ } else {
+ /* mark the macro sig itself matched */
+ mdata->lsigcnt[lsigid1][lsigid2+1]++;
+ mdata->lsigsuboff[lsigid1][lsigid2+1] = last_macro_match;
+ }
+ }
+ if (realoff != CLI_OFF_NONE) {
+ mdata->lsigcnt[lsigid1][lsigid2]++;
+ }
+}
+
+void cli_ac_chkmacro(struct cli_matcher *root, struct cli_ac_data *data, unsigned lsigid1)
+{
+ const struct cli_lsig_tdb *tdb = &root->ac_lsigtable[lsigid1]->tdb;
+ unsigned i;
+ /* Loop through all subsigs, and if they are tied to macros check that the
+ * macro matched at a correct distance */
+ for (i=0;i<tdb->subsigs;i++) {
+ lsig_sub_matched(root, data, lsigid1, i, CLI_OFF_NONE);
+ }
+}
+
+
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;
@@ -1084,7 +1142,7 @@ 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(patt->offdata[0] != CLI_OFF_VERSION && !patt->next_same && (patt->offset_min != CLI_OFF_ANY) && (!patt->sigid || patt->partno == 1)) {
+ if(patt->offdata[0] != CLI_OFF_VERSION && patt->offdata[0] != CLI_OFF_MACRO && !patt->next_same && (patt->offset_min != CLI_OFF_ANY) && (!patt->sigid || patt->partno == 1)) {
if(patt->offset_min == CLI_OFF_NONE) {
patt = patt->next;
continue;
@@ -1116,6 +1174,10 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
continue;
}
cli_dbgmsg("cli_ac_scanbuff: VI match for offset %x\n", realoff);
+ } else if (patt->offdata[0] == CLI_OFF_MACRO) {
+ mdata->macro_lastmatch[patt->offdata[1]] = realoff;
+ pt = pt->next_same;
+ continue;
} else if(pt->offset_min != CLI_OFF_ANY && (!pt->sigid || pt->partno == 1)) {
if(pt->offset_min == CLI_OFF_NONE) {
pt = pt->next_same;
@@ -1210,9 +1272,7 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
} else { /* !pt->type */
if(pt->lsigid[0]) {
- mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
- if(mdata->lsigsuboff[pt->lsigid[1]][pt->lsigid[2]] == CLI_OFF_NONE)
- mdata->lsigsuboff[pt->lsigid[1]][pt->lsigid[2]] = realoff;
+ lsig_sub_matched(root, mdata, pt->lsigid[1], pt->lsigid[2], realoff);
pt = pt->next_same;
continue;
}
@@ -1255,9 +1315,7 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
}
} else {
if(pt->lsigid[0]) {
- mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
- if(mdata->lsigsuboff[pt->lsigid[1]][pt->lsigid[2]] == CLI_OFF_NONE)
- mdata->lsigsuboff[pt->lsigid[1]][pt->lsigid[2]] = realoff;
+ lsig_sub_matched(root, mdata, pt->lsigid[1], pt->lsigid[2], realoff);
pt = pt->next_same;
continue;
}
@@ -1701,7 +1759,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
return ret;
}
- if(new->offdata[0] != CLI_OFF_ANY && new->offdata[0] != CLI_OFF_ABSOLUTE) {
+ if(new->offdata[0] != CLI_OFF_ANY && new->offdata[0] != CLI_OFF_ABSOLUTE && new->offdata[0] != CLI_OFF_MACRO) {
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");
diff --git a/libclamav/matcher-ac.h b/libclamav/matcher-ac.h
index 6fb2761..9bb004d 100644
--- a/libclamav/matcher-ac.h
+++ b/libclamav/matcher-ac.h
@@ -39,6 +39,7 @@ struct cli_ac_data {
uint32_t **lsigcnt;
uint32_t **lsigsuboff;
uint32_t *offset;
+ uint32_t macro_lastmatch[32];
/** Hashset for versioninfo matching */
struct cli_hashset vinfo;
};
@@ -88,6 +89,7 @@ struct cli_ac_result {
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, uint32_t reloffsigs, uint8_t tracklen);
+void cli_ac_chkmacro(struct cli_matcher *root, struct cli_ac_data *data, unsigned lsigid1);
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, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx);
diff --git a/libclamav/matcher.c b/libclamav/matcher.c
index 27b6be6..f445782 100644
--- a/libclamav/matcher.c
+++ b/libclamav/matcher.c
@@ -184,6 +184,17 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, fmap_t *map, un
} else if(!strncmp(offcpy, "VI", 2)) {
/* versioninfo */
offdata[0] = CLI_OFF_VERSION;
+ } else if (strchr(offcpy, '$')) {
+ if (sscanf(offcpy, "$%u$", &n) != 1) {
+ cli_errmsg("cli_caloff: Invalid macro($) in offset: %s\n", offcpy);
+ return CL_EMALFDB;
+ }
+ if (n >= 32) {
+ cli_errmsg("cli_caloff: at most 32 macro groups supported\n");
+ return CL_EMALFDB;
+ }
+ offdata[0] = CLI_OFF_MACRO;
+ offdata[1] = n;
} else {
offdata[0] = CLI_OFF_ABSOLUTE;
if(!cli_isnumber(offcpy)) {
@@ -194,7 +205,8 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, fmap_t *map, un
*offset_max = *offset_min + offdata[2];
}
- if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE && offdata[0] != CLI_OFF_EOF_MINUS) {
+ if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE &&
+ offdata[0] != CLI_OFF_EOF_MINUS && offdata[0] != CLI_OFF_MACRO) {
if(target != 1 && target != 6 && target != 9) {
cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target);
return CL_EMALFDB;
@@ -472,6 +484,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
for(i = 0; i < xroot->ac_lsigs; i++) { \
evalcnt = 0; \
evalids = 0; \
+ cli_ac_chkmacro(xroot, &xdata, i);\
if(cli_ac_chklsig(xroot->ac_lsigtable[i]->logic, xroot->ac_lsigtable[i]->logic + strlen(xroot->ac_lsigtable[i]->logic), xdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) { \
if(xroot->ac_lsigtable[i]->tdb.container && xroot->ac_lsigtable[i]->tdb.container[0] != ctx->container_type) \
continue; \
diff --git a/libclamav/matcher.h b/libclamav/matcher.h
index b90d84b..4df9d2f 100644
--- a/libclamav/matcher.h
+++ b/libclamav/matcher.h
@@ -61,6 +61,8 @@ struct cli_lsig_tdb {
*secturva, *sectuvsz, *secturaw, *sectursz;
*/
const char *icongrp1, *icongrp2;
+ uint32_t *macro_ptids;
+ uint32_t subsigs;
#ifdef USE_MPOOL
mpool_t *mempool;
#endif
@@ -155,6 +157,7 @@ struct cli_target_info {
#define CLI_OFF_SL_PLUS 5
#define CLI_OFF_SX_PLUS 6
#define CLI_OFF_VERSION 7
+#define CLI_OFF_MACRO 8
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);
diff --git a/libclamav/readdb.c b/libclamav/readdb.c
index d746b72..a94db15 100644
--- a/libclamav/readdb.c
+++ b/libclamav/readdb.c
@@ -118,6 +118,44 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
hexlen = strlen(hexsig);
+ if (hexsig[0] == '$') {
+ /* macro */
+ unsigned smin, smax, tid;
+ struct cli_ac_patt *pt;
+ if (hexsig[hexlen-1] != '$') {
+ cli_errmsg("cli_parseadd(): missing terminator $\n");
+ return CL_EMALFDB;
+ }
+ if (!lsigid) {
+ cli_errmsg("cli_parseadd(): macro signatures only valid inside logical signatures\n");
+ return CL_EMALFDB;
+ }
+ if (sscanf(hexsig,"${%u-%u}%u$",
+ &smin, &smax, &tid) != 3) {
+ cli_errmsg("cli_parseadd(): invalid macro signature format\n");
+ return CL_EMALFDB;
+ }
+ if (tid >= 32) {
+ cli_errmsg("cli_parseadd(): only 32 macro groups are supported\n");
+ return CL_EMALFDB;
+ }
+ pt = mpool_calloc(root->mempool, 1, sizeof(*pt));
+ if (!pt)
+ return CL_EMEM;
+ /* this is not a pattern that will be matched by AC itself, rather it is a
+ * pattern checked by the lsig code */
+ pt->ch_mindist[0] = smin;
+ pt->ch_maxdist[0] = smax;
+ pt->sigid = tid;
+ pt->length = root->ac_mindepth;
+ /* dummy */
+ pt->pattern = mpool_calloc(root->mempool, pt->length, sizeof(*pt->pattern));
+ if ((ret = cli_ac_addpatt(root, pt))) {
+ free(pt);
+ return ret;
+ }
+ return CL_SUCCESS;
+ }
if(strchr(hexsig, '{')) {
root->ac_partsigs++;
@@ -239,7 +277,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
free(pt);
}
- } else if(root->ac_only || type || lsigid || strpbrk(hexsig, "?([") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ','))) || strstr(offset, "VI")) {
+ } else if(root->ac_only || type || lsigid || strpbrk(hexsig, "?([") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ','))) || strstr(offset, "VI") || strchr(offset, '$')) {
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;
@@ -1112,6 +1150,8 @@ static int lsigattribs(char *attribs, struct cli_lsig_tdb *tdb)
mpool_free(x.mempool, x.range); \
if(x.cnt[CLI_TDB_STR]) \
mpool_free(x.mempool, x.str); \
+ if(x.macro_ptids)\
+ mpool_free(x.mempool, x.macro_ptids);\
} while(0);
#define LDB_TOKENS 67
@@ -1219,7 +1259,6 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
}
lsigid[0] = lsig->id = root->ac_lsigs;
- memcpy(&lsig->tdb, &tdb, sizeof(tdb));
root->ac_lsigs++;
newtable = (struct cli_ac_lsig **) mpool_realloc(engine->mempool, root->ac_lsigtable, root->ac_lsigs * sizeof(struct cli_ac_lsig *));
@@ -1235,6 +1274,7 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
lsig->bc_idx = bc_idx;
newtable[root->ac_lsigs - 1] = lsig;
root->ac_lsigtable = newtable;
+ tdb.subsigs = subsigs;
for(i = 0; i < subsigs; i++) {
lsigid[1] = i;
@@ -1251,6 +1291,14 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, lsigid, options)))
return ret;
+ if(sig[0] == '$' && i) {
+ /* allow mapping from lsig back to pattern for macros */
+ if (!tdb.macro_ptids)
+ tdb.macro_ptids = mpool_calloc(root->mempool, subsigs, sizeof(*tdb.macro_ptids));
+ if (!tdb.macro_ptids)
+ return CL_EMEM;
+ tdb.macro_ptids[i-1] = root->ac_patterns-1;
+ }
if(tdb.engine) {
if(tdb.engine[0] > cl_retflevel()) {
@@ -1265,6 +1313,7 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
}
}
}
+ memcpy(&lsig->tdb, &tdb, sizeof(tdb));
return CL_SUCCESS;
}
--
Debian repository for ClamAV
More information about the Pkg-clamav-commits
mailing list