diff --git a/ChangeLog b/ChangeLog index c73319eb5..ea018f75d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ Wed Jul 15 12:20:04 CEST 2009 (tk) ---------------------------------- * clamd, clamav-milter: make pid files globally readable (bb#1642) +Wed Jul 15 12:33:22 CEST 2009 (acab) +------------------------------------ + * libclamav/ishield.c: use mmap for big files, fix some leaks, + some portability fixes + Wed Jul 15 11:20:56 CEST 2009 (tk) ---------------------------------- * libclamav/filetypes.c: fix off-by-one error (bb#1639) diff --git a/libclamav/ishield.c b/libclamav/ishield.c index 64aa1878a..5b5848a3b 100644 --- a/libclamav/ishield.c +++ b/libclamav/ishield.c @@ -32,7 +32,15 @@ #ifdef HAVE_UNISTD_H #include #endif +#if HAVE_MMAP +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#endif /* HAVE_MMAP */ +#if HAVE_STRING_H #include +#endif +#include #include #include @@ -45,6 +53,10 @@ #define O_BINARY 0 #endif +#ifndef LONG_MAX +#define LONG_MAX ((-1UL)>>1) +#endif + #ifndef HAVE_ATTRIB_PACKED #define __attribute__(x) #endif @@ -463,12 +475,20 @@ struct IS_HDR { }; +#define IS_FREE_HDR if(map) munmap(map, mp_hdrsz); else free(hdr); +#if HAVE_MMAP +#define IS_MAX_NOMAP_SZ 0x100000 +#else +#define IS_MAX_NOMAP_SZ CLI_MAX_ALLOCATION +#endif + /* Process data1.hdr and extracts all the available files from dataX.cab */ static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { uint32_t h1_data_off, objs_files_cnt, objs_dirs_off; unsigned int off, i, scanned = 0; int ret = CL_BREAK; - char hash[33], *hdr; + char hash[33], *hdr, *map = NULL; + size_t mp_hdrsz; struct IS_HDR *h1; struct IS_OBJECTS *objs; @@ -479,26 +499,41 @@ static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { return CL_CLEAN; } - if(!(hdr = (char *)cli_malloc(c->hdrsz))) /* FIXMEISHIELD: mmap if large */ - return CL_EMEM; - - if(pread(desc, hdr, c->hdrsz, c->hdr) < (ssize_t)c->hdrsz) { - cli_errmsg("is_parse_hdr: short read for header\n"); - free(hdr); - return CL_EREAD; /* hdr must be within bounds, it's k to hard fail here */ + if(c->hdrsz < IS_MAX_NOMAP_SZ) { + if(!(hdr = (char *)cli_malloc(c->hdrsz))) + return CL_EMEM; + if(pread(desc, hdr, c->hdrsz, c->hdr) < (ssize_t)c->hdrsz) { + cli_errmsg("is_parse_hdr: short read for header\n"); + free(hdr); + return CL_EREAD; /* hdr must be within bounds, it's k to hard fail here */ + } + } else { +#if HAVE_MMAP + int psz = getpagesize(); + off_t mp_hdr = (c->hdr / psz) * psz; + mp_hdrsz = c->hdrsz + c->hdr - mp_hdr; + if((map = mmap(NULL, mp_hdrsz, PROT_READ, MAP_PRIVATE, desc, mp_hdr))==MAP_FAILED) { + cli_errmsg("is_parse_hdr: mmap failed\n"); + return CL_EMEM; + } + hdr = map + c->hdr - mp_hdr; +#else + cli_warnmsg("is_parse_hdr: hdr too big and mmap unavailable\n"); + return CL_CLEAN +#endif } h1 = (struct IS_HDR *)hdr; if(!CLI_ISCONTAINED(hdr, c->hdrsz, ((char *)h1), sizeof(*h1))) { cli_dbgmsg("is_parse_hdr: not enough room for H1\n"); - free(hdr); + IS_FREE_HDR; return CL_CLEAN; } h1_data_off = le32_to_host(h1->data_off); objs = (struct IS_OBJECTS *)(hdr + h1_data_off); if(!CLI_ISCONTAINED(hdr, c->hdrsz, ((char *)objs), sizeof(*objs))) { cli_dbgmsg("is_parse_hdr: not enough room for OBJECTS\n"); - free(hdr); + IS_FREE_HDR; return CL_CLEAN; } @@ -506,6 +541,7 @@ static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { h1->magic, h1->unk1, h1->unk2, h1_data_off, h1->data_sz); if(le32_to_host(h1->magic) != 0x28635349) { cli_dbgmsg("is_parse_hdr: bad magic. wrong version?\n"); + IS_FREE_HDR; return CL_CLEAN; } @@ -602,6 +638,7 @@ static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { scanned++; if (ctx->engine->maxfiles && scanned >= ctx->engine->maxfiles) { cli_dbgmsg("is_parse_hdr: File limit reached (max: %u)\n", ctx->engine->maxfiles); + IS_FREE_HDR; return CL_EMAXFILES; } cabret = is_extract_cab(desc, ctx, file_stream_off + c->cabs[j].off, file_size, file_csize); @@ -635,7 +672,7 @@ static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { } off += sizeof(*file); } - free(hdr); + IS_FREE_HDR; return ret; } @@ -687,10 +724,17 @@ static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, u fclose(in); return CL_EMEM; } - if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) return CL_EMEM; + if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) { + free(inbuf); + free(outbuf); + fclose(in); + return CL_EMEM; + } if((ofd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { cli_errmsg("is_extract_cab: failed to create file %s\n", tempfile); free(tempfile); + free(inbuf); + free(outbuf); fclose(in); return CL_ECREAT; } @@ -754,6 +798,8 @@ static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, u if(!success) break; } fclose(in); + free(inbuf); + free(outbuf); if(success) { if (outsz != size) cli_dbgmsg("is_extract_cab: extracted %llu bytes to %s, expected %llu, scanning anyway.\n", outsz, tempfile, size);