[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