diff --git a/libclamav/autoit.c b/libclamav/autoit.c index a62b8beab..81f9d1ac4 100644 --- a/libclamav/autoit.c +++ b/libclamav/autoit.c @@ -181,7 +181,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) { uint8_t b[300], comp; uint8_t *buf = b; uint32_t s, m4sum=0; - int i; + int i, ret; unsigned int files=0; char tempfile[1024]; struct UNP UNP; @@ -192,7 +192,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) { for (i=0; i<16; i++) m4sum += buf[i]; - while(!ctx->limits || !ctx->limits->maxfiles || files < ctx->limits->maxfiles) { + while((ret=cli_checklimits("autoit", ctx, 0, 0, 0))==CL_CONTINUE) { buf = b; if (cli_readn(desc, buf, 8)!=8) return CL_CLEAN; @@ -250,8 +250,9 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) { cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x45aa); cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xc3d2); - if(ctx->limits && ctx->limits->maxfilesize && UNP.csize > ctx->limits->maxfilesize) { - cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize); + + if((ret=cli_checklimits("autoit", ctx, UNP.csize, 0, 0))!=CL_CONTINUE) { + if(ret==CL_VIRUS) return ret; lseek(desc, UNP.csize, SEEK_CUR); continue; } @@ -275,9 +276,9 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) { if(!(UNP.usize = be32_to_host(*(uint32_t *)(buf+4)))) UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */ - if(ctx->limits && ctx->limits->maxfilesize && UNP.usize > ctx->limits->maxfilesize) { - cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize); + if((ret=cli_checklimits("autoit", ctx, UNP.usize, 0, 0))!=CL_CONTINUE) { free(buf); + if(ret==CL_VIRUS) return ret; continue; } @@ -382,8 +383,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) { close(i); if(!cli_leavetemps_flag) unlink(tempfile); } - cli_dbgmsg("autoit: files limit reached (max: %u)\n", ctx->limits->maxfiles); - return CL_EMAXFILES; + return ret; } @@ -478,7 +478,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) { uint8_t b[600], comp, script; uint8_t *buf; uint32_t s; - int i; + int i, ret; unsigned int files=0; char tempfile[1024]; const char prefixes[] = { '\0', '\0', '@', '$', '\0', '.', '"', '#' }; @@ -492,7 +492,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) { /* buf+=0x10; */ lseek(desc, 16, SEEK_CUR); /* for now we just skip the garbage */ - while(!ctx->limits || !ctx->limits->maxfiles || files < ctx->limits->maxfiles) { + while((ret=cli_checklimits("cli_autoit", ctx, 0, 0, 0))==CL_CONTINUE) { buf = b; if (cli_readn(desc, buf, 8)!=8) return CL_CLEAN; @@ -555,8 +555,8 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) { cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x87bc); cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xa685); - if(ctx->limits && ctx->limits->maxfilesize && UNP.csize > ctx->limits->maxfilesize) { - cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize); + if((ret=cli_checklimits("autoit", ctx, UNP.csize, 0, 0))!=CL_CONTINUE) { + if(ret==CL_VIRUS) return ret; lseek(desc, UNP.csize, SEEK_CUR); continue; } @@ -581,8 +581,9 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) { if(!(UNP.usize = be32_to_host(*(uint32_t *)(buf+4)))) UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */ - if(ctx->limits && ctx->limits->maxfilesize && UNP.usize > ctx->limits->maxfilesize) { + if((ret=cli_checklimits("autoit", ctx, UNP.usize, 0, 0))!=CL_CONTINUE) { free(buf); + if(ret==CL_VIRUS) return ret; continue; } if (!(UNP.outputbuf = cli_malloc(UNP.usize))) { @@ -893,8 +894,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) { close(i); if(!cli_leavetemps_flag) unlink(tempfile); } - cli_dbgmsg("autoit: Files limit reached (max: %u)\n", ctx->limits->maxfiles); - return CL_EMAXFILES; + return ret; } #endif /* FPU_WORDS_BIGENDIAN */ diff --git a/libclamav/msexpand.c b/libclamav/msexpand.c index a1e3e8dad..ba638d5e8 100644 --- a/libclamav/msexpand.c +++ b/libclamav/msexpand.c @@ -108,13 +108,9 @@ int cli_msexpand(int fd, int ofd, cli_ctx *ctx) cli_dbgmsg("MSEXPAND: File size from header: %u\n", hdr.fsize); - if(ctx->limits && ctx->limits->maxfilesize && (hdr.fsize > ctx->limits->maxfilesize)) { - cli_dbgmsg("MSEXPAND: Size exceeded (%u, max: %lu)\n", hdr.fsize, ctx->limits->maxfilesize); - if(BLOCKMAX) { - *ctx->virname = "MSEXPAND.ExceededFileSize"; - return CL_VIRUS; - } - hdr.fsize = ctx->limits->maxfilesize; + if((ret=cli_checklimits("MSEXPAND", ctx, hdr.fsize, 0, 0))!=CL_CONTINUE) { + if(ret==CL_VIRUS) return ret; + hdr.fsize = (ctx->limits->maxfilesize > ctx->limits->maxscansize-ctx->scansize) ? ctx->limits->maxscansize-ctx->scansize : ctx->limits->maxfilesize; cli_dbgmsg("MSEXPAND: Only extracting first %u bytes\n", hdr.fsize); /* may extract up to 2kB more */ } diff --git a/libclamav/others.c b/libclamav/others.c index 2e8da5d04..55eec6e86 100644 --- a/libclamav/others.c +++ b/libclamav/others.c @@ -196,63 +196,65 @@ const char *cl_strerror(int clerror) } } -int cli_sizelimits(cli_ctx *ctx, unsigned long need1, unsigned long need2, unsigned long need3) { - int ret = CL_SUCCESS; - unsigned long needed; - - /* if called without limits, go on, unpack, scan */ - if(!ctx || !ctx->limits) return CL_SUCCESS; - - needed = (need1>need2)?need1:need2; - needed = (needed>need3)?needed:need3; - - /* if we have global scan limits */ - if(ctx->limits->maxscansize) { - /* if the remaining scansize is too small... */ - if(ctx->limits->maxscansize-ctx->scansizelimits->maxscansize, ctx->scansize, needed); - /* ... we return INFECTED only upon request */ - if(BLOCKMAX) { - *ctx->virname = "Archive.ExceededScanSize"; - return CL_VIRUS; - } - /* ... otherwise we tell the caller to skip this file */ - ret = CL_BREAK; - } else { - /* if the remaining scanzise is big enough, we update it */ - ctx->scansize+=needed; +int cli_checklimits(const char *who, cli_ctx *ctx, unsigned long need1, unsigned long need2, unsigned long need3) { + int ret = CL_SUCCESS; + unsigned long needed; + + /* if called without limits, go on, unpack, scan */ + if(!ctx || !ctx->limits) return CL_SUCCESS; + + /* check if we have limits on the number of files */ + /* FIMMELIMITS: this only makes sense in updatelimits */ + if(ctx->limits->maxfiles && ctx->scanned>=ctx->limits->maxfiles) { + cli_dbgmsg("%s: files limit reached (max: %u)\n", who, ctx->maxfiles); + return CL_EMAXFILES; } - } - - /* if we have per-file size limits, and we are overlimit... */ - if(ctx->limits->maxfilesize && ctx->limits->maxfilesizevirname = "Archive.ExceededFileSize"; - return CL_VIRUS; + + needed = (need1>need2)?need1:need2; + needed = (needed>need3)?needed:need3; + + /* if we have global scan limits */ + if(ctx->limits->maxscansize) { + /* if the remaining scansize is too small... */ + if(ctx->limits->maxscansize-ctx->scansizelimits->maxscansize, ctx->scansize, needed); + /* ... we return INFECTED only upon request */ + if(BLOCKMAX) { + *ctx->virname = "Archive.ExceededScanSize"; + return CL_VIRUS; + } + /* ... otherwise we tell the caller to skip this file */ + ret = CL_EMAXSIZE; + } } - /* ... otherwise we tell the caller to skip this file */ - ret = CL_BREAK; - } - return ret; + /* if we have per-file size limits, and we are overlimit... */ + if(ctx->limits->maxfilesize && ctx->limits->maxfilesizelimits->maxfilesize, needed); + /* ... we return INFECTED only upon request */ + if(BLOCKMAX) { + *ctx->virname = "Archive.ExceededFileSize"; + return CL_VIRUS; + } + /* ... otherwise we tell the caller to skip this file */ + ret = CL_EMAXSIZE; + } + return ret; } -int cli_filelimits(cli_ctx *ctx) { - /* FIXME: inline in magic_scandesc? */ +int cli_updatelimits(cli_ctx *ctx, unsigned long need) { + int ret; - /* if called without limits, go on, unpack, scan */ - if(!ctx || !ctx->limits || !ctx->limits->maxfiles) return CL_SUCCESS; + if((ret=cli_checklimits(ctx, need, 0, 0))==CL_SUCCESS) { + /* update counter */ + ctx->scanned++; + /* update the remaining scanzise */ + ctx->scansize+=needed; + if(ctx->scansize > ctx->limits->maxscansize) + ctx->scansize = ctx->limits->maxscansize; + } - /* if we are within the limit */ - if(ctx->limits->maxfiles > ctx->scanned) { - /* update counters and ack */ - ctx->scanned++; - return CL_SUCCESS; - } else { - /* else tell the caller to quit */ - return CL_BREAK; - } + return ret; } unsigned char *cli_md5digest(int desc) diff --git a/libclamav/others.h b/libclamav/others.h index 12d927f33..da5ac16b2 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -231,5 +231,7 @@ bitset_t *cli_bitset_init(void); void cli_bitset_free(bitset_t *bs); int cli_bitset_set(bitset_t *bs, unsigned long bit_offset); int cli_bitset_test(bitset_t *bs, unsigned long bit_offset); +int cli_checklimits(const char *, cli_ctx *, unsigned long, unsigned long, unsigned long); +int cli_updatelimits(cli_ctx *, unsigned long); #endif diff --git a/libclamav/pdf.c b/libclamav/pdf.c index 30ace38e1..7a92185c8 100644 --- a/libclamav/pdf.c +++ b/libclamav/pdf.c @@ -79,10 +79,9 @@ cli_pdf(const char *dir, int desc, const cli_ctx *ctx) char *buf; /* start of memory mapped area */ const char *p, *q, *trailerstart; const char *xrefstart; /* cross reference table */ - const struct cl_limits *limits; /*size_t xreflength;*/ table_t *md5table; - int printed_predictor_message, printed_embedded_font_message, rc; + int printed_predictor_message, printed_embedded_font_message, rc, ret; unsigned int files; struct stat statb; @@ -192,7 +191,6 @@ cli_pdf(const char *dir, int desc, const cli_ctx *ctx) rc = CL_CLEAN; files = 0; - limits = ctx->limits; /* * The body section consists of a sequence of indirect objects @@ -494,10 +492,10 @@ cli_pdf(const char *dir, int desc, const cli_ctx *ctx) free(md5digest); cli_dbgmsg("cli_pdf: extracted file %u to %s\n", ++files, fullname); - if(limits && limits->maxfiles && (files >= limits->maxfiles)) { + + if((ret=cli_checklimits("cli_pdf", ctx, 0, 0, 0))!=CL_CONTINUE) { /* Bug 698 */ - cli_dbgmsg("cli_pdf: number of files exceeded %u\n", limits->maxfiles); - rc = CL_EMAXFILES; + rc = ret; } } @@ -541,7 +539,7 @@ try_flatedecode(unsigned char *buf, off_t real_len, off_t calculated_len, int fo static int flatedecode(unsigned char *buf, off_t len, int fout, const cli_ctx *ctx) { - int zstat; + int zstat, ret; off_t nbytes; z_stream stream; unsigned char output[BUFSIZ]; @@ -611,17 +609,9 @@ flatedecode(unsigned char *buf, off_t len, int fout, const cli_ctx *ctx) } nbytes += written; - if(ctx->limits && - ctx->limits->maxfilesize && - (nbytes > (off_t) ctx->limits->maxfilesize)) { - cli_dbgmsg("cli_pdf: flatedecode size exceeded (%lu > %lu)\n", - (unsigned long)nbytes, (unsigned long)ctx->limits->maxfilesize); + if((ret=cli_checklimits("cli_pdf", ctx, nbytes, 0, 0))!=CL_CONTINUE) { inflateEnd(&stream); - if(BLOCKMAX) { - *ctx->virname = "PDF.ExceededFileSize"; - return CL_VIRUS; - } - return CL_CLEAN; + return ret; } stream.next_out = output; stream.avail_out = sizeof(output); @@ -651,28 +641,6 @@ flatedecode(unsigned char *buf, off_t len, int fout, const cli_ctx *ctx) } } - - /* - * On BSD systems total_in and total_out are "long long", so these - * numbers could (in theory) get truncated in the debug statement - */ - cli_dbgmsg("cli_pdf: flatedecode in=%lu out=%lu ratio %lu (max %u)\n", - (unsigned long)stream.total_in, (unsigned long)stream.total_out, - (unsigned long)(stream.total_out / stream.total_in), - ctx->limits ? ctx->limits->maxratio : 0); - - if(ctx->limits && - ctx->limits->maxratio && - ((stream.total_out / stream.total_in) > ctx->limits->maxratio)) { - cli_dbgmsg("cli_pdf: flatedecode Max ratio reached\n"); - inflateEnd(&stream); - if(BLOCKMAX) { - *ctx->virname = "Oversized.PDF"; - return CL_VIRUS; - } - return CL_CLEAN; - } - #ifdef SAVE_TMP unlink(tmpfilename); #endif