unzip/implode support

git-svn: trunk@3476
remotes/push_mirror/metadata
aCaB 18 years ago
parent bc978636ac
commit f8be651b43
  1. 5
      ChangeLog
  2. 4
      libclamav/Makefile.am
  3. 7
      libclamav/Makefile.in
  4. 315
      libclamav/explode.c
  5. 73
      libclamav/explode.h
  6. 50
      libclamav/unzip.c

@ -1,3 +1,8 @@
Tue Jan 1 23:30:06 CET 2008 (acab)
-----------------------------------
* libclamav/unzip: add support for zip method 6 (implode) - bb#584
fix for zip method 12 (bzip2)
Mon Dec 31 14:08:40 EET 2007 (edwin)
------------------------------------
* configure*: add support for version scripts when using Sun's ld on Solaris.

@ -180,7 +180,9 @@ libclamav_la_SOURCES = \
dconf.c \
dconf.h \
lzma_iface.c \
lzma_iface.h
lzma_iface.h \
explode.c \
explode.h
libclamav_internal_utils_la_SOURCES=str.c \
str.h \

@ -88,7 +88,7 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
pdf.lo spin.lo yc.lo elf.lo sis.lo uuencode.lo pst.lo \
phishcheck.lo phish_domaincheck_db.lo phish_whitelist.lo \
regex_list.lo mspack.lo cab.lo entconv.lo hashtab.lo dconf.lo \
lzma_iface.lo
lzma_iface.lo explode.lo
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
libclamav_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@ -410,7 +410,9 @@ libclamav_la_SOURCES = \
dconf.c \
dconf.h \
lzma_iface.c \
lzma_iface.h
lzma_iface.h \
explode.c \
explode.h
libclamav_internal_utils_la_SOURCES = str.c \
str.h \
@ -515,6 +517,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsig.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entconv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/explode.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsg.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashtab.Plo@am__quote@

@ -0,0 +1,315 @@
/*
* Copyright (C) 2007 Sourcefire Inc.
* Author: aCaB <acab@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
/*
* Written from scratch based on specs from PKWARE:
* see www.pkware.com/documents/casestudies/APPNOTE.TXT
*
* To the best of my knowledge, it's patent free:
* http://www.unisys.com/about__unisys/lzw
*/
/* To Cami and Dario, the only laywers I can stand */
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#include "explode.h"
/* NOTE: sorting algo must be stable! */
static void bs(uint8_t *k, uint8_t *v, unsigned int elements) {
uint8_t tmp;
unsigned int i=0, l=0, stop=0, r=elements;
while(!stop) {
stop=1;
for(; i<r; i++) {
if(v[k[i]]>v[k[i+1]]) {
tmp=k[i];
k[i]=k[i+1];
k[i+1]=tmp;
stop=0;
}
}
if(stop) break;
r--;
i--;
for(; i>l; i--) {
if(v[k[i]]<v[k[i-1]]) {
tmp=k[i];
k[i]=k[i-1];
k[i-1]=tmp;
stop=0;
}
}
l++;
i++;
}
}
static int unpack_tree(struct xplstate *X, uint32_t *tree, unsigned int expected) {
uint8_t temptree[256], order[256], *ttree=temptree;
uint8_t *cur=X->window;
uint8_t packsz;
unsigned int i;
uint16_t code=0, codeinc=0, lastlen=0;
packsz=*cur++;
for(i=0; i<expected; i++) order[i]=i;
i=expected;
do {
uint8_t values, len;
values = *cur++;
len = (values&15) + 1;
values = (values>>4) + 1;
if(values>i) return 1;
i-=values;
while(values--)
*ttree++ = len;
} while(packsz--);
if(i) return 1;
bs(order, temptree, expected-1);
i=expected-1;
do {
code=code+codeinc;
if(temptree[order[i]]!=lastlen) {
lastlen=temptree[order[i]];
codeinc=1<<(16-lastlen);
}
tree[order[i]]=code | ((uint32_t)lastlen<<16);
} while(i--);
return 0;
}
/* bit lame of a lookup, but prolly not worth optimizing */
static int lookup_tree(uint32_t *tree, unsigned int size, uint16_t code, uint8_t len) {
uint32_t lookup=((uint32_t)(len+1))<<16 | code;
unsigned int i;
for(i=0; i<size; i++)
if(tree[i]==lookup) return i;
return -1;
}
int explode_init(struct xplstate *X, uint8_t flags) {
X->bits = X->cur = 0;
if(flags&2) {
X->largewin = 1;
X->mask = 0x1fff;
} else {
X->largewin = 0;
X->mask = 0xfff;
}
if(flags&4) {
X->state = GRABLITS;
X->litcodes = 1;
X->minlen=3;
} else {
X->state = GRABLENS;
X->litcodes = 0;
X->minlen=2;
}
X->got=0;
return EXPLODE_OK;
}
#define GETBIT \
if(X->bits) { \
X->bits--; \
val=X->bitmap&1; \
X->bitmap>>=1; \
} else { \
if(!X->avail_in) return EXPLODE_EBUFF; \
if(X->avail_in>=4) { \
X->bitmap=*(uint32_t *)X->next_in; \
X->bits=31; \
X->next_in+=4; \
X->avail_in-=4; \
} else { \
X->bitmap=*X->next_in; \
X->bits=7; \
X->next_in++; \
X->avail_in--; \
} \
val=X->bitmap&1; \
X->bitmap>>=1; \
}
#define GETBITS(NUM) \
if(X->bits>=(NUM)) { \
val=X->bitmap&((1<<(NUM))-1); \
X->bitmap>>=(NUM); \
X->bits-=(NUM); \
} else { \
if(X->avail_in*8+X->bits<(NUM)) return EXPLODE_EBUFF; \
val=X->bitmap; \
if(X->avail_in>=4) { \
X->bitmap=*(uint32_t *)X->next_in; \
X->next_in+=4; \
X->avail_in-=4; \
val|=(X->bitmap&((1<<((NUM)-X->bits))-1))<<X->bits; \
X->bitmap>>=(NUM)-X->bits; \
X->bits=32-((NUM)-X->bits); \
} else { \
X->bitmap=*X->next_in; \
X->next_in++; \
X->avail_in--; \
val|=(X->bitmap&((1<<((NUM)-X->bits))-1))<<X->bits; \
X->bitmap>>=(NUM)-X->bits; \
X->bits=8-((NUM)-X->bits); \
} \
}
#define GETCODES(CASE, WHICH, HOWMANY) \
case CASE: { \
if(!X->avail_in) return EXPLODE_EBUFF; \
if(!X->got) need = *X->next_in; \
else need = X->window[0]; \
if(need > HOWMANY - 1) return EXPLODE_ESTREAM; /* too many codes */ \
need = need + 2 - X->got; /* bytes remaining */ \
if(need>X->avail_in) { /* if not enuff */ \
/* just copy what's avail... */ \
memcpy(&X->window[X->got], X->next_in, X->avail_in); \
X->got += X->avail_in; \
X->next_in += X->avail_in; \
X->avail_in = 0; \
return EXPLODE_EBUFF; /* ...and beg for more */ \
} \
/* else fetch what's needed */ \
memcpy(&X->window[X->got], X->next_in, need); \
X->avail_in -= need; \
X->next_in += need; \
if(unpack_tree(X, X->WHICH, HOWMANY )) return EXPLODE_ESTREAM; \
/* and move on */ \
X->got=0; \
X->state++; \
}
#define SETCASE(CASE) \
X->state = (CASE); \
case(CASE): \
{/* FAKE */}
int explode(struct xplstate *X) {
unsigned int val, need;
int temp;
switch(X->state) {
/* grab compressed coded literals, if present */
GETCODES(GRABLITS, lit_tree, 256);
/* grab compressed coded lens */
GETCODES(GRABLENS, len_tree, 64);
/* grab compressed coded dists */
GETCODES(GRABDISTS, dist_tree, 64);
case EXPLODE:
while(X->avail_in || X->bits) {
GETBIT; /* can't fail */
if(val) {
if(X->litcodes) {
X->backsize=0;
X->state=EXPLODE_LITCODES;
for(X->got=0; X->got<=15; X->got++) {
case EXPLODE_LITCODES:
GETBIT;
X->backsize|=val<<(15-X->got);
if((temp=lookup_tree(X->lit_tree, 256, X->backsize, X->got))!=-1) break;
}
if(temp==-1) return EXPLODE_ESTREAM;
X->got=temp;
} else {
SETCASE(EXPLODE_LITS);
GETBITS(8);
X->got=val;
}
SETCASE(EXPLODE_WBYTE);
if(!X->avail_out) return EXPLODE_EBUFF;
X->avail_out--;
*X->next_out = X->window[X->cur & X->mask] = X->got;
X->cur++;
X->next_out++;
} else {
SETCASE(EXPLODE_BASEDIST);
GETBITS(6+X->largewin);
X->backbytes=val;
X->backsize=0;
X->state=EXPLODE_DECODEDISTS;
for(X->got=0; X->got<=15; X->got++) {
case EXPLODE_DECODEDISTS:
GETBIT;
X->backsize|=val<<(15-X->got);
if((temp=lookup_tree(X->dist_tree, 64, X->backsize, X->got))!=-1) break;
}
if(temp==-1) return EXPLODE_ESTREAM;
X->backbytes|=temp<<(6+X->largewin);
X->backbytes++;
X->backsize=0;
X->state=EXPLODE_DECODELENS;
for(X->got=0; X->got<=15; X->got++) {
case EXPLODE_DECODELENS:
GETBIT;
X->backsize|=val<<(15-X->got);
if((temp=lookup_tree(X->len_tree, 64, X->backsize, X->got))!=-1) break;
}
if(temp==-1) {
cli_dbgmsg("HERE3\n");
return EXPLODE_ESTREAM;
}
if(temp==63) {
SETCASE(EXPLODE_DECODEEXTRA);
GETBITS(8);
temp=63+val;
}
X->backsize=temp+X->minlen;
X->state=EXPLODE_BACKCOPY;
while(X->backsize--) {
case EXPLODE_BACKCOPY:
if(!X->avail_out) return EXPLODE_EBUFF;
X->avail_out--;
if (X->cur>=X->backbytes)
*X->next_out = X->window[X->cur & X->mask] = X->window[(X->cur-X->backbytes) & X->mask];
else
*X->next_out = X->window[X->cur & X->mask] = 0;
X->cur++;
X->next_out++;
}
}
X->state=EXPLODE;
}
}
return EXPLODE_EBUFF;
}
void explode_shutdown() {};

@ -0,0 +1,73 @@
/*
* Copyright (C) 2007 Sourcefire Inc.
* Author: aCaB <acab@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#ifndef __EXPLODE_H
#define __EXPLODE_H
#include "cltypes.h"
enum {
EXPLODE_EBUFF,
EXPLODE_ESTREAM
};
#define EXPLODE_OK EXPLODE_EBUFF
enum XPL_STATE {
GRABLITS,
GRABLENS,
GRABDISTS,
EXPLODE,
EXPLODE_LITCODES,
EXPLODE_LITS,
EXPLODE_BASEDIST,
EXPLODE_DECODEDISTS,
EXPLODE_DECODELENS,
EXPLODE_DECODEEXTRA,
EXPLODE_WBYTE,
EXPLODE_BACKCOPY
};
struct xplstate {
uint8_t *next_in;
uint8_t *next_out;
unsigned int got;
unsigned int minlen;
unsigned int mask;
unsigned int cur;
uint32_t lit_tree[256];
uint32_t len_tree[64];
uint32_t dist_tree[64];
uint32_t bitmap;
uint32_t avail_in;
uint32_t avail_out;
uint16_t backbytes;
uint16_t backsize;
uint8_t window[8192];
uint8_t bits;
uint8_t largewin;
uint8_t litcodes;
enum XPL_STATE state;
};
int explode_init(struct xplstate *, uint8_t);
int explode(struct xplstate *);
void explode_shutdown();
#endif /* __EXPLODE_H */

@ -45,6 +45,7 @@
#include <bzlib.h>
#endif
#include "explode.h"
#include "others.h"
#include "clamav.h"
#include "scanners.h"
@ -62,7 +63,7 @@ static int wrap_inflateinit2(void *a, int b) {
return inflateInit2(a, b);
}
static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, unsigned int *fu, cli_ctx *ctx, char *tmpd) {
static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, uint16_t flags, unsigned int *fu, cli_ctx *ctx, char *tmpd) {
char name[1024], obuf[BUFSIZ];
char *tempfile = name;
int of, ret=CL_CLEAN;
@ -84,7 +85,7 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, un
if(csize<usize) {
unsigned int fake = *fu + 1;
cli_dbgmsg("cli_unzip: attempting to inflate stored file with inconsistent size\n");
if ((ret=unz(src, csize, usize, ALG_DEFLATE, &fake, ctx, tmpd))==CL_CLEAN) {
if ((ret=unz(src, csize, usize, ALG_DEFLATE, 0, &fake, ctx, tmpd))==CL_CLEAN) {
(*fu)++;
res=fake-(*fu);
}
@ -206,7 +207,7 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, un
break;
}
cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->limits->maxfilesize);
res = Z_STREAM_END;
res = BZ_STREAM_END;
break;
}
if(cli_writen(of, obuf, sizeof(obuf)-strm.avail_out) != (int)(sizeof(obuf)-strm.avail_out)) {
@ -216,6 +217,7 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, un
}
strm.next_out = obuf;
strm.avail_out = sizeof(obuf);
continue;
}
break;
}
@ -227,6 +229,45 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, un
}
#endif /* HAVE_BZLIB_H */
case ALG_IMPLODE: {
struct xplstate strm;
strm.next_in = (char *)src;
strm.next_out = obuf;
strm.avail_in = csize;
strm.avail_out = sizeof(obuf);
if (explode_init(&strm, flags)!=EXPLODE_OK) {
cli_dbgmsg("cli_unzip: explode_init() failed\n");
break;
}
while((res = explode(&strm))==EXPLODE_OK) {
if(strm.avail_out!=sizeof(obuf)) {
written+=sizeof(obuf)-strm.avail_out;
if(ctx->limits && ctx->limits->maxfilesize && written > ctx->limits->maxfilesize) {
if(BLOCKMAX) {
*ctx->virname = "Zip.ExceededFileSize";
ret = CL_VIRUS;
break;
}
cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->limits->maxfilesize);
res = 0;
break;
}
if(cli_writen(of, obuf, sizeof(obuf)-strm.avail_out) != (int)(sizeof(obuf)-strm.avail_out)) {
cli_warnmsg("cli_unzip: falied to write %lu exploded bytes\n", sizeof(obuf)-strm.avail_out);
ret = CL_EIO;
res=1;
}
strm.next_out = obuf;
strm.avail_out = sizeof(obuf);
continue;
}
break;
}
break;
}
case ALG_LZMA:
/* easy but there's not a single sample in the zoo */
@ -238,7 +279,6 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, un
case ALG_REDUCE2:
case ALG_REDUCE3:
case ALG_REDUCE4:
case ALG_IMPLODE:
case ALG_TOKENZD:
case ALG_OLDTERSE:
case ALG_RSVD1:
@ -365,7 +405,7 @@ static unsigned int lhdr(uint8_t *zip, uint32_t zsize, unsigned int *fu, unsigne
*ctx->virname = "Oversized.Zip";
*ret = CL_VIRUS;
return 0;
} else *ret = unz(zip, csize, usize, LH_method, fu, ctx, tmpd);
} else *ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd);
zip+=csize;
zsize-=csize;
}

Loading…
Cancel
Save