[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:36 UTC 2010


The following commit has been merged in the debian/unstable branch:
commit 461a7bd9025b88594c5239c027c68f65fb1a12f2
Merge: 40103a3004de9ab704bf4824aca2595753bc095d 2a94c08e19303bf4c7394fa11ba41dd337b60913
Author: Török Edvin <edwin at clamav.net>
Date:   Tue Feb 9 20:19:56 2010 +0200

    Merge branch 'prefiltering_split' into prefiltering3
    
    * prefiltering_split:
      move matching code to matcher_run.
      matcher-ac: move leaf checks inside IS_FINAL.
    
    Conflicts:
    	libclamav/matcher.c

diff --combined libclamav/matcher-ac.c
index f01014d,a43f458..21ae45e
--- a/libclamav/matcher-ac.c
+++ b/libclamav/matcher-ac.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - *  Copyright (C) 2007-2008 Sourcefire, Inc.
 + *  Copyright (C) 2007-2009 Sourcefire, Inc.
   *
   *  Authors: Tomasz Kojm
   *
@@@ -26,7 -26,6 +26,7 @@@
  #include <string.h>
  #include <stdlib.h>
  #include <ctype.h>
 +#include <sys/stat.h>
  
  #include <assert.h>
  #ifdef	HAVE_UNISTD_H
@@@ -45,45 -44,12 +45,45 @@@
  
  #include "mpool.h"
  
 +#define AC_SPECIAL_ALT_CHAR	1
 +#define AC_SPECIAL_ALT_STR	2
 +#define AC_SPECIAL_LINE_MARKER	3
 +#define AC_SPECIAL_BOUNDARY	4
 +
 +#define AC_BOUNDARY_LEFT		1
 +#define AC_BOUNDARY_LEFT_NEGATIVE	2
 +#define AC_BOUNDARY_RIGHT		4
 +#define AC_BOUNDARY_RIGHT_NEGATIVE	8
 +#define AC_LINE_MARKER_LEFT		16
 +#define AC_LINE_MARKER_LEFT_NEGATIVE	32
 +#define AC_LINE_MARKER_RIGHT		64
 +#define AC_LINE_MARKER_RIGHT_NEGATIVE	128
 +
 +static char boundary[256] = {
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    3, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 3, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 
 +    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 +};
 +
  int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern)
  {
  	struct cli_ac_node *pt, *next;
  	struct cli_ac_patt *ph;
  	void *newtable;
 -	struct cli_ac_alt *a1, *a2;
 +	struct cli_ac_special *a1, *a2;
  	uint8_t i, match;
  	uint16_t len = MIN(root->ac_maxdepth, pattern->length);
  
@@@ -164,31 -130,27 +164,31 @@@
      while(ph) {
  	if((ph->length == pattern->length) && (ph->prefix_length == pattern->prefix_length) && (ph->ch[0] == pattern->ch[0]) && (ph->ch[1] == pattern->ch[1])) {
  	    if(!memcmp(ph->pattern, pattern->pattern, ph->length * sizeof(uint16_t)) && !memcmp(ph->prefix, pattern->prefix, ph->prefix_length * sizeof(uint16_t))) {
 -		if(!ph->alt && !pattern->alt) {
 +		if(!ph->special && !pattern->special) {
  		    match = 1;
 -		} else if(ph->alt == pattern->alt) {
 +		} else if(ph->special == pattern->special) {
  		    match = 1;
 -		    for(i = 0; i < ph->alt; i++) {
 -			a1 = ph->alttable[i];
 -			a2 = pattern->alttable[i];
 +		    for(i = 0; i < ph->special; i++) {
 +			a1 = ph->special_table[i];
 +			a2 = pattern->special_table[i];
  
  			if(a1->num != a2->num) {
  			    match = 0;
  			    break;
  			}
 -			if(a1->chmode != a2->chmode) {
 +			if(a1->negative != a2->negative) {
 +			    match = 0;
 +			    break;
 +			}
 +			if(a1->type != a2->type) {
  			    match = 0;
  			    break;
 -			} else if(a1->chmode) {
 +			} else if(a1->type == AC_SPECIAL_ALT_CHAR) {
  			    if(memcmp(a1->str, a2->str, a1->num)) {
  				match = 0;
  				break;
  			    }
 -			} else {
 +			} else if(a1->type == AC_SPECIAL_ALT_STR) {
  			    while(a1 && a2) {
  				if((a1->len != a2->len) || memcmp(a1->str, a2->str, a1->len))
  				    break;
@@@ -333,7 -295,7 +333,7 @@@ static int ac_maketrans(struct cli_matc
  	    continue;
  	for(i = 0; i < 256; i++) {
  	    child = node->trans[i];
- 	    if(!child) {
+ 	    if (!child || (!IS_FINAL(child) && IS_LEAF(child))) {
  		struct cli_ac_node *failtarget = node->fail;
  		while(IS_LEAF(failtarget) || !failtarget->trans[i])
  		    failtarget = failtarget->fail;
@@@ -387,22 -349,22 +387,22 @@@ int cli_ac_init(struct cli_matcher *roo
  }
  
  #ifdef USE_MPOOL
 -#define mpool_ac_free_alt(a, b) ac_free_alt(a, b)
 -static void ac_free_alt(mpool_t *mempool, struct cli_ac_patt *p)
 +#define mpool_ac_free_special(a, b) ac_free_special(a, b)
 +static void ac_free_special(mpool_t *mempool, struct cli_ac_patt *p)
  #else
 -#define mpool_ac_free_alt(a, b) ac_free_alt(b)
 -static void ac_free_alt(struct cli_ac_patt *p)
 +#define mpool_ac_free_special(a, b) ac_free_special(b)
 +static void ac_free_special(struct cli_ac_patt *p)
  #endif
  {
 -	uint16_t i;
 -	struct cli_ac_alt *a1, *a2;
 +	unsigned int i;
 +	struct cli_ac_special *a1, *a2;
  
  
 -    if(!p->alt)
 +    if(!p->special)
  	return;
  
 -    for(i = 0; i < p->alt; i++) {
 -	a1 = p->alttable[i];
 +    for(i = 0; i < p->special; i++) {
 +	a1 = p->special_table[i];
  	while(a1) {
  	    a2 = a1;
  	    a1 = a1->next;
@@@ -411,7 -373,7 +411,7 @@@
  	    mpool_free(mempool, a2);
  	}
      }
 -    mpool_free(mempool, p->alttable);
 +    mpool_free(mempool, p->special_table);
  }
  
  void cli_ac_free(struct cli_matcher *root)
@@@ -424,16 -386,15 +424,16 @@@
  	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);
 +	if(patt->special)
 +	    mpool_ac_free_special(root->mempool, patt);
  	mpool_free(root->mempool, patt);
      }
      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);
@@@ -687,84 -648,61 +687,84 @@@ int cli_ac_chklsig(const char *expr, co
   *        more than one of them can match at the current position.
   */
  
 -#define AC_MATCH_CHAR(p,b)						\
 -    switch(wc = p & CLI_MATCH_WILDCARD) {				\
 -	case CLI_MATCH_CHAR:						\
 -	    if((unsigned char) p != b)					\
 -		match = 0;						\
 -	    break;							\
 -									\
 -	case CLI_MATCH_IGNORE:						\
 -	    break;							\
 -									\
 -	case CLI_MATCH_ALTERNATIVE:					\
 -	    match = 0;							\
 -	    alt = pattern->alttable[altcnt];				\
 -	    if(alt->chmode) {						\
 -		for(j = 0; j < alt->num; j++) {				\
 -		    if(alt->str[j] == b) {				\
 -			match = 1;					\
 -			break;						\
 -		    }							\
 -		}							\
 -	    } else {							\
 -		while(alt) {						\
 -		    if(bp + alt->len <= length) {			\
 -			if(!memcmp(&buffer[bp], alt->str, alt->len)) {	\
 -			    match = 1;					\
 -			    bp += alt->len - 1;				\
 -			    break;					\
 -			}						\
 -		    }							\
 -		    alt = alt->next;					\
 -		}							\
 -	    }								\
 -	    altcnt++;							\
 -	    break;							\
 -									\
 -	case CLI_MATCH_NIBBLE_HIGH:					\
 -	    if((unsigned char) (p & 0x00f0) != (b & 0xf0))		\
 -		match = 0;						\
 -	    break;							\
 -									\
 -	case CLI_MATCH_NIBBLE_LOW:					\
 -	    if((unsigned char) (p & 0x000f) != (b & 0x0f))		\
 -		match = 0;						\
 -	    break;							\
 -									\
 -	default:							\
 -	    cli_errmsg("ac_findmatch: Unknown wildcard 0x%x\n", wc);	\
 -	    match = 0;							\
 -    }
 -
 -inline static int ac_findmatch(const unsigned char *buffer, uint32_t offset, uint32_t length, const struct cli_ac_patt *pattern, uint32_t *end)
 +#define AC_MATCH_CHAR(p,b)								\
 +    switch(wc = p & CLI_MATCH_WILDCARD) {						\
 +	case CLI_MATCH_CHAR:								\
 +	    if((unsigned char) p != b)							\
 +		match = 0;								\
 +	    break;									\
 +											\
 +	case CLI_MATCH_IGNORE:								\
 +	    break;									\
 +											\
 +	case CLI_MATCH_SPECIAL:								\
 +	    special = pattern->special_table[specialcnt];				\
 +	    match = special->negative;							\
 +	    switch(special->type) {							\
 +		case AC_SPECIAL_ALT_CHAR:						\
 +		    for(j = 0; j < special->num; j++) {					\
 +			if(special->str[j] == b) {					\
 +			    match = !special->negative;					\
 +			    break;							\
 +			} else if(special->str[j] > b)					\
 +			    break;							\
 +		    }									\
 +		    break;								\
 +											\
 +		case AC_SPECIAL_ALT_STR:						\
 +		    while(special) {							\
 +			if(bp + special->len <= length) {				\
 +			    if(!memcmp(&buffer[bp], special->str, special->len)) {	\
 +				match = !special->negative;				\
 +				bp += special->len - 1;					\
 +				break;							\
 +			    }								\
 +			}								\
 +			special = special->next;					\
 +		    }									\
 +		    break;								\
 +											\
 +		case AC_SPECIAL_LINE_MARKER:						\
 +		    if(b == '\n') {							\
 +			match = !special->negative;					\
 +		    } else if(b == '\r' && (bp + 1 < length && buffer[bp + 1] == '\n')) {   \
 +			bp++;								\
 +			match = !special->negative;					\
 +		    }									\
 +		    break;								\
 +											\
 +		case AC_SPECIAL_BOUNDARY:						\
 +		    if(boundary[b])							\
 +			match = !special->negative;					\
 +		    break;								\
 +											\
 +		default:								\
 +		    cli_errmsg("ac_findmatch: Unknown special\n");			\
 +		    match = 0;								\
 +	    }										\
 +	    specialcnt++;								\
 +	    break;									\
 +											\
 +	case CLI_MATCH_NIBBLE_HIGH:							\
 +	    if((unsigned char) (p & 0x00f0) != (b & 0xf0))				\
 +		match = 0;								\
 +	    break;									\
 +											\
 +	case CLI_MATCH_NIBBLE_LOW:							\
 +	    if((unsigned char) (p & 0x000f) != (b & 0x0f))				\
 +		match = 0;								\
 +	    break;									\
 +											\
 +	default:									\
 +	    cli_errmsg("ac_findmatch: Unknown wildcard 0x%x\n", wc);			\
 +	    match = 0;									\
 +    }
 +
 +inline static int ac_findmatch(const unsigned char *buffer, uint32_t offset, uint32_t fileoffset, uint32_t length, const struct cli_ac_patt *pattern, uint32_t *end)
  {
  	uint32_t bp, match;
 -	uint16_t wc, i, j, altcnt = pattern->alt_pattern;
 -	struct cli_ac_alt *alt;
 +	uint16_t wc, i, j, specialcnt = pattern->special_pattern;
 +	struct cli_ac_special *special;
  
  
      if((offset + pattern->length > length) || (pattern->prefix_length > offset))
@@@ -781,38 -719,6 +781,38 @@@
      }
      *end = bp;
  
 +    if(pattern->boundary & AC_BOUNDARY_LEFT) {
 +	match = !!(pattern->boundary & AC_BOUNDARY_LEFT_NEGATIVE);
 +	if(!fileoffset || (offset && (boundary[buffer[offset - 1]] == 1 || boundary[buffer[offset - 1]] == 3)))
 +	    match = !match;
 +	if(!match)
 +	    return 0;
 +    }
 +
 +    if(pattern->boundary & AC_BOUNDARY_RIGHT) {
 +	match = !!(pattern->boundary & AC_BOUNDARY_RIGHT_NEGATIVE);
 +	if((length <= SCANBUFF) && (bp == length || boundary[buffer[bp]] >= 2))
 +	    match = !match;
 +	if(!match)
 +	    return 0;
 +    }
 +
 +    if(pattern->boundary & AC_LINE_MARKER_LEFT) {
 +	match = !!(pattern->boundary & AC_LINE_MARKER_LEFT_NEGATIVE);
 +	if(!fileoffset || (offset && (buffer[offset - 1] == '\n')))
 +	    match = !match;
 +	if(!match)
 +	    return 0;
 +    }
 +
 +    if(pattern->boundary & AC_LINE_MARKER_RIGHT) {
 +	match = !!(pattern->boundary & AC_LINE_MARKER_RIGHT_NEGATIVE);
 +	if((length <= SCANBUFF) && (bp == length || buffer[bp] == '\n' || (buffer[bp] == '\r' && bp + 1 < length && buffer[bp + 1] == '\n')))
 +	    match = !match;
 +	if(!match)
 +	    return 0;
 +    }
 +
      if(!(pattern->ch[1] & CLI_MATCH_IGNORE)) {
  	bp += pattern->ch_mindist[1];
  	for(i = pattern->ch_mindist[1]; i <= pattern->ch_maxdist[1]; i++) {
@@@ -829,7 -735,7 +829,7 @@@
      }
  
      if(pattern->prefix) {
 -	altcnt = 0;
 +	specialcnt = 0;
  	bp = offset - pattern->prefix_length;
  	match = 1;
  	for(i = 0; i < pattern->prefix_length; i++) {
@@@ -862,9 -768,9 +862,9 @@@
      return 1;
  }
  
 -int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen)
 +int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint32_t reloffsigs, uint8_t tracklen)
  {
 -	unsigned int i;
 +	unsigned int i, j;
  
  
      if(!data) {
@@@ -872,26 -778,12 +872,26 @@@
  	return CL_ENULLARG;
      }
  
 -    data->partsigs = partsigs;
 +    cli_hashset_init_noalloc(&data->vinfo);
  
 +    data->reloffsigs = reloffsigs;
 +    if(reloffsigs) {
 +	data->offset = (uint32_t *) cli_malloc(reloffsigs * 2 * sizeof(uint32_t));
 +	if(!data->offset) {
 +	    cli_errmsg("cli_ac_init: Can't allocate memory for data->offset\n");
 +	    return CL_EMEM;
 +	}
 +	for(i = 0; i < reloffsigs * 2; i += 2)
 +	    data->offset[i] = CLI_OFF_NONE;
 +    }
 +
 +    data->partsigs = partsigs;
      if(partsigs) {
  	data->offmatrix = (int32_t ***) cli_calloc(partsigs, sizeof(int32_t **));
  	if(!data->offmatrix) {
  	    cli_errmsg("cli_ac_init: Can't allocate memory for data->offmatrix\n");
 +	    if(reloffsigs)
 +		free(data->offset);
  	    return CL_EMEM;
  	}
      }
@@@ -902,8 -794,6 +902,8 @@@
  	if(!data->lsigcnt) {
  	    if(partsigs)
  		free(data->offmatrix);
 +	    if(reloffsigs)
 +		free(data->offset);
  	    cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigcnt\n");
  	    return CL_EMEM;
  	}
@@@ -912,82 -802,13 +912,82 @@@
  	    free(data->lsigcnt);
  	    if(partsigs)
  		free(data->offmatrix);
 +	    if(reloffsigs)
 +		free(data->offset);
  	    cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigcnt[0]\n");
  	    return CL_EMEM;
  	}
  	for(i = 1; i < lsigs; i++)
  	    data->lsigcnt[i] = data->lsigcnt[0] + 64 * i;
 -     }
 - 
 +
 +	/* subsig offsets */
 +	data->lsigsuboff = (uint32_t **) cli_malloc(lsigs * sizeof(uint32_t *));
 +	if(!data->lsigsuboff) {
 +	    free(data->lsigcnt[0]);
 +	    free(data->lsigcnt);
 +	    if(partsigs)
 +		free(data->offmatrix);
 +	    if(reloffsigs)
 +		free(data->offset);
 +	    cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigsuboff\n");
 +	    return CL_EMEM;
 +	}
 +	data->lsigsuboff[0] = (uint32_t *) cli_calloc(lsigs * 64, sizeof(uint32_t));
 +	if(!data->lsigsuboff[0]) {
 +	    free(data->lsigsuboff);
 +	    free(data->lsigcnt[0]);
 +	    free(data->lsigcnt);
 +	    if(partsigs)
 +		free(data->offmatrix);
 +	    if(reloffsigs)
 +		free(data->offset);
 +	    cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigsuboff[0]\n");
 +	    return CL_EMEM;
 +	}
 +	for(j = 0; j < 64; j++)
 +	    data->lsigsuboff[0][j] = CLI_OFF_NONE;
 +	for(i = 1; i < lsigs; i++) {
 +	    data->lsigsuboff[i] = data->lsigsuboff[0] + 64 * i;
 +	    for(j = 0; j < 64; j++)
 +		data->lsigsuboff[i][j] = CLI_OFF_NONE;
 +	}
 +    }
 +    for (i=0;i<32;i++)
 +	data->macro_lastmatch[i] = CLI_OFF_NONE;
 +
 +    return CL_SUCCESS;
 +}
 +
 +int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, fmap_t *map)
 +{
 +	int ret;
 +	unsigned int i;
 +	struct cli_ac_patt *patt;
 +	struct cli_target_info info;
 +
 +    if(map) {
 +	memset(&info, 0, sizeof(info));
 +	info.fsize = map->len;
 +    }
 +
 +    info.exeinfo.vinfo = &data->vinfo;
 +
 +    for(i = 0; i < root->ac_reloff_num; i++) {
 +	patt = root->ac_reloff[i];
 +	if(!map) {
 +	    data->offset[patt->offset_min] = CLI_OFF_NONE;
 +	} else if((ret = cli_caloff(NULL, &info, map, root->type, patt->offdata, &data->offset[patt->offset_min], &data->offset[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;
 +	} else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length > info.fsize)) {
 +	    data->offset[patt->offset_min] = CLI_OFF_NONE;
 +	}
 +    }
 +    if(map && info.exeinfo.section)
 +	free(info.exeinfo.section);
 +
      return CL_SUCCESS;
  }
  
@@@ -995,7 -816,6 +995,7 @@@ void cli_ac_freedata(struct cli_ac_dat
  {
  	uint32_t i;
  
 +    cli_hashset_destroy(&data->vinfo);
  
      if(data && data->partsigs) {
  	for(i = 0; i < data->partsigs; i++) {
@@@ -1011,15 -831,8 +1011,15 @@@
      if(data && data->lsigs) {
  	free(data->lsigcnt[0]);
  	free(data->lsigcnt);
 +	free(data->lsigsuboff[0]);
 +	free(data->lsigsuboff);
  	data->lsigs = 0;
      }
 +
 +    if(data && data->reloffsigs) {
 +	free(data->offset);
 +	data->reloffsigs = 0;
 +    }
  }
  
  inline static int ac_addtype(struct cli_matched_type **list, cli_file_t type, off_t offset, const cli_ctx *ctx)
@@@ -1054,63 -867,7 +1054,63 @@@
      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)
 +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;
  	struct cli_ac_patt *patt, *pt;
@@@ -1118,83 -875,49 +1118,81 @@@
  	uint16_t j;
  	int32_t **offmatrix;
  	uint8_t found;
  	int type = CL_CLEAN;
  	struct cli_ac_result *newres;
  
      if(!root->ac_root)
  	return CL_CLEAN;
  
 -    if(!mdata) {
 +    if(!mdata && (root->ac_partsigs || root->ac_lsigs || root->ac_reloff_num)) {
  	cli_errmsg("cli_ac_scanbuff: mdata == NULL\n");
  	return CL_ENULLARG;
      }
  
      current = root->ac_root;
  
      for(i = 0; i < length; i++)  {
- 
- 	if(IS_LEAF(current))
- 	    current = current->fail;
- 
  	current = current->trans[buffer[i]];
  
  	if(IS_FINAL(current)) {
  	    patt = current->list;
+ 	    if (IS_LEAF(current))
+ 		current = current->fail;
  	    while(patt) {
  		bp = i + 1 - patt->depth;
 -		if(ac_findmatch(buffer, bp, length, patt, &matchend)) {
 -		    pt = patt;
 +		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;
 +		    }
 +		    realoff = offset + bp - patt->prefix_length;
 +		    if(patt->offdata[0] == CLI_OFF_ABSOLUTE) {
 +			if(patt->offset_max < realoff || patt->offset_min > realoff) {
 +			    patt = patt->next;
 +			    continue;
 +			}
 +		    } else {
 +			if(mdata->offset[patt->offset_min] == CLI_OFF_NONE || mdata->offset[patt->offset_max] < realoff || mdata->offset[patt->offset_min] > realoff) {
 +			    patt = patt->next;
 +			    continue;
 +			}
 +		    }
 +		}
 +		pt = patt;
 +		if(ac_findmatch(buffer, bp, offset + bp - patt->prefix_length, length, patt, &matchend)) {
  		    while(pt) {
 -
  			if((pt->type && !(mode & AC_SCAN_FT)) || (!pt->type && !(mode & AC_SCAN_VIR))) {
  			    pt = pt->next_same;
  			    continue;
  			}
 -
  			realoff = offset + bp - pt->prefix_length;
 -
 -			if(pt->offset && (!pt->sigid || pt->partno == 1)) {
 -			    if((fd == -1 && !ftype) || !cli_validatesig(ftype, pt->offset, realoff, &info, fd, pt->virname)) {
 +			if(patt->offdata[0] == CLI_OFF_VERSION) {
 +			    if(!cli_hashset_contains_maybe_noalloc(&mdata->vinfo, realoff)) {
  				pt = pt->next_same;
  				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;
 +				continue;
 +			    }
 +			    if(pt->offdata[0] == CLI_OFF_ABSOLUTE) {
 +				if(pt->offset_max < realoff || pt->offset_min > realoff) {
 +				    pt = pt->next_same;
 +				    continue;
 +				}
 +			    } else {
 +				if(mdata->offset[pt->offset_min] == CLI_OFF_NONE || mdata->offset[pt->offset_max] < realoff || mdata->offset[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])) {
@@@ -1206,6 -929,8 +1204,6 @@@
  				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;
  				}
  
@@@ -1214,6 -939,8 +1212,6 @@@
  				    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));
@@@ -1252,17 -979,25 +1250,17 @@@
  			    } 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) && ((ftype == CL_TYPE_MSEXE && type >= CL_TYPE_SFX) || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE)))  {
 +					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));
@@@ -1272,28 -1007,34 +1270,28 @@@
  
  				} else { /* !pt->type */
  				    if(pt->lsigid[0]) {
 -					mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
 -					pt = pt->next;
 +					lsig_sub_matched(root, mdata, pt->lsigid[1], pt->lsigid[2], realoff);
 +					pt = pt->next_same;
  					continue;
  				    }
  
  				    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;
 +					newres->offset = realoff;
  					*res = newres;
  
 -					pt = pt->next;
 +					pt = pt->next_same;
  					continue;
  				    } else {
  					if(virname)
  					    *virname = pt->virname;
  					if(customdata)
  					    *customdata = pt->customdata;
 -
 -					if(info.exeinfo.section)
 -					    free(info.exeinfo.section);
 -
  					return CL_VIRUS;
  				    }
  				}
@@@ -1301,42 -1042,54 +1299,42 @@@
  
  			} 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) && ((ftype == CL_TYPE_MSEXE && type >= CL_TYPE_SFX) || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE)))  {
 +				    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 {
  				if(pt->lsigid[0]) {
 -				    mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
 -				    pt = pt->next;
 +				    lsig_sub_matched(root, mdata, pt->lsigid[1], pt->lsigid[2], realoff);
 +				    pt = pt->next_same;
  				    continue;
  				}
  
  				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->offset = realoff;
  				    newres->next = *res;
  				    *res = newres;
  
 -				    pt = pt->next;
 +				    pt = pt->next_same;
  				    continue;
  				} else {
  				    if(virname)
  					*virname = pt->virname;
  				    if(customdata)
  					*customdata = pt->customdata;
 -
 -				    if(info.exeinfo.section)
 -					free(info.exeinfo.section);
 -
  				    return CL_VIRUS;
  				}
  			    }
@@@ -1349,14 -1102,12 +1347,14 @@@
  	}
      }
  
      return (mode & AC_SCAN_FT) ? type : CL_CLEAN;
  }
  
 +static int qcompare(const void *a, const void *b)
 +{
 +    return *(const unsigned char *)a - *(const unsigned char *)b;
 +}
 +
  /* FIXME: clean up the code */
  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)
  {
@@@ -1364,7 -1115,7 +1362,7 @@@
  	char *pt, *pt2, *hex = NULL, *hexcpy = NULL;
  	uint16_t i, j, ppos = 0, pend, *dec, nzpos = 0;
  	uint8_t wprefix = 0, zprefix = 1, plen = 0, nzplen = 0;
 -	struct cli_ac_alt *newalt, *altpt, **newtable;
 +	struct cli_ac_special *newspecial, *specialpt, **newtable;
  	int ret, error = CL_SUCCESS;
  
  
@@@ -1499,149 -1250,99 +1497,149 @@@
  		error = CL_EMALFDB;
  		break;
  	    }
 -
 +	    newspecial = (struct cli_ac_special *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_special));
 +	    if(!newspecial) {
 +		cli_errmsg("cli_ac_addsig: Can't allocate newspecial\n");
 +		error = CL_EMEM;
 +		break;
 +	    }
 +	    if(pt >= hexcpy + 2) {
 +		if(pt[-2] == '!') {
 +		    newspecial->negative = 1;
 +		    pt[-2] = 0;
 +		}
 +	    }
  	    strcat(hexnew, start);
 -	    strcat(hexnew, "()");
  
  	    if(!(start = strchr(pt, ')'))) {
 +		mpool_free(root->mempool, newspecial);
  		error = CL_EMALFDB;
  		break;
  	    }
  	    *start++ = 0;
 -
 -	    newalt = (struct cli_ac_alt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_alt));
 -	    if(!newalt) {
 -		cli_errmsg("cli_ac_addsig: Can't allocate newalt\n");
 -		error = CL_EMEM;
 +	    if(!strlen(pt)) {
 +		cli_errmsg("cli_ac_addsig: Empty block\n");
 +		error = CL_EMALFDB;
  		break;
  	    }
  
 -	    new->alt++;
 -
 -	    newtable = (struct cli_ac_alt **) mpool_realloc(root->mempool, new->alttable, new->alt * sizeof(struct cli_ac_alt *));
 +	    if(!strcmp(pt, "B")) {
 +		if(!*start) {
 +		    new->boundary |= AC_BOUNDARY_RIGHT;
 +		    if(newspecial->negative)
 +			new->boundary |= AC_BOUNDARY_RIGHT_NEGATIVE;
 +		    mpool_free(root->mempool, newspecial);
 +		    continue;
 +		} else if(pt - 1 == hexcpy) {
 +		    new->boundary |= AC_BOUNDARY_LEFT;
 +		    if(newspecial->negative)
 +			new->boundary |= AC_BOUNDARY_LEFT_NEGATIVE;
 +		    mpool_free(root->mempool, newspecial);
 +		    continue;
 +		}
 +	    } else if(!strcmp(pt, "L")) {
 +		if(!*start) {
 +		    new->boundary |= AC_LINE_MARKER_RIGHT;
 +		    if(newspecial->negative)
 +			new->boundary |= AC_LINE_MARKER_RIGHT_NEGATIVE;
 +		    mpool_free(root->mempool, newspecial);
 +		    continue;
 +		} else if(pt - 1 == hexcpy) {
 +		    new->boundary |= AC_LINE_MARKER_LEFT;
 +		    if(newspecial->negative)
 +			new->boundary |= AC_LINE_MARKER_LEFT_NEGATIVE;
 +		    mpool_free(root->mempool, newspecial);
 +		    continue;
 +		}
 +	    }
 +	    strcat(hexnew, "()");
 +	    new->special++;
 +	    newtable = (struct cli_ac_special **) mpool_realloc(root->mempool, new->special_table, new->special * sizeof(struct cli_ac_special *));
  	    if(!newtable) {
 -		new->alt--;
 -		mpool_free(root->mempool, newalt);
 -		cli_errmsg("cli_ac_addsig: Can't realloc new->alttable\n");
 +		new->special--;
 +		mpool_free(root->mempool, newspecial);
 +		cli_errmsg("cli_ac_addsig: Can't realloc new->special_table\n");
  		error = CL_EMEM;
  		break;
  	    }
 -	    newtable[new->alt - 1] = newalt;
 -	    new->alttable = newtable;
 -
 -	    for(i = 0; i < strlen(pt); i++)
 -		if(pt[i] == '|')
 -		    newalt->num++;
 -
 -            if(!newalt->num) {
 -                error = CL_EMALFDB;
 -                break;
 -            } else
 -                newalt->num++;
 -
 -	    if(3 * newalt->num - 1 == (uint16_t) strlen(pt)) {
 -		newalt->chmode = 1;
 -		newalt->str = (unsigned char *) mpool_malloc(root->mempool, newalt->num);
 -		if(!newalt->str) {
 -		    cli_errmsg("cli_ac_addsig: Can't allocate newalt->str\n");
 -		    error = CL_EMEM;
 -		    break;
 -		}
 -	    }
 +	    newtable[new->special - 1] = newspecial;
 +	    new->special_table = newtable;
 +
 +	    if(!strcmp(pt, "B")) {
 +		newspecial->type = AC_SPECIAL_BOUNDARY;
 +	    } else if(!strcmp(pt, "L")) {
 +		newspecial->type = AC_SPECIAL_LINE_MARKER;
 +	    /*
 +	    } else if(strcmp(pt, "W")) {
 +		newspecial->type = AC_SPECIAL_WHITE;
 +	    */
 +	    } else {
 +		for(i = 0; i < strlen(pt); i++)
 +		    if(pt[i] == '|')
 +			newspecial->num++;
  
 -	    for(i = 0; i < newalt->num; i++) {
 -		if(!(h = cli_strtok(pt, i, "|"))) {
 +		if(!newspecial->num) {
  		    error = CL_EMALFDB;
  		    break;
 +		} else
 +		    newspecial->num++;
 +
 +		if(3 * newspecial->num - 1 == (uint16_t) strlen(pt)) {
 +		    newspecial->type = AC_SPECIAL_ALT_CHAR;
 +		    newspecial->str = (unsigned char *) mpool_malloc(root->mempool, newspecial->num);
 +		    if(!newspecial->str) {
 +			cli_errmsg("cli_ac_addsig: Can't allocate newspecial->str\n");
 +			error = CL_EMEM;
 +			break;
 +		    }
 +		} else {
 +		    newspecial->type = AC_SPECIAL_ALT_STR;
  		}
  
 -		if(!(c = cli_mpool_hex2str(root->mempool, h))) {
 -		    free(h);
 -		    error = CL_EMALFDB;
 -		    break;
 -		}
 +		for(i = 0; i < newspecial->num; i++) {
 +		    if(!(h = cli_strtok(pt, i, "|"))) {
 +			error = CL_EMALFDB;
 +			break;
 +		    }
  
 -		if(newalt->chmode) {
 -		    newalt->str[i] = *c;
 -		    mpool_free(root->mempool, c);
 -		} else {
 -		    if(i) {
 -			altpt = newalt;
 -			while(altpt->next)
 -			    altpt = altpt->next;
 -
 -			altpt->next = (struct cli_ac_alt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_alt));
 -			if(!altpt->next) {
 -			    cli_errmsg("cli_ac_addsig: Can't allocate altpt->next\n");
 -			    error = CL_EMEM;
 -			    free(c);
 -			    free(h);
 -			    break;
 -			}
 +		    if(!(c = cli_mpool_hex2str(root->mempool, h))) {
 +			free(h);
 +			error = CL_EMALFDB;
 +			break;
 +		    }
  
 -			altpt->next->str = (unsigned char *) c;
 -			altpt->next->len = strlen(h) / 2;
 +		    if(newspecial->type == AC_SPECIAL_ALT_CHAR) {
 +			newspecial->str[i] = *c;
 +			mpool_free(root->mempool, c);
  		    } else {
 -			newalt->str = (unsigned char *) c;
 -			newalt->len = strlen(h) / 2;
 +			if(i) {
 +			    specialpt = newspecial;
 +			    while(specialpt->next)
 +				specialpt = specialpt->next;
 +
 +			    specialpt->next = (struct cli_ac_special *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_special));
 +			    if(!specialpt->next) {
 +				cli_errmsg("cli_ac_addsig: Can't allocate specialpt->next\n");
 +				error = CL_EMEM;
 +				free(c);
 +				free(h);
 +				break;
 +			    }
 +			    specialpt->next->str = (unsigned char *) c;
 +			    specialpt->next->len = strlen(h) / 2;
 +			} else {
 +			    newspecial->str = (unsigned char *) c;
 +			    newspecial->len = strlen(h) / 2;
 +			}
  		    }
 +		    free(h);
  		}
 +		if(newspecial->type == AC_SPECIAL_ALT_CHAR)
 +		    cli_qsort(newspecial->str, newspecial->num, sizeof(unsigned char), qcompare);
  
 -		free(h);
 +		if(error)
 +		    break;
  	    }
 -
 -	    if(error)
 -		break;
  	}
  
  	if(start)
@@@ -1651,9 -1352,9 +1649,9 @@@
  	free(hexcpy);
  
  	if(error) {
 -	    if(new->alt) {
 +	    if(new->special) {
  		free(hex);
 -		mpool_ac_free_alt(root->mempool, new);
 +		mpool_ac_free_special(root->mempool, new);
  	    }
  	    mpool_free(root->mempool, new);
  	    return error;
@@@ -1662,8 -1363,8 +1660,8 @@@
  
      new->pattern = cli_mpool_hex2ui(root->mempool, hex ? hex : hexsig);
      if(new->pattern == NULL) {
 -	if(new->alt)
 -	    mpool_ac_free_alt(root->mempool, new);
 +	if(new->special)
 +	    mpool_ac_free_special(root->mempool, new);
  	mpool_free(root->mempool, new);
  	free(hex);
  	return CL_EMALFDB;
@@@ -1712,7 -1413,7 +1710,7 @@@
  
  	if(plen < root->ac_mindepth) {
  	    cli_errmsg("cli_ac_addsig: Can't find a static subpattern of length %u\n", root->ac_mindepth);
 -	    mpool_ac_free_alt(root->mempool, new);
 +	    mpool_ac_free_special(root->mempool, new);
  	    mpool_free(root->mempool, new->pattern);
  	    mpool_free(root->mempool, new);
  	    return CL_EMALFDB;
@@@ -1724,17 -1425,17 +1722,17 @@@
  	new->length -= ppos;
  
  	for(i = 0; i < new->prefix_length; i++)
 -	    if((new->prefix[i] & CLI_MATCH_WILDCARD) == CLI_MATCH_ALTERNATIVE)
 -		new->alt_pattern++;
 +	    if((new->prefix[i] & CLI_MATCH_WILDCARD) == CLI_MATCH_SPECIAL)
 +		new->special_pattern++;
      }
  
      if(new->length > root->maxpatlen)
  	root->maxpatlen = new->length;
  
 -    new->virname = cli_mpool_virname(root->mempool, (char *) virname, options & CL_DB_OFFICIAL);
 +    new->virname = cli_mpool_virname(root->mempool, virname, options & CL_DB_OFFICIAL);
      if(!new->virname) {
  	mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern);
 -	mpool_ac_free_alt(root->mempool, new);
 +	mpool_ac_free_special(root->mempool, new);
  	mpool_free(root->mempool, new);
  	return CL_EMEM;
      }
@@@ -1742,34 -1443,26 +1740,34 @@@
      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, NULL, 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_special(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_ac_free_special(root->mempool, new);
  	mpool_free(root->mempool, new);
  	return ret;
      }
  
 +    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");
 +	    return CL_EMEM;
 +	}
 +	root->ac_reloff[root->ac_reloff_num] = new;
 +	new->offset_min = root->ac_reloff_num * 2;
 +	new->offset_max = new->offset_min + 1;
 +	root->ac_reloff_num++;
 +    }
 +
      return CL_SUCCESS;
  }
diff --combined libclamav/matcher.c
index f445782,c061450..ecd925f
--- a/libclamav/matcher.c
+++ b/libclamav/matcher.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - *  Copyright (C) 2007-2008 Sourcefire, Inc.
 + *  Copyright (C) 2007-2009 Sourcefire, Inc.
   *
   *  Authors: Tomasz Kojm
   *
@@@ -44,12 -44,23 +44,28 @@@
  #include "str.h"
  #include "cltypes.h"
  #include "default.h"
 +#include "macho.h"
 +#include "fmap.h"
 +#include "pe_icons.h"
 +#include "regex/regex.h"
  
+ 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,
+ 			      cli_file_t ftype,
 -			      int desc,
+ 			      struct cli_matched_type **ftoffset,
 -			      unsigned int acmode)
++			      unsigned int acmode,
++			      fmap_t *map,
++			      struct cli_bm_off *offdata)
+ {
+     int ret;
 -    if (root->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, root, offset, ftype, desc)) != CL_VIRUS)
 -	ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, root, mdata, offset, ftype, desc, ftoffset, acmode, NULL);
++    if (root->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, map, offdata)) != CL_VIRUS)
++	ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, root, mdata, offset, ftype, ftoffset, acmode, NULL);
+     return ret;
+ }
+ 
 -int cli_scanbuff(const unsigned char *buffer, uint32_t length, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
 +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 ret = CL_CLEAN;
  	unsigned int i;
@@@ -76,11 -87,10 +92,10 @@@
  
      if(troot) {
  
 -	if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
 +	if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
  	    return ret;
  
- 	if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, NULL, troot, offset, NULL, NULL)) != CL_VIRUS)
- 	    ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL);
 -	ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), 0, ftype, -1, NULL, AC_SCAN_VIR);
++	ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL, NULL);
  
  	if(!acdata)
  	    cli_ac_freedata(&mdata);
@@@ -89,11 -99,10 +104,10 @@@
  	    return ret;
      }
  
 -    if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
 +    if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
  	return ret;
  
-     if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, NULL, groot, offset, NULL, NULL)) != CL_VIRUS)
- 	ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL);
 -    ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), 0, ftype, -1, NULL, AC_SCAN_VIR);
++    ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL, NULL);
  
      if(!acdata)
  	cli_ac_freedata(&mdata);
@@@ -101,285 -110,171 +115,285 @@@
      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, fmap_t *map, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
  {
 -	int (*einfo)(int, struct cli_exe_info *) = NULL;
 +	int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
 +	char offcpy[65];
  	unsigned int n, val;
 -	const char *pt;
 -	off_t pos, offset;
 +	char *pt;
  
 +    if(!info) { /* decode offset string */
 +	if(!offstr) {
 +	    cli_errmsg("cli_caloff: offstr == NULL\n");
 +	    return CL_ENULLARG;
 +	}
  
 -    *ret = 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;
 +	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 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)) {
 +		cli_errmsg("cli_caloff: Invalid offset value\n");
 +		return CL_EMALFDB;
 +	    }
 +	    *offset_min = offdata[1] = atoi(offcpy);
 +	    *offset_max = *offset_min + offdata[2];
  	}
 -    }
 -
 -    if((pt = strchr(offstr, ',')))
 -	*maxshift = atoi(++pt);
 -
 -    if(isdigit(offstr[0])) {
 -	return atoi(offstr);
 -
 -    } else 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(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) {
 -
 -	    if(sscanf(offstr, "SL+%u", &val) != 1) {
 -		*ret = -1;
 -		return 0;
 +	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;
  	    }
 +	}
  
 -	    offset = val + info->exeinfo.section[info->exeinfo.nsections - 1].raw;
 +    } else {
 +	/* calculate relative offsets */
 +	if(info->status == -1) {
 +	    *offset_min = CLI_OFF_NONE;
 +	    if(offset_max)
 +		*offset_max = CLI_OFF_NONE;
 +	    return CL_SUCCESS;
 +	}
  
 -	} else {
 +	if((offdata[0] == CLI_OFF_EOF_MINUS)) {
 +	    if(!info->fsize)
 +		info->fsize = map->len;
 +	} 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(einfo(map, &info->exeinfo)) {
 +		/* einfo *may* fail */
 +		info->status = -1;
 +		*offset_min = CLI_OFF_NONE;
 +		if(offset_max)
 +		    *offset_max = CLI_OFF_NONE;
 +		return CL_SUCCESS;
  	    }
 -
 -	    offset = val + info->exeinfo.section[n].raw;
 +	    info->status = 1;
  	}
  
 -	return offset;
 +	switch(offdata[0]) {
 +	    case CLI_OFF_EOF_MINUS:
 +		*offset_min = info->fsize - offdata[1];
 +		break;
 +
 +	    case CLI_OFF_EP_PLUS:
 +		*offset_min = info->exeinfo.ep + offdata[1];
 +		break;
  
 -    } else if(!strncmp(offstr, "EOF-", 4)) {
 -	    struct stat sb;
 +	    case CLI_OFF_EP_MINUS:
 +		*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_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 = CLI_OFF_NONE;
 +		else
 +		    *offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1];
 +		break;
 +	    case CLI_OFF_VERSION:
 +		*offset_min = *offset_max = CLI_OFF_ANY;
 +		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_max) {
 +	    if(*offset_min != CLI_OFF_NONE)
 +		*offset_max = *offset_min + offdata[2];
 +	    else
 +		*offset_max = CLI_OFF_NONE;
 +	}
      }
  
 -    *ret = -1;
 -    return 0;
 +    return CL_SUCCESS;
  }
  
 -static int cli_checkfp(int fd, const struct cl_engine *engine)
 +int cli_checkfp(int fd, cli_ctx *ctx)
  {
  	unsigned char *digest;
 +	char md5[33];
 +	unsigned int i;
  	const char *virname;
 +	off_t pos;
 +	struct stat sb;
 +	const struct cli_bm_patt *patt = NULL;
 +
  
 +    if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
 +	cli_errmsg("cli_checkfp(): lseek() failed\n");
 +	return 0;
 +    }
 +
 +    lseek(fd, 0, SEEK_SET);
 +
 +    if(ctx->engine->md5_fp) {
 +	if(fstat(fd, &sb) == -1) {
 +	    cli_errmsg("cli_checkfp(): fstat(%d) failed\n", fd);
 +	    lseek(fd, pos, SEEK_SET);
 +	    return 0;
 +	}
  
 -    if(engine->md5_fp) {
  	if(!(digest = cli_md5digest(fd))) {
  	    cli_errmsg("cli_checkfp(): Can't generate MD5 checksum\n");
 +	    lseek(fd, pos, SEEK_SET);
  	    return 0;
  	}
  
 -	if(cli_bm_scanbuff(digest, 16, &virname, engine->md5_fp, 0, 0, -1) == CL_VIRUS) {
 -	    cli_dbgmsg("Eliminated false positive match (fp sig: %s)\n", virname);
 +	if(cli_bm_scanbuff(digest, 16, &virname, &patt, ctx->engine->md5_fp, 0, NULL, NULL) == CL_VIRUS && patt->filesize == sb.st_size) {
 +	    cli_dbgmsg("cli_checkfp(): Found false positive detection (fp sig: %s)\n", virname);
  	    free(digest);
 +	    lseek(fd, pos, SEEK_SET);
  	    return 1;
  	}
 +
 +	for(i = 0; i < 16; i++)
 +	    sprintf(md5 + i * 2, "%02x", digest[i]);
 +	md5[32] = 0;
 +	cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) sb.st_size, *ctx->virname ? *ctx->virname : "Name");
 +
  	free(digest);
      }
  
 +    lseek(fd, pos, SEEK_SET);
      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)
 +static int matchicon(cli_ctx *ctx, const char *grp1, const char *grp2)
  {
 -	off_t offset;
 -	int ret;
 -	unsigned int maxshift = 0;
 -
 +	icon_groupset iconset;
  
 -    if(offstr && desc != -1) {
 -	offset = cli_caloff(offstr, info, desc, ftype, &ret, &maxshift);
 +    cli_icongroupset_init(&iconset);
 +    cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
 +    cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
 +    return cli_match_icon(&iconset, ctx);
 +}
  
 -	if(ret == -1) {
 -	    cli_dbgmsg("cli_validatesig: Can't calculate offset for signature %s\n", virname);
 -	    return 0;
 -	}
 +int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode)
 +{
 +    int ret = CL_EMEM;
 +    fmap_t *map = *ctx->fmap;
  
 -	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;
 -	}
 +    if((*ctx->fmap = fmap(desc, 0, 0))) {
 +	ret = cli_fmap_scandesc(ctx, ftype, ftonly, ftoffset, acmode, NULL);
 +	funmap(*ctx->fmap);
      }
 -
 -    return 1;
 +    *ctx->fmap = map;
 +    return ret;
  }
  
 -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_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, unsigned char *refhash)
  {
 - 	unsigned char *buffer, *buff, *endbl, *upt;
 + 	unsigned char *buff;
  	int ret = CL_CLEAN, type = CL_CLEAN, bytes;
 -	unsigned int i, evalcnt;
 -	uint32_t buffersize, length, maxpatlen, shift = 0, offset = 0;
 +	unsigned int i, evalcnt, bm_offmode = 0;
 +	uint32_t maxpatlen, offset = 0;
  	uint64_t evalids;
  	struct cli_ac_data gdata, tdata;
 +	struct cli_bm_off toff;
  	cli_md5_ctx md5ctx;
  	unsigned char digest[16];
  	struct cli_matcher *groot = NULL, *troot = NULL;
 -
 +	fmap_t *map = *ctx->fmap;
 +	int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
 +	struct cli_exe_info exeinfo;
  
      if(!ctx->engine) {
  	cli_errmsg("cli_scandesc: engine == NULL\n");
@@@ -410,195 -305,140 +424,195 @@@
  	    maxpatlen = groot->maxpatlen;
      }
  
 -    /* prepare the buffer */
 -    buffersize = maxpatlen + SCANBUFF;
 -    if(!(buffer = (unsigned char *) cli_calloc(buffersize, sizeof(unsigned char)))) {
 -	cli_dbgmsg("cli_scandesc(): unable to cli_calloc(%u)\n", buffersize);
 -	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_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, map)))
 +	    return ret;
  
      if(troot) {
 -	if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
 +	if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, map))) {
 +	    if(!ftonly)
 +		cli_ac_freedata(&gdata);
  	    return ret;
 +	}
 +	if(troot->bm_offmode) {
 +	    if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
 +		if((ret = cli_bm_initoff(troot, &toff, map))) {
 +		    if(!ftonly)
 +			cli_ac_freedata(&gdata);
 +		    cli_ac_freedata(&tdata);
 +		    return ret;
 +		}
 +		bm_offmode = 1;
 +	    }
 +	}
      }
  
 -    if(!ftonly && ctx->engine->md5_hdb)
 +    if(!refhash && !ftonly && ctx->engine->md5_hdb)
  	cli_md5_init(&md5ctx);
  
 -    buff = buffer;
 -    buff += maxpatlen; /* pointer to read data block */
 -    endbl = buff + SCANBUFF - maxpatlen; /* pointer to the last block
 -					  * length of maxpatlen
 -					  */
 -
 -    upt = buff;
 -    while((bytes = cli_readn(desc, buff + shift, SCANBUFF - shift)) > 0) {
 -
 +    while(offset < map->len) {
 +	bytes = MIN(map->len - offset, SCANBUFF);
 +	if(!(buff = fmap_need_off_once(map, offset, bytes)))
 +	    break;
  	if(ctx->scanned)
  	    *ctx->scanned += bytes / CL_COUNT_PRECISION;
  
 -	length = shift + bytes;
 -	if(upt == buffer)
 -	    length += maxpatlen;
 -
  	if(troot) {
- 	    if(troot->ac_only || (ret = cli_bm_scanbuff(buff, bytes, ctx->virname, NULL, troot, offset, map, bm_offmode ? &toff : NULL)) != CL_VIRUS)
- 		ret = cli_ac_scanbuff(buff, bytes, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, ftoffset, acmode, NULL);
 -	    ret = matcher_run(troot, upt, length, ctx->virname, &tdata, offset, ftype, desc, NULL, acmode);
++	    ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, ftype, ftoffset, acmode, map, bm_offmode ? &toff : NULL);
+ 
  	    if(ret == CL_VIRUS) {
  		if(!ftonly)
  		    cli_ac_freedata(&gdata);
  		cli_ac_freedata(&tdata);
 -
 -		lseek(desc, 0, SEEK_SET);
 -		if(cli_checkfp(desc, ctx->engine))
 -		    return CL_CLEAN;
 -		else
 -		    return CL_VIRUS;
 +		if(bm_offmode)
 +		    cli_bm_freeoff(&toff);
 +		return CL_VIRUS;
  	    }
  	}
  
  	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(buff, bytes, ctx->virname, NULL, groot, offset, map, NULL)) != CL_VIRUS)
 +		ret = cli_ac_scanbuff(buff, bytes, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, ftoffset, acmode, NULL);
  	    if(ret == CL_VIRUS) {
 -		free(buffer);
  		cli_ac_freedata(&gdata);
 -		if(troot)
 +		if(troot) {
  		    cli_ac_freedata(&tdata);
 -		lseek(desc, 0, SEEK_SET);
 -		if(cli_checkfp(desc, ctx->engine))
 -		    return CL_CLEAN;
 -		else
 -		    return CL_VIRUS;
 -
 +		    if(bm_offmode)
 +			cli_bm_freeoff(&toff);
 +		}
 +		return CL_VIRUS;
  	    } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
  		if(ret > type)
  		    type = ret;
  	    }
  
 -	    if(ctx->engine->md5_hdb)
 -		cli_md5_update(&md5ctx, buff + shift, bytes);
 +	    if(!refhash && ctx->engine->md5_hdb)
 +		cli_md5_update(&md5ctx, buff + maxpatlen * (offset!=0), bytes - maxpatlen * (offset!=0));
  	}
  
 -	if(bytes + shift == SCANBUFF) {
 -	    memmove(buffer, endbl, maxpatlen);
 -	    offset += SCANBUFF;
 -
 -	    if(upt == buff) {
 -		upt = buffer;
 -		offset -= maxpatlen;
 -	    }
 -
 -	    shift = 0;
 -
 -	} else {
 -	    shift += bytes;
 -	}
 +	if(bytes < SCANBUFF) break;
 +	offset += bytes - maxpatlen;
      }
  
 -    free(buffer);
 +#define LSIGEVAL(xroot, xdata) \
 +    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; \
 +	    if(xroot->ac_lsigtable[i]->tdb.filesize && (xroot->ac_lsigtable[i]->tdb.filesize[0] > map->len || xroot->ac_lsigtable[i]->tdb.filesize[1] < map->len)) \
 +		continue; \
 +	    \
 +	    if(xroot->ac_lsigtable[i]->tdb.ep || xroot->ac_lsigtable[i]->tdb.nos) { \
 +		einfo = NULL; \
 +		if(xroot->type == 1) \
 +		    einfo = cli_peheader; \
 +		else if(xroot->type == 6) \
 +		    einfo = cli_elfheader; \
 +		else if(xroot->type == 9) \
 +		    einfo = cli_machoheader; \
 +		if(!einfo) \
 +		    continue; \
 +		memset(&exeinfo, 0, sizeof(exeinfo)); \
 +		if(einfo(map, &exeinfo)) \
 +		    continue; \
 +		if(exeinfo.section) \
 +		    free(exeinfo.section); \
 +		if(xroot->ac_lsigtable[i]->tdb.ep && (xroot->ac_lsigtable[i]->tdb.ep[0] > exeinfo.ep || xroot->ac_lsigtable[i]->tdb.ep[1] < exeinfo.ep)) \
 +		    continue; \
 +		if(xroot->ac_lsigtable[i]->tdb.nos && (xroot->ac_lsigtable[i]->tdb.nos[0] > exeinfo.nsections || xroot->ac_lsigtable[i]->tdb.nos[1] < exeinfo.nsections)) \
 +		    continue; \
 +	    } \
 +	    if(xroot->ac_lsigtable[i]->tdb.icongrp1 || xroot->ac_lsigtable[i]->tdb.icongrp2) { \
 +		if(matchicon(ctx, xroot->ac_lsigtable[i]->tdb.icongrp1, xroot->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) { \
 +		    ret = CL_VIRUS; \
 +		    break; \
 +		} else { \
 +		    continue; \
 +		} \
 +	    } \
 +	    if(!xroot->ac_lsigtable[i]->bc_idx) { \
 +		if(ctx->virname) \
 +		    *ctx->virname = xroot->ac_lsigtable[i]->virname; \
 +		ret = CL_VIRUS; \
 +		break; \
 +	    } \
 +	    if(cli_bytecode_runlsig(ctx, &ctx->engine->bcs, xroot->ac_lsigtable[i]->bc_idx, ctx->virname, xdata.lsigcnt[i], xdata.lsigsuboff[i], map) == CL_VIRUS) { \
 +		ret = CL_VIRUS; \
 +		break; \
 +	    } \
 +	} \
 +    }
  
      if(troot) {
 -	for(i = 0; i < troot->ac_lsigs; i++) {
 -	    evalcnt = 0;
 -	    evalids = 0;
 -	    if(cli_ac_chklsig(troot->ac_lsigtable[i]->logic, troot->ac_lsigtable[i]->logic + strlen(troot->ac_lsigtable[i]->logic), tdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
 -		if(ctx->virname)
 -		    *ctx->virname = troot->ac_lsigtable[i]->virname;
 -		ret = CL_VIRUS;
 -		break;
 -	    }
 -	}
 +	LSIGEVAL(troot, tdata);
  	cli_ac_freedata(&tdata);
 +	if(bm_offmode)
 +	    cli_bm_freeoff(&toff);
      }
  
      if(groot) {
 -	if(ret != CL_VIRUS) for(i = 0; i < groot->ac_lsigs; i++) {
 -	    evalcnt = 0;
 -	    evalids = 0;
 -	    if(cli_ac_chklsig(groot->ac_lsigtable[i]->logic, groot->ac_lsigtable[i]->logic + strlen(groot->ac_lsigtable[i]->logic), gdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
 -		if(ctx->virname)
 -		    *ctx->virname = groot->ac_lsigtable[i]->virname;
 -		ret = CL_VIRUS;
 -		break;
 -	    }
 -	}
 +	if(ret != CL_VIRUS)
 +	    LSIGEVAL(groot, gdata);
  	cli_ac_freedata(&gdata);
      }
  
 -    if(ret == CL_VIRUS) {
 -	lseek(desc, 0, SEEK_SET);
 -	if(cli_checkfp(desc, ctx->engine))
 -	    return CL_CLEAN;
 -	else
 -	    return CL_VIRUS;
 -    }
 +    if(ret == CL_VIRUS)
 +	return CL_VIRUS;
  
      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))
 +	    const struct cli_bm_patt *patt;
 +	if(!refhash) {
 +	    cli_md5_final(digest, &md5ctx);
 +	    refhash = digest;
 +	}
 +	if(cli_bm_scanbuff(refhash, 16, ctx->virname, &patt, ctx->engine->md5_hdb, 0, NULL, NULL) == CL_VIRUS && patt->filesize == map->len && (cli_bm_scanbuff(refhash, 16, NULL, &patt, ctx->engine->md5_fp, 0, NULL, NULL) != CL_VIRUS || patt->filesize != map->len))
  	    return CL_VIRUS;
      }
  
      return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
  }
 +
 +int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, int filepos, int res1, void *res2)
 +{
 +	const struct cli_cdb *cdb;
 +
 +    if(!(cdb = ctx->engine->cdb))
 +	return CL_CLEAN;
 +
 +    do {
 +	if(cdb->ctype != CL_TYPE_ANY && cdb->ctype != ctx->container_type)
 +	    continue;
 +
 +	if(cdb->encrypted != 2 && cdb->encrypted != encrypted)
 +	    continue;
 +
 +	if(cdb->res1 && (cdb->ctype == CL_TYPE_ZIP || cdb->ctype == CL_TYPE_RAR) && cdb->res1 != res1)
 +	    continue;
 +
 +#define CDBRANGE(field, val)						    \
 +	if(field[0] != CLI_OFF_ANY) {					    \
 +	    if(field[0] == field[1] && field[0] != val)			    \
 +		continue;						    \
 +	    else if(field[0] != field[1] && ((field[0] && field[0] > val) ||\
 +	      (field[1] && field[1] < val)))				    \
 +		continue;						    \
 +	}
 +
 +	CDBRANGE(cdb->csize, ctx->container_size);
 +	CDBRANGE(cdb->fsizec, fsizec);
 +	CDBRANGE(cdb->fsizer, fsizer);
 +	CDBRANGE(cdb->filepos, filepos);
 +
 +	if(cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
 +	    continue;
 +
 +	*ctx->virname = cdb->virname;
 +	return CL_VIRUS;
 +
 +    } while((cdb = cdb->next));
 +
 +    return CL_CLEAN;
 +}

-- 
Debian repository for ClamAV



More information about the Pkg-clamav-commits mailing list