[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b
aCaB
acab at clamav.net
Sun Apr 4 01:04:57 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit bad8ee8efda5a30d8dbbd8d14a68fb6f6e6fd3c5
Merge: c12fe59e2d2e0d5c954d036cab5847b363be30c1 e78b518630ca9fa1f40522136b3cdc5a27321f5e
Author: aCaB <acab at clamav.net>
Date: Thu Sep 17 18:30:03 2009 +0200
merge master
diff --combined libclamav/ishield.c
index 90ffb13,d51f314..76667ac
--- a/libclamav/ishield.c
+++ b/libclamav/ishield.c
@@@ -24,12 -24,19 +24,12 @@@
#include "clamav-config.h"
#endif
-#define _XOPEN_SOURCE 500
-
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#if HAVE_MMAP
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-#endif /* HAVE_MMAP */
#if HAVE_STRING_H
#include <string.h>
#endif
@@@ -42,7 -49,6 +42,7 @@@
#include "scanners.h"
#include "cltypes.h"
#include "others.h"
+#include "fmap.h"
#include "ishield.h"
#ifndef O_BINARY
@@@ -65,14 -71,6 +65,14 @@@
/* PACKED things go here */
+struct IS_HDR {
+ uint32_t magic;
+ uint32_t unk1; /* version ??? */
+ uint32_t unk2; /* ??? */
+ uint32_t data_off;
+ uint32_t data_sz; /* ??? */
+} __attribute__((packed));
+
struct IS_FB {
char fname[0x104]; /* MAX_PATH */
uint32_t unk1; /* 6 */
@@@ -189,22 -187,21 +189,22 @@@ struct IS_FILEITEM
-static int is_dump_and_scan(int desc, cli_ctx *ctx, off_t off, size_t fsize);
+static int is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize);
static const uint8_t skey[] = { 0xec, 0xca, 0x79, 0xf8 }; /* ~0x13, ~0x35, ~0x86, ~0x07 */
/* Extracts the content of MSI based IS */
-int cli_scanishield_msi(int desc, cli_ctx *ctx, off_t off) {
- uint8_t buf[BUFSIZ];
+int cli_scanishield_msi(cli_ctx *ctx, off_t off) {
+ uint8_t *buf;
unsigned int fcount, scanned = 0;
int ret;
+ struct F_MAP *map = *ctx->fmap;
cli_dbgmsg("in ishield-msi\n");
- lseek(desc, off, SEEK_SET);
- if(cli_readn(desc, buf, 0x20) != 0x20) {
+ if(!(buf = fmap_need_off_once(map, off, 0x20))) {
cli_dbgmsg("ishield-msi: short read for header\n");
return CL_CLEAN;
}
+ off += 0x20;
if(cli_readint32(buf + 8) | cli_readint32(buf + 0xc) | cli_readint32(buf + 0x10) | cli_readint32(buf + 0x14) | cli_readint32(buf + 0x18) | cli_readint32(buf + 0x1c))
return CL_CLEAN;
if(!(fcount = cli_readint32(buf))) {
@@@ -220,20 -217,16 +220,20 @@@
uint64_t csize;
z_stream z;
- if(cli_readn(desc, &fb, sizeof(fb)) != sizeof(fb)) {
+ if(fmap_readn(map, &fb, off, sizeof(fb)) != sizeof(fb)) {
cli_dbgmsg("ishield-msi: short read for fileblock\n");
return CL_CLEAN;
}
+ off += sizeof(fb);
fb.fname[sizeof(fb.fname)-1] = '\0';
csize = le64_to_host(fb.csize);
-
+ if(!CLI_ISCONTAINED(0, map->len, off, csize)) {
+ cli_dbgmsg("ishield-msi: next stream is out of file, giving up\n");
+ return CL_CLEAN;
+ }
if(ctx->engine->maxfilesize && csize > ctx->engine->maxfilesize) {
- cli_dbgmsg("ishield-msi: skipping stream due to size limits (%lu vs %lu)\n", csize, ctx->engine->maxfilesize);
+ cli_dbgmsg("ishield-msi: skipping stream due to size limits (%lu vs %lu)\n", (unsigned long int) csize, (unsigned long int) ctx->engine->maxfilesize);
- lseek(desc, csize, SEEK_CUR);
+ off += csize;
continue;
}
@@@ -254,21 -247,20 +254,21 @@@
inflateInit(&z);
ret = CL_SUCCESS;
while(csize) {
- unsigned int sz = csize < sizeof(buf) ? csize : sizeof(buf);
- z.avail_in = cli_readn(desc, buf, sz);
- if(z.avail_in <= 0) {
+ uint8_t buf2[BUFSIZ];
+ z.avail_in = MIN(csize, sizeof(buf2));
+ if(fmap_readn(map, buf2, off, z.avail_in) != z.avail_in) {
cli_dbgmsg("ishield-msi: premature EOS or read fail\n");
- break;
+ break;
}
+ off += z.avail_in;
for(i=0; i<z.avail_in; i++, lameidx++) {
- uint8_t c = buf[i];
+ uint8_t c = buf2[i];
c = (c>>4) | (c<<4);
c ^= key[(lameidx & 0x3ff) % keylen];
- buf[i] = c;
+ buf2[i] = c;
}
csize -= z.avail_in;
- z.next_in = buf;
+ z.next_in = buf2;
do {
int inf;
z.avail_out = sizeof(obuf);
@@@ -277,7 -269,7 +277,7 @@@
if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
cli_dbgmsg("ishield-msi: bad stream\n");
csize = 0;
- lseek(desc, csize, SEEK_CUR);
+ off += csize;
break;
}
if (cli_writen(ofd, obuf, sizeof(obuf) - z.avail_out) < 0) {
@@@ -286,8 -278,8 +286,8 @@@
break;
}
if(ctx->engine->maxfilesize && z.total_out > ctx->engine->maxfilesize) {
- cli_dbgmsg("ishield-msi: trimming output file due to size limits (%lu vs %lu)\n", z.total_out, ctx->engine->maxfilesize);
+ cli_dbgmsg("ishield-msi: trimming output file due to size limits (%lu vs %lu)\n", z.total_out, (unsigned long int) ctx->engine->maxfilesize);
- lseek(desc, csize, SEEK_CUR);
+ off += csize;
csize = 0;
break;
}
@@@ -333,47 -325,55 +333,47 @@@ struct IS_CABSTUFF
};
static void md5str(uint8_t *sum);
-static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c);
-static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize);
+static int is_parse_hdr(cli_ctx *ctx, struct IS_CABSTUFF *c);
+static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize);
/* Extract the content of older (non-MSI) IS */
-int cli_scanishield(int desc, cli_ctx *ctx, off_t off, size_t sz) {
+int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz) {
char *fname, *path, *version, *strsz, *eostr, *data;
- char buf[2048];
- int rd, ret = CL_CLEAN;
+ int ret = CL_CLEAN;
long fsize;
off_t coff = off;
struct IS_CABSTUFF c = { NULL, -1, 0, 0 };
+ struct F_MAP *map = *ctx->fmap;
while(ret == CL_CLEAN) {
- rd = pread(desc, buf, sizeof(buf), coff);
- if(rd <= 0)
- break;
+ fname = fmap_need_offstr(map, coff, 2048);
+ if(!fname) break;
+ coff += strlen(fname) + 1;
- fname = buf;
- if(!*fname) break;
- path = memchr(fname, 0, rd);
- if(!path)
- break;
+ path = fmap_need_offstr(map, coff, 2048);
+ if(!path) break;
+ coff += strlen(path) + 1;
- path++;
- rd -= (path - buf);
- if(rd<=0 || !(version = memchr(path, 0, rd)))
- break;
+ version = fmap_need_offstr(map, coff, 2048);
+ if(!version) break;
+ coff += strlen(version) + 1;
- version++;
- rd -= (version - path);
- if(rd<=0 || !(strsz = memchr(version, 0, rd)))
- break;
+ strsz = fmap_need_offstr(map, coff, 2048);
+ if(!strsz) break;
+ coff += strlen(strsz) + 1;
- strsz++;
- rd -= (strsz - version);
- if(rd<=0 || !(data = memchr(strsz, 0, rd)))
- break;
+ data = &strsz[strlen(strsz) + 1];
- data++;
fsize = strtol(strsz, &eostr, 10);
if(fsize < 0 || fsize == LONG_MAX ||
!*strsz || !eostr || eostr == strsz || *eostr ||
(unsigned long)fsize >= sz ||
- data - buf >= sz - fsize
+ data - fname >= sz - fsize
) break;
- cli_dbgmsg("ishield: @%lx found file %s (%s) - version %s - size %lu\n", coff, fname, path, version, fsize);
+ cli_dbgmsg("ishield: @%lx found file %s (%s) - version %s - size %lu\n", (unsigned long int) coff, fname, path, version, (unsigned long int) fsize);
- sz -= (data - buf) + fsize;
- coff += (data - buf);
+ sz -= (data - fname) + fsize;
+
if(!strncasecmp(fname, "data", 4)) {
long cabno;
if(!strcasecmp(fname + 4, "1.hdr")) {
@@@ -407,21 -407,20 +407,21 @@@
}
}
- ret = is_dump_and_scan(desc, ctx, coff, fsize);
+ fmap_unneed_ptr(map, fname, data-fname);
+ ret = is_dump_and_scan(ctx, coff, fsize);
coff += fsize;
}
if(ret == CL_CLEAN && (c.cabcnt || c.hdr != -1)) {
- if((ret = is_parse_hdr(desc, ctx, &c)) == CL_CLEAN) {
+ if((ret = is_parse_hdr(ctx, &c)) == CL_CLEAN) {
unsigned int i;
if(c.hdr != -1) {
cli_dbgmsg("ishield: scanning data1.hdr\n");
- ret = is_dump_and_scan(desc, ctx, c.hdr, c.hdrsz);
+ ret = is_dump_and_scan(ctx, c.hdr, c.hdrsz);
}
for(i=0; i<c.cabcnt && ret == CL_CLEAN; i++) {
cli_dbgmsg("ishield: scanning data%u.cab\n", c.cabs[i].cabno);
- ret = is_dump_and_scan(desc, ctx, c.cabs[i].off, c.cabs[i].sz);
+ ret = is_dump_and_scan(ctx, c.cabs[i].off, c.cabs[i].sz);
}
} else if( ret == CL_BREAK ) ret = CL_CLEAN;
}
@@@ -431,10 -430,9 +431,10 @@@
/* Utility func to scan a fd @ a given offset and size */
-static int is_dump_and_scan(int desc, cli_ctx *ctx, off_t off, size_t fsize) {
- char *fname, buf[BUFSIZ];
+static int is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize) {
+ char *fname, *buf;
int ofd, ret = CL_CLEAN;
+ struct F_MAP *map = *ctx->fmap;
if(!fsize) {
cli_dbgmsg("ishield: skipping empty file\n");
@@@ -449,18 -447,19 +449,18 @@@
return CL_ECREAT;
}
while(fsize) {
- size_t rd = fsize < sizeof(buf) ? fsize : sizeof(buf);
- int got = pread(desc, buf, rd, off);
- if(got <= 0) {
+ size_t rd = MIN(fsize, map->pgsz);
+ if(!(buf = fmap_need_off_once(map, off, rd))) {
cli_dbgmsg("ishield: read error\n");
ret = CL_EREAD;
break;
}
- if(cli_writen(ofd, buf, got) <= 0) {
+ if(cli_writen(ofd, buf, rd) <= 0) {
ret = CL_EWRITE;
break;
}
- fsize -= got;
- off += got;
+ fsize -= rd;
+ off += rd;
}
if(!fsize) {
cli_dbgmsg("ishield: extracted to %s\n", fname);
@@@ -474,13 -473,29 +474,13 @@@
return ret;
}
-
-struct IS_HDR {
- uint32_t magic;
- uint32_t unk1; /* version ??? */
- uint32_t unk2; /* ??? */
- uint32_t data_off;
- uint32_t data_sz; /* ??? */
-};
-
-
-#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) {
+static int is_parse_hdr(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, *map = NULL;
+ char hash[33], *hdr;
+ struct F_MAP *map = *ctx->fmap;
size_t mp_hdrsz;
struct IS_HDR *h1;
@@@ -492,29 -507,52 +492,29 @@@
return CL_CLEAN;
}
- 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 defined(HAVE_MMAP) && defined(HAVE_CLI_GETPAGESIZE)
- int psz = cli_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 is not usable\n");
- return CL_CLEAN;
-#endif
- }
-
- h1 = (struct IS_HDR *)hdr;
- if(!CLI_ISCONTAINED(hdr, c->hdrsz, ((char *)h1), sizeof(*h1))) {
+ if(!(h1 = fmap_need_off(map, c->hdr, c->hdrsz))) {
cli_dbgmsg("is_parse_hdr: not enough room for H1\n");
- IS_FREE_HDR;
return CL_CLEAN;
}
+ hdr = (char *)h1;
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");
- IS_FREE_HDR;
- return CL_CLEAN;
+ objs = (struct IS_OBJECTS *)fmap_need_ptr(map, hdr + h1_data_off, sizeof(*objs));
+ if(!objs) {
+ cli_dbgmsg("is_parse_hdr: not enough room for OBJECTS\n");
+ fmunmap(map);
+ return CL_CLEAN;
}
cli_dbgmsg("is_parse_hdr: magic %x, unk1 %x, unk2 %x, data_off %x, data_sz %x\n",
- h1->magic, h1->unk1, h1->unk2, h1_data_off, h1->data_sz);
+ 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;
+ cli_dbgmsg("is_parse_hdr: bad magic. wrong version?\n");
+ fmunmap(map);
+ return CL_CLEAN;
}
+ fmap_unneed_ptr(map, h1, sizeof(*h1));
+
/* cli_errmsg("COMPONENTS\n"); */
/* off = le32_to_host(objs->comps_off) + h1_data_off; */
/* for(i=1; ; i++) { */
@@@ -551,12 -589,11 +551,12 @@@
objs_files_cnt = le32_to_host(objs->files_cnt);
off = h1_data_off + objs_dirs_off + le32_to_host(objs->dir_sz2);
+ fmap_unneed_ptr(map, objs, sizeof(*objs));
for(i=0; i<objs_files_cnt ;i++) {
- struct IS_FILEITEM *file = (struct IS_FILEITEM *)(&hdr[off]);
+ struct IS_FILEITEM *file = (struct IS_FILEITEM *)fmap_need_off(map, c->hdr + off, sizeof(*file));
- if(CLI_ISCONTAINED(hdr, c->hdrsz, ((char *)file), sizeof(*file))) {
- const char *dir_name = "", *file_name = "";
+ if(file) {
+ const char *emptyname = "", *dir_name = emptyname, *file_name = emptyname;
uint32_t dir_rel = h1_data_off + objs_dirs_off + 4 * le32_to_host(file->dir_id); /* rel off of dir entry from array of rel ptrs */
uint32_t file_rel = objs_dirs_off + h1_data_off + le32_to_host(file->str_name_off); /* rel off of fname */
uint64_t file_stream_off, file_size, file_csize;
@@@ -564,12 -601,12 +564,12 @@@
memcpy(hash, file->md5, 16);
md5str((uint8_t *)hash);
- if(CLI_ISCONTAINED(hdr, c->hdrsz, &hdr[dir_rel], 4)) {
+ if(fmap_need_ptr_once(map, &hdr[dir_rel], 4)) {
dir_rel = cli_readint32(&hdr[dir_rel]) + h1_data_off + objs_dirs_off;
- if(CLI_ISCONTAINED(hdr, c->hdrsz, &hdr[dir_rel], 1) && memchr(&hdr[dir_rel], 0, c->hdrsz - dir_rel))
+ if(fmap_need_str(map, &hdr[dir_rel], c->hdrsz - dir_rel))
dir_name = &hdr[dir_rel];
}
- if(CLI_ISCONTAINED(hdr, c->hdrsz, &hdr[file_rel], 1) && memchr(&hdr[file_rel], 0, c->hdrsz - file_rel))
+ if(fmap_need_str(map, &hdr[file_rel], c->hdrsz - file_rel))
file_name = &hdr[file_rel];
file_stream_off = le64_to_host(file->stream_off);
@@@ -599,7 -636,7 +599,7 @@@
int cabret = CL_CLEAN;
if(ctx->engine->maxfilesize && file_csize > ctx->engine->maxfilesize) {
- cli_dbgmsg("is_parse_hdr: skipping file due to size limits (%lu vs %lu)\n", file_csize, ctx->engine->maxfilesize);
+ cli_dbgmsg("is_parse_hdr: skipping file due to size limits (%lu vs %lu)\n", (unsigned long int) file_csize, (unsigned long int) ctx->engine->maxfilesize);
break;
}
@@@ -609,13 -646,10 +609,13 @@@
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;
+ if(file_name != emptyname)
+ fmap_unneed_ptr(map, (void *)file_name, strlen(file_name)+1);
+ if(dir_name != emptyname)
+ fmap_unneed_ptr(map, (void *)dir_name, strlen(dir_name)+1);
return CL_EMAXFILES;
}
- cabret = is_extract_cab(desc, ctx, file_stream_off + c->cabs[j].off, file_size, file_csize);
+ cabret = is_extract_cab(ctx, file_stream_off + c->cabs[j].off, file_size, file_csize);
} else {
ret = CL_CLEAN;
cli_dbgmsg("is_parse_hdr: stream out of file\n");
@@@ -629,10 -663,7 +629,10 @@@
cabret = CL_CLEAN;
}
if(cabret != CL_CLEAN) {
- IS_FREE_HDR;
+ if(file_name != emptyname)
+ fmap_unneed_ptr(map, (void *)file_name, strlen(file_name)+1);
+ if(dir_name != emptyname)
+ fmap_unneed_ptr(map, (void *)dir_name, strlen(dir_name)+1);
return cabret;
}
} else {
@@@ -643,17 -674,13 +643,17 @@@
default:
cli_dbgmsg("is_parse_hdr: skipped unknown file entry %u\n", i);
}
+ if(file_name != emptyname)
+ fmap_unneed_ptr(map, (void *)file_name, strlen(file_name)+1);
+ if(dir_name != emptyname)
+ fmap_unneed_ptr(map, (void *)dir_name, strlen(dir_name)+1);
+ fmap_unneed_ptr(map, file, sizeof(*file));
} else {
ret = CL_CLEAN;
cli_dbgmsg("is_parse_hdr: FILEITEM out of bounds\n");
}
off += sizeof(*file);
}
- IS_FREE_HDR;
return ret;
}
@@@ -673,25 -700,55 +673,25 @@@ static void md5str(uint8_t *sum)
#define IS_CABBUFSZ 65536
-static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize) {
+static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize) {
uint8_t *inbuf, *outbuf;
char *tempfile;
- FILE *in;
int ofd, ret = CL_CLEAN;
z_stream z;
uint64_t outsz = 0;
int success = 0;
+ struct F_MAP *map = *ctx->fmap;
- if((ofd=dup(desc)) < 0) {
- cli_errmsg("is_extract_cab: dup failed\n");
- return CL_EDUP;
- }
- if(!(in = fdopen(ofd, "rb"))) {
- cli_errmsg("is_extract_cab: fdopen failed\n");
- close(ofd);
- return CL_EOPEN;
- }
-#if HAVE_FSEEKO
- if(fseeko(in, (off_t)off, SEEK_SET))
-#else
- if(fseek(in, (long)off, SEEK_SET))
-#endif
- {
- cli_dbgmsg("is_extract_cab: fseek failed\n");
- fclose(in);
- return CL_ESEEK;
- }
- if(!(inbuf = cli_malloc(IS_CABBUFSZ))) {
- fclose(in);
- return CL_EMEM;
- }
- if(!(outbuf = cli_malloc(IS_CABBUFSZ))) {
- free(inbuf);
- fclose(in);
+ if(!(outbuf = cli_malloc(IS_CABBUFSZ)))
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;
}
@@@ -703,12 -760,11 +703,12 @@@
break;
}
csize -= 2;
- if(!fread(outbuf, 2, 1, in)) {
+ if(!(inbuf = fmap_need_off_once(map, off, 2))) {
cli_dbgmsg("is_extract_cab: short read for chunk size\n");
break;
}
- chunksz = outbuf[0] | (outbuf[1] << 8);
+ off += 2;
+ chunksz = inbuf[0] | (inbuf[1] << 8);
if(!chunksz) {
cli_dbgmsg("is_extract_cab: zero sized chunk\n");
continue;
@@@ -718,11 -774,10 +718,11 @@@
break;
}
csize -= chunksz;
- if(!fread(inbuf, chunksz, 1, in)) {
+ if(!(inbuf = fmap_need_off_once(map, off, chunksz))) {
cli_dbgmsg("is_extract_cab: short read for chunk\n");
break;
}
+ off += chunksz;
memset(&z, 0, sizeof(z));
inflateInit2(&z, -MAX_WBITS);
z.next_in = (uint8_t *)inbuf;
@@@ -742,7 -797,7 +742,7 @@@
break;
}
if(ctx->engine->maxfilesize && z.total_out > ctx->engine->maxfilesize) {
- cli_dbgmsg("ishield_extract_cab: trimming output file due to size limits (%lu vs %lu)\n", z.total_out, ctx->engine->maxfilesize);
+ cli_dbgmsg("ishield_extract_cab: trimming output file due to size limits (%lu vs %lu)\n", z.total_out, (unsigned long int) ctx->engine->maxfilesize);
success = 1;
outsz = size;
break;
@@@ -755,6 -810,8 +755,6 @@@
inflateEnd(&z);
if(!success) break;
}
- fclose(in);
- free(inbuf);
free(outbuf);
if(success) {
if (outsz != size)
diff --combined libclamav/matcher-ac.c
index 2f3c144,00efb69..7646195
--- a/libclamav/matcher-ac.c
+++ b/libclamav/matcher-ac.c
@@@ -45,12 -45,18 +45,18 @@@
#include "mpool.h"
+ #define AC_SPECIAL_ALT_CHAR 1
+ #define AC_SPECIAL_ALT_STR 2
+ #define AC_SPECIAL_LINE_START 3
+ #define AC_SPECIAL_LINE_END 4
+ #define AC_SPECIAL_BOUNDARY 5
+
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);
@@@ -131,27 -137,31 +137,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;
@@@ -350,22 -360,22 +360,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;
@@@ -374,7 -384,7 +384,7 @@@
mpool_free(mempool, a2);
}
}
- mpool_free(mempool, p->alttable);
+ mpool_free(mempool, p->special_table);
}
void cli_ac_free(struct cli_matcher *root)
@@@ -387,8 -397,8 +397,8 @@@
patt = root->ac_pattable[i];
mpool_free(root->mempool, patt->prefix ? patt->prefix : patt->pattern);
mpool_free(root->mempool, patt->virname);
- 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)
@@@ -650,61 -660,75 +660,75 @@@ 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; \
+ #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_BOUNDARY: \
+ if(memchr("\x22\x27\x20\x2f\x3d\x2d\x5f\x3e\x0a\x0d", b, 10)) \
+ 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 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))
@@@ -737,7 -761,7 +761,7 @@@
}
if(pattern->prefix) {
- altcnt = 0;
+ specialcnt = 0;
bp = offset - pattern->prefix_length;
match = 1;
for(i = 0; i < pattern->prefix_length; i++) {
@@@ -830,23 -854,28 +854,23 @@@ int cli_ac_initdata(struct cli_ac_data
return CL_SUCCESS;
}
-int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, int fd)
+int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, struct F_MAP *map)
{
int ret;
unsigned int i;
struct cli_ac_patt *patt;
struct cli_target_info info;
- struct stat sb;
- if(fd != -1) {
+ if(map) {
memset(&info, 0, sizeof(info));
- if(fstat(fd, &sb) == -1) {
- cli_errmsg("cli_ac_caloff: fstat(%d) failed\n", fd);
- return CL_ESTAT;
- }
- info.fsize = sb.st_size;
+ info.fsize = map->len;
}
for(i = 0; i < root->ac_reloff_num; i++) {
patt = root->ac_reloff[i];
- if(fd == -1) {
+ if(!map) {
data->offset[patt->offset_min] = CLI_OFF_NONE;
- } else if((ret = cli_caloff(NULL, &info, fd, root->type, patt->offdata, &data->offset[patt->offset_min], &data->offset[patt->offset_max]))) {
+ } 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);
@@@ -855,7 -884,7 +879,7 @@@
data->offset[patt->offset_min] = CLI_OFF_NONE;
}
}
- if(fd != -1 && info.exeinfo.section)
+ if(map && info.exeinfo.section)
free(info.exeinfo.section);
return CL_SUCCESS;
@@@ -1151,6 -1180,11 +1175,11 @@@ int cli_ac_scanbuff(const unsigned cha
return (mode & AC_SCAN_FT) ? type : CL_CLEAN;
}
+ static int qcompare(const void *a, const void *b)
+ {
+ return *(unsigned char *)a - *(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)
{
@@@ -1158,7 -1192,7 +1187,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;
@@@ -1293,99 -1327,121 +1322,121 @@@
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 *));
+ 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;
+ /* TODO
+ } else if(strcmp(pt, "S")) {
+ newspecial->type = AC_SPECIAL_LINE_START;
+ } else if(strcmp(pt, "E")) {
+ newspecial->type = AC_SPECIAL_LINE_END;
+ } 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)
@@@ -1395,9 -1451,9 +1446,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;
@@@ -1406,8 -1462,8 +1457,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;
@@@ -1456,7 -1512,7 +1507,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;
@@@ -1468,8 -1524,8 +1519,8 @@@
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)
@@@ -1478,7 -1534,7 +1529,7 @@@
new->virname = cli_mpool_virname(root->mempool, (char *) 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;
}
@@@ -1486,10 -1542,10 +1537,10 @@@
if(new->lsigid[0])
root->ac_lsigtable[new->lsigid[1]]->virname = new->virname;
- ret = cli_caloff(offset, NULL, -1, root->type, new->offdata, &new->offset_min, &new->offset_max);
+ 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_alt(root->mempool, new);
+ mpool_ac_free_special(root->mempool, new);
mpool_free(root->mempool, new->virname);
mpool_free(root->mempool, new);
return ret;
@@@ -1498,7 -1554,7 +1549,7 @@@
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);
+ mpool_ac_free_special(root->mempool, new);
mpool_free(root->mempool, new);
return ret;
}
diff --combined libclamav/matcher-ac.h
index e8dc62f,ad0b9ab..90d9816
--- a/libclamav/matcher-ac.h
+++ b/libclamav/matcher-ac.h
@@@ -25,7 -25,6 +25,7 @@@
#include "filetypes.h"
#include "cltypes.h"
+#include "fmap.h"
#define AC_CH_MAXDIST 32
@@@ -39,11 -38,11 +39,11 @@@ struct cli_ac_data
uint32_t *offset;
};
- struct cli_ac_alt {
+ struct cli_ac_special {
unsigned char *str;
- struct cli_ac_alt *next;
+ struct cli_ac_special *next;
uint16_t len, num;
- uint8_t chmode;
+ uint8_t type, negative;
};
struct cli_ac_patt {
@@@ -56,8 -55,8 +56,8 @@@
void *customdata;
uint16_t ch_mindist[2];
uint16_t ch_maxdist[2];
- uint16_t parts, partno, alt, alt_pattern;
- struct cli_ac_alt **alttable;
+ uint16_t parts, partno, special, special_pattern;
+ struct cli_ac_special **special_table;
struct cli_ac_patt *next, *next_same;
uint8_t depth;
uint16_t rtype, type;
@@@ -87,7 -86,7 +87,7 @@@ void cli_ac_freedata(struct cli_ac_dat
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);
int cli_ac_buildtrie(struct cli_matcher *root);
int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth);
-int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, int fd);
+int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, struct F_MAP *map);
void cli_ac_free(struct cli_matcher *root);
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);
diff --combined libclamav/matcher-bm.c
index 6b592eb,7c8eda6..caf4972
--- a/libclamav/matcher-bm.c
+++ b/libclamav/matcher-bm.c
@@@ -51,7 -51,7 +51,7 @@@ int cli_bm_addpatt(struct cli_matcher *
return CL_EMALFDB;
}
- if((ret = cli_caloff(offset, NULL, -1, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) {
+ if((ret = cli_caloff(offset, NULL, NULL, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) {
cli_errmsg("cli_bm_addpatt: Can't calculate offset for signature %s\n", pattern->virname);
return ret;
}
@@@ -145,12 -145,13 +145,12 @@@ static int qcompare(const void *a, cons
return *(const uint32_t *)a - *(const uint32_t *)b;
}
-int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, int fd)
+int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, struct F_MAP *map)
{
int ret;
unsigned int i;
struct cli_bm_patt *patt;
struct cli_target_info info;
- struct stat sb;
if(!root->bm_patterns) {
@@@ -159,7 -160,11 +159,7 @@@
return CL_SUCCESS;
}
memset(&info, 0, sizeof(info));
- if(fstat(fd, &sb) == -1) {
- cli_errmsg("cli_bm_initoff: fstat(%d) failed\n", fd);
- return CL_ESTAT;
- }
- info.fsize = sb.st_size;
+ info.fsize = map->len;
data->cnt = data->pos = 0;
data->offtab = (uint32_t *) cli_malloc(root->bm_patterns * sizeof(uint32_t));
@@@ -178,7 -183,7 +178,7 @@@
if(patt->offdata[0] == CLI_OFF_ABSOLUTE) {
data->offtab[data->cnt] = patt->offset_min + patt->prefix_length;
data->cnt++;
- } else if((ret = cli_caloff(NULL, &info, fd, root->type, patt->offdata, &data->offset[patt->offset_min], NULL))) {
+ } else if((ret = cli_caloff(NULL, &info, map, root->type, patt->offdata, &data->offset[patt->offset_min], NULL))) {
cli_errmsg("cli_bm_initoff: Can't calculate relative offset in signature for %s\n", patt->virname);
if(info.exeinfo.section)
free(info.exeinfo.section);
@@@ -195,7 -200,7 +195,7 @@@
if(info.exeinfo.section)
free(info.exeinfo.section);
- qsort(data->offtab, data->cnt, sizeof(uint32_t), qcompare);
+ cli_qsort(data->offtab, data->cnt, sizeof(uint32_t), qcompare);
return CL_SUCCESS;
}
@@@ -238,7 -243,7 +238,7 @@@ void cli_bm_free(struct cli_matcher *ro
}
}
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd, struct cli_bm_off *offdata)
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, struct F_MAP *map, struct cli_bm_off *offdata)
{
uint32_t i, j, off, off_min, off_max;
uint8_t found, pchain, shift;
@@@ -272,7 -277,7 +272,7 @@@
if(p && p->cnt == 1 && p->pattern0 != prefix) {
if(offdata) {
off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE;
- for(; off >= offdata->offtab[offdata->pos] && offdata->pos < offdata->cnt; offdata->pos++);
+ for(; offdata->pos < offdata->cnt && off >= offdata->offtab[offdata->pos]; offdata->pos++);
if(offdata->pos == offdata->cnt || off >= offdata->offtab[offdata->pos])
return CL_CLEAN;
i += offdata->offtab[offdata->pos] - off;
@@@ -337,7 -342,7 +337,7 @@@
if(found && p->length + p->prefix_length == j) {
if(!offdata && (p->offset_min != CLI_OFF_ANY)) {
if(p->offdata[0] != CLI_OFF_ABSOLUTE) {
- ret = cli_caloff(NULL, &info, fd, root->type, p->offdata, &off_min, &off_max);
+ ret = cli_caloff(NULL, &info, map, root->type, p->offdata, &off_min, &off_max);
if(ret != CL_SUCCESS) {
cli_errmsg("cli_bm_scanbuff: Can't calculate relative offset in signature for %s\n", p->virname);
if(info.exeinfo.section)
@@@ -367,7 -372,7 +367,7 @@@
if(offdata) {
off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE;
- for(; off >= offdata->offtab[offdata->pos] && offdata->pos < offdata->cnt; offdata->pos++);
+ for(; offdata->pos < offdata->cnt && off >= offdata->offtab[offdata->pos]; offdata->pos++);
if(offdata->pos == offdata->cnt || off >= offdata->offtab[offdata->pos])
return CL_CLEAN;
i += offdata->offtab[offdata->pos] - off;
diff --combined libclamav/matcher.h
index 863a781,0385838..ff3d9e9
--- a/libclamav/matcher.h
+++ b/libclamav/matcher.h
@@@ -33,13 -33,13 +33,13 @@@
#include "matcher-ac.h"
#include "matcher-bm.h"
#include "hashtab.h"
-
+#include "fmap.h"
#include "mpool.h"
#define CLI_MATCH_WILDCARD 0xff00
#define CLI_MATCH_CHAR 0x0000
#define CLI_MATCH_IGNORE 0x0100
- #define CLI_MATCH_ALTERNATIVE 0x0200
+ #define CLI_MATCH_SPECIAL 0x0200
#define CLI_MATCH_NIBBLE_HIGH 0x0300
#define CLI_MATCH_NIBBLE_LOW 0x0400
@@@ -140,9 -140,8 +140,9 @@@ struct cli_target_info
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 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);
-int cli_caloff(const char *offstr, struct cli_target_info *info, int fd, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
+int cli_caloff(const char *offstr, struct cli_target_info *info, struct F_MAP *map, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
int cli_checkfp(int fd, cli_ctx *ctx);
diff --combined libclamav/others.h
index f4e9e3b,9f318dc..8ce23aa
--- a/libclamav/others.h
+++ b/libclamav/others.h
@@@ -38,7 -38,6 +38,7 @@@
#include "clamav.h"
#include "dconf.h"
#include "filetypes.h"
+#include "fmap.h"
#include "libclamunrar_iface/unrar_iface.h"
#include "regex/regex.h"
@@@ -110,7 -109,6 +110,7 @@@ typedef struct
unsigned int found_possibly_unwanted;
cli_file_t container_type; /* FIXME: to be made into a stack or array - see bb#1579 & bb#1293 */
struct cli_dconf *dconf;
+ struct F_MAP **fmap;
} cli_ctx;
struct cl_engine {
@@@ -413,6 -411,7 +413,7 @@@ int cli_checklimits(const char *, cli_c
int cli_updatelimits(cli_ctx *, unsigned long);
unsigned long cli_getsizelimit(cli_ctx *, unsigned long);
int cli_matchregex(const char *str, const char *regex);
+ void cli_qsort(void *basep, size_t nelems, size_t size, int (*comp)(const void *, const void *));
/* symlink behaviour */
#define CLI_FTW_FOLLOW_FILE_SYMLINK 0x01
diff --combined libclamav/scanners.c
index 463ad10,2eab5f6..22c1158
--- a/libclamav/scanners.c
+++ b/libclamav/scanners.c
@@@ -22,7 -22,6 +22,7 @@@
#include "clamav-config.h"
#endif
+#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@@ -41,6 -40,14 +41,6 @@@
#include <netinet/in.h>
#endif
-#if HAVE_MMAP
-#if HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#else /* HAVE_SYS_MMAN_H */
-#undef HAVE_MMAP
-#endif
-#endif
-
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@@ -89,7 -96,6 +89,7 @@@
#include "macho.h"
#include "ishield.h"
#include "7z.h"
+#include "fmap.h"
#ifdef HAVE_BZLIB_H
#include <bzlib.h>
@@@ -432,67 -438,77 +432,67 @@@ static int cli_scanarj(int desc, cli_ct
return ret;
}
-static int cli_scangzip(int desc, cli_ctx *ctx)
+static int cli_scangzip(cli_ctx *ctx)
{
- int fd, bytes, ret = CL_CLEAN;
- unsigned long int size = 0;
- char *buff;
+ int fd, ret = CL_CLEAN;
+ unsigned char buff[FILEBUFF];
char *tmpname;
- gzFile gd;
-
-
+ z_stream z;
+ size_t at = 0;
+ struct F_MAP *map = *ctx->fmap;
+
cli_dbgmsg("in cli_scangzip()\n");
- if((gd = gzdopen(dup(desc), "rb")) == NULL) {
- cli_dbgmsg("GZip: Can't open descriptor %d\n", desc);
- return CL_EOPEN;
+ memset(&z, 0, sizeof(z));
+ if(inflateInit2(&z, MAX_WBITS + 16) != Z_OK) {
+ cli_dbgmsg("GZip: InflateInit failed\n");
+ return CL_CLEAN;
}
- if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
+ if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
cli_dbgmsg("GZip: Can't generate temporary file.\n");
- gzclose(gd);
+ inflateEnd(&z);
return ret;
}
- if(!(buff = (char *) cli_malloc(FILEBUFF))) {
- cli_dbgmsg("GZip: Unable to malloc %u bytes.\n", FILEBUFF);
- gzclose(gd);
- close(fd);
- if(!ctx->engine->keeptmp) {
- if(cli_unlink(tmpname)) {
- free(tmpname);
+ while (at < map->len) {
+ unsigned int bytes = MIN(map->len - at, map->pgsz);
+ if(!(z.next_in = fmap_need_off_once(map, at, bytes))) {
+ cli_dbgmsg("GZip: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
+ inflateEnd(&z);
+ close(fd);
+ if (cli_unlink(tmpname)) {
+ free(tmpname);
return CL_EUNLINK;
}
+ free(tmpname);
+ return CL_EREAD;
}
- return CL_EMEM;
- }
-
- while((bytes = gzread(gd, buff, FILEBUFF)) > 0) {
- size += bytes;
-
- if(cli_checklimits("GZip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
- break;
-
- if(cli_writen(fd, buff, bytes) != bytes) {
- cli_dbgmsg("GZip: Can't write to file.\n");
- close(fd);
- if(!ctx->engine->keeptmp) {
- if (cli_unlink(tmpname)) {
+ at += bytes;
+ z.avail_in = bytes;
+ do {
+ int inf;
+ z.avail_out = sizeof(buff);
+ z.next_out = buff;
+ inf = inflate(&z, Z_NO_FLUSH);
+ if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
+ cli_dbgmsg("GZip: Bad stream.\n");
+ at = map->len;
+ break;
+ }
+ if(cli_writen(fd, buff, sizeof(buff) - z.avail_out) < 0) {
+ inflateEnd(&z);
+ close(fd);
+ if (cli_unlink(tmpname)) {
free(tmpname);
return CL_EUNLINK;
}
}
- free(tmpname);
- gzclose(gd);
- free(buff);
- return CL_EWRITE;
- }
+ } while (z.avail_out == 0);
}
- free(buff);
- gzclose(gd);
-
- if(ret == CL_VIRUS) {
- close(fd);
- if(!ctx->engine->keeptmp)
- if (cli_unlink(tmpname)) ret = CL_EUNLINK;
- free(tmpname);
- return ret;
- }
+ inflateEnd(&z);
- lseek(fd, 0, SEEK_SET);
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
close(fd);
@@@ -502,13 -518,14 +502,13 @@@
return CL_EUNLINK;
}
}
- free(tmpname);
+ free(tmpname);
return CL_VIRUS;
}
close(fd);
if(!ctx->engine->keeptmp)
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
- free(tmpname);
-
+ free(tmpname);
return ret;
}
@@@ -900,19 -917,24 +900,19 @@@ static int cli_vba_scandir(const char *
return ret;
}
-static int cli_scanhtml(int desc, cli_ctx *ctx)
+static int cli_scanhtml(cli_ctx *ctx)
{
char *tempname, fullname[1024];
int ret=CL_CLEAN, fd;
- struct stat sb;
+ struct F_MAP *map = *ctx->fmap;
cli_dbgmsg("in cli_scanhtml()\n");
- if(fstat(desc, &sb) == -1) {
- cli_errmsg("cli_scanhtml: fstat() failed for descriptor %d\n", desc);
- return CL_ESTAT;
- }
-
/* Because HTML detection is FP-prone and html_normalise_fd() needs to
* mmap the file don't normalise files larger than 10 MB.
*/
- if(sb.st_size > 10485760) {
+ if(map->len > 10485760) {
cli_dbgmsg("cli_scanhtml: exiting (file larger than 10 MB)\n");
return CL_CLEAN;
}
@@@ -928,7 -950,7 +928,7 @@@
cli_dbgmsg("cli_scanhtml: using tempdir %s\n", tempname);
- html_normalise_fd(desc, tempname, NULL, ctx->dconf);
+ html_normalise_map(map, tempname, NULL, ctx->dconf);
snprintf(fullname, 1024, "%s/nocomment.html", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if (fd >= 0) {
@@@ -936,7 -958,7 +936,7 @@@
close(fd);
}
- if(ret == CL_CLEAN && sb.st_size < 2097152) {
+ if(ret == CL_CLEAN && map->len < 2097152) {
/* limit to 2 MB, we're not interesting in scanning large files in notags form */
/* TODO: don't even create notags if file is over 2 MB */
snprintf(fullname, 1024, "%s/notags.html", tempname);
@@@ -972,25 -994,30 +972,25 @@@
return ret;
}
-static int cli_scanscript(int desc, cli_ctx *ctx)
+static int cli_scanscript(cli_ctx *ctx)
{
- unsigned char buff[FILEBUFF];
+ unsigned char *buff;
unsigned char* normalized;
struct text_norm_state state;
struct stat sb;
char *tmpname = NULL;
int ofd = -1, ret;
- ssize_t nread;
const struct cli_matcher *troot = ctx->engine->root[7];
uint32_t maxpatlen = troot ? troot->maxpatlen : 0, offset = 0;
struct cli_matcher *groot = ctx->engine->root[0];
struct cli_ac_data gmdata, tmdata;
struct cli_ac_data *mdata[2];
+ struct F_MAP *map = *ctx->fmap;
+ size_t at = 0;
cli_dbgmsg("in cli_scanscript()\n");
- if(fstat(desc, &sb) == -1) {
- cli_errmsg("cli_scanscript: fstat() failed for descriptor %d\n", desc);
- return CL_ESTAT;
- }
-
- /* don't normalize files that are too large */
- if(sb.st_size > 5242880) {
+ if(map->len > 5242880) {
cli_dbgmsg("cli_scanscript: exiting (file larger than 5 MB)\n");
return CL_CLEAN;
}
@@@ -1022,37 -1049,37 +1022,37 @@@
mdata[0] = &tmdata;
mdata[1] = &gmdata;
- do {
- nread = cli_readn(desc, buff, sizeof(buff));
- if(nread <= 0 || state.out_pos + nread > state.out_len) {
- /* flush if error/EOF, or too little buffer space left */
- if((ofd != -1) && (write(ofd, state.out, state.out_pos) == -1)) {
- cli_errmsg("cli_scanscript: can't write to file %s\n",tmpname);
- close(ofd);
- ofd = -1;
- /* we can continue to scan in memory */
- }
- /* when we flush the buffer also scan */
- if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
- ret = CL_VIRUS;
- break;
- }
- if(ctx->scanned)
- *ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
- offset += state.out_pos;
- /* carry over maxpatlen from previous buffer */
- if (state.out_pos > maxpatlen)
- memmove(state.out, state.out + state.out_pos - maxpatlen, maxpatlen);
- text_normalize_reset(&state);
- state.out_pos = maxpatlen;
+ while(1) {
+ size_t len = MIN(map->pgsz, map->len - at);
+ buff = fmap_need_off_once(map, at, len);
+ at += len;
+ if(!buff || !len || state.out_pos + len > state.out_len) {
+ /* flush if error/EOF, or too little buffer space left */
+ if((ofd != -1) && (write(ofd, state.out, state.out_pos) == -1)) {
+ cli_errmsg("cli_scanscript: can't write to file %s\n",tmpname);
+ close(ofd);
+ ofd = -1;
+ /* we can continue to scan in memory */
}
- if(nread > 0 && (text_normalize_buffer(&state, buff, nread) != nread)) {
- cli_dbgmsg("cli_scanscript: short read during normalizing\n");
+ /* when we flush the buffer also scan */
+ if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
+ ret = CL_VIRUS;
+ break;
}
- /* used a do {}while() here, since we need to flush our buffers at the end,
- * and using while(){} loop would mean code duplication */
- } while (nread > 0);
-
+ if(ctx->scanned)
+ *ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
+ offset += state.out_pos;
+ /* carry over maxpatlen from previous buffer */
+ if (state.out_pos > maxpatlen)
+ memmove(state.out, state.out + state.out_pos - maxpatlen, maxpatlen);
+ text_normalize_reset(&state);
+ state.out_pos = maxpatlen;
+ }
+ if(!len) break;
+ if(text_normalize_buffer(&state, buff, len) != len) {
+ cli_dbgmsg("cli_scanscript: short read during normalizing\n");
+ }
+ }
cli_ac_freedata(&tmdata);
cli_ac_freedata(&gmdata);
if(ctx->engine->keeptmp) {
@@@ -1064,12 -1091,11 +1064,12 @@@
return ret;
}
-static int cli_scanhtml_utf16(int desc, cli_ctx *ctx)
+static int cli_scanhtml_utf16(cli_ctx *ctx)
{
- char *tempname, buff[512], *decoded;
+ char *tempname, *decoded, *buff;
int ret = CL_CLEAN, fd, bytes;
-
+ size_t at = 0;
+ struct F_MAP *map = *ctx->fmap;
cli_dbgmsg("in cli_scanhtml_utf16()\n");
@@@ -1084,15 -1110,7 +1084,15 @@@
cli_dbgmsg("cli_scanhtml_utf16: using tempfile %s\n", tempname);
- while((bytes = read(desc, buff, sizeof(buff))) > 0) {
+ while(at < map->len) {
+ bytes = MIN(map->len - at, map->pgsz * 16);
+ if(!(buff = fmap_need_off_once(map, at, bytes))) {
+ close(fd);
+ cli_unlink(tempname);
+ free(tempname);
+ return CL_EREAD;
+ }
+ at += bytes;
decoded = cli_utf16toascii(buff, bytes);
if(decoded) {
if(write(fd, decoded, strlen(decoded)) == -1) {
@@@ -1107,14 -1125,8 +1107,14 @@@
}
}
- lseek(fd, 0, SEEK_SET);
- ret = cli_scanhtml(fd, ctx);
+ *ctx->fmap = fmap(fd, 0, 0);
+ if(*ctx->fmap) {
+ ret = cli_scanhtml(ctx);
+ fmunmap(*ctx->fmap);
+ } else
+ cli_errmsg("cli_scanhtml_utf16: fmap of %s failed\n", tempname);
+
+ *ctx->fmap = map;
close(fd);
if(!ctx->engine->keeptmp) {
@@@ -1126,7 -1138,7 +1126,7 @@@
return ret;
}
-static int cli_scanole2(int desc, cli_ctx *ctx)
+static int cli_scanole2(cli_ctx *ctx)
{
char *dir;
int ret = CL_CLEAN;
@@@ -1147,7 -1159,7 +1147,7 @@@
return CL_ETMPDIR;
}
- ret = cli_ole2_extract(desc, dir, ctx, &vba);
+ ret = cli_ole2_extract(dir, ctx, &vba);
if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
if(!ctx->engine->keeptmp)
@@@ -1200,7 -1212,7 +1200,7 @@@ static int cli_scantar(int desc, cli_ct
return ret;
}
-static int cli_scanbinhex(int desc, cli_ctx *ctx)
+static int cli_scanbinhex(cli_ctx *ctx)
{
char *dir;
int ret = CL_CLEAN;
@@@ -1218,7 -1230,7 +1218,7 @@@
return CL_ETMPDIR;
}
- if((ret = cli_binhex(dir, desc)))
+ if((ret = cli_binhex(dir, *ctx->fmap)))
cli_dbgmsg("Binhex: %s\n", cl_strerror(ret));
else
ret = cli_scandir(dir, ctx);
@@@ -1258,11 -1270,11 +1258,11 @@@ static int cli_scanmschm(int desc, cli_
}
do {
- ret = cli_chm_prepare_file(desc, dir, &metadata);
+ ret = cli_chm_prepare_file(&metadata);
if (ret != CL_SUCCESS) {
break;
}
- ret = cli_chm_extract_file(desc, dir, &metadata, ctx);
+ ret = cli_chm_extract_file(dir, &metadata, ctx);
if (ret == CL_SUCCESS) {
lseek(metadata.ofd, 0, SEEK_SET);
rc = cli_magic_scandesc(metadata.ofd, ctx);
@@@ -1429,7 -1441,7 +1429,7 @@@ static int cli_scancryptff(int desc, cl
return ret;
}
-static int cli_scanpdf(int desc, cli_ctx *ctx, off_t offset)
+static int cli_scanpdf(cli_ctx *ctx, off_t offset)
{
int ret;
char *dir = cli_gentemp(ctx->engine->tmpdir);
@@@ -1443,7 -1455,7 +1443,7 @@@
return CL_ETMPDIR;
}
- ret = cli_pdf(dir, desc, ctx, offset);
+ ret = cli_pdf(dir, ctx, offset);
if(!ctx->engine->keeptmp)
cli_rmdirs(dir);
@@@ -1478,7 -1490,7 +1478,7 @@@ static int cli_scantnef(int desc, cli_c
return ret;
}
-static int cli_scanuuencoded(int desc, cli_ctx *ctx)
+static int cli_scanuuencoded(cli_ctx *ctx)
{
int ret;
char *dir = cli_gentemp(ctx->engine->tmpdir);
@@@ -1492,7 -1504,7 +1492,7 @@@
return CL_ETMPDIR;
}
- ret = cli_uuencode(dir, desc);
+ ret = cli_uuencode(dir, *ctx->fmap);
if(ret == CL_CLEAN)
ret = cli_scandir(dir, ctx);
@@@ -1678,14 -1690,14 +1678,14 @@@ static int cli_scanembpe(int desc, cli_
return CL_CLEAN;
}
-static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype)
+static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype)
{
int ret = CL_CLEAN, nret = CL_CLEAN;
struct cli_matched_type *ftoffset = NULL, *fpt;
uint32_t lastzip, lastrar;
struct cli_exe_info peinfo;
unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
- struct stat sb;
+ struct F_MAP *map = *ctx->fmap;
if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
@@@ -1694,7 -1706,12 +1694,7 @@@
if(typercg)
acmode |= AC_SCAN_FT;
- if(lseek(desc, 0, SEEK_SET) < 0) {
- cli_errmsg("cli_scanraw: lseek() failed\n");
- return CL_ESEEK;
- }
-
- ret = cli_scandesc(desc, ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode);
+ ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode);
if(ret >= CL_TYPENO) {
ctx->recursion++;
@@@ -1718,72 -1735,73 +1718,72 @@@
cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
if(type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && fpt->offset < 102400 && (DCONF_ARCH & ARCH_CONF_RAR)) {
cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanrar(desc, ctx, fpt->offset, &lastrar);
+ nret = cli_scanrar(map->fd, ctx, fpt->offset, &lastrar);
}
break;
case CL_TYPE_ZIPSFX:
if(type != CL_TYPE_ZIP && SCAN_ARCHIVE && fpt->offset < 102400 && (DCONF_ARCH & ARCH_CONF_ZIP)) {
cli_dbgmsg("ZIP/ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_unzip_single(desc, ctx, fpt->offset);
+ nret = cli_unzip_single(ctx, fpt->offset);
}
break;
case CL_TYPE_CABSFX:
if(type != CL_TYPE_MSCAB && SCAN_ARCHIVE && fpt->offset < 102400 && (DCONF_ARCH & ARCH_CONF_CAB)) {
cli_dbgmsg("CAB/CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanmscab(desc, ctx, fpt->offset);
+ nret = cli_scanmscab(map->fd, ctx, fpt->offset);
}
break;
case CL_TYPE_ARJSFX:
if(type != CL_TYPE_ARJ && SCAN_ARCHIVE && fpt->offset < 102400 && (DCONF_ARCH & ARCH_CONF_ARJ)) {
cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanarj(desc, ctx, fpt->offset, &lastrar);
+ nret = cli_scanarj(map->fd, ctx, fpt->offset, &lastrar);
}
break;
case CL_TYPE_NULSFT:
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) && fpt->offset > 4) {
cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
- nret = cli_scannulsft(desc, ctx, fpt->offset - 4);
+ nret = cli_scannulsft(map->fd, ctx, fpt->offset - 4);
}
break;
case CL_TYPE_AUTOIT:
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanautoit(desc, ctx, fpt->offset + 23);
+ nret = cli_scanautoit(map->fd, ctx, fpt->offset + 23);
}
break;
case CL_TYPE_ISHIELD_MSI:
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD)) {
cli_dbgmsg("ISHIELD-MSI signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanishield_msi(desc, ctx, fpt->offset + 14);
+ nret = cli_scanishield_msi(ctx, fpt->offset + 14);
}
break;
case CL_TYPE_PDF:
if(type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanpdf(desc, ctx, fpt->offset);
+ nret = cli_scanpdf(ctx, fpt->offset);
}
break;
case CL_TYPE_MSEXE:
if(SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2) && ctx->dconf->pe) {
- fstat(desc, &sb);
- if(sb.st_size > 10485760)
+ if(map->len > 10485760)
break;
memset(&peinfo, 0, sizeof(struct cli_exe_info));
peinfo.offset = fpt->offset;
- lseek(desc, fpt->offset, SEEK_SET);
- if(cli_peheader(desc, &peinfo) == 0) {
+ lseek(map->fd, fpt->offset, SEEK_SET);
+ if(cli_peheader(map, &peinfo) == 0) {
cli_dbgmsg("*** Detected embedded PE file at %u ***\n", (unsigned int) fpt->offset);
if(peinfo.section)
free(peinfo.section);
- lseek(desc, fpt->offset, SEEK_SET);
- nret = cli_scanembpe(desc, ctx);
+ lseek(map->fd, fpt->offset, SEEK_SET);
+ nret = cli_scanembpe(map->fd, ctx);
break_loop = 1; /* we can stop here and other
* embedded executables will
* be found recursively
@@@ -1808,13 -1826,13 +1808,13 @@@
case CL_TYPE_HTML:
if(SCAN_HTML && type == CL_TYPE_TEXT_ASCII && (DCONF_DOC & DOC_CONF_HTML)) {
*dettype = CL_TYPE_HTML;
- nret = cli_scanhtml(desc, ctx);
+ nret = cli_scanhtml(ctx);
}
break;
case CL_TYPE_MAIL:
if(SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX))
- nret = cli_scanmail(desc, ctx);
+ nret = cli_scanmail(map->fd, ctx);
break;
default:
@@@ -1831,7 -1849,7 +1831,7 @@@
}
if(ret == CL_VIRUS)
- cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+ cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, map->fd);
return ret;
}
@@@ -1872,40 -1890,28 +1872,40 @@@ int cli_magic_scandesc(int desc, cli_ct
if(cli_updatelimits(ctx, sb.st_size)!=CL_CLEAN)
return CL_CLEAN;
+ ctx->fmap++;
+ if(!(*ctx->fmap = fmap(desc, 0, sb.st_size))) {
+ cli_errmsg("CRITICAL: fmap() failed\n");
+ return CL_EMEM;
+ }
+
if(!ctx->options || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
if(ctx->recursion == ctx->engine->maxreclevel)
cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
else
cli_dbgmsg("Raw mode: No support for special files\n");
- if((ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR)) == CL_VIRUS)
+ if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR)) == CL_VIRUS)
cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+ fmunmap(*ctx->fmap);
+ ctx->fmap--;
return ret;
}
- lseek(desc, 0, SEEK_SET);
- type = cli_filetype2(desc, ctx->engine);
+ type = cli_filetype2(*ctx->fmap, ctx->engine); /* FIXMEFMAP: port to fmap */
if(type == CL_TYPE_ERROR) {
cli_dbgmsg("cli_magic_scandesc: cli_filetype2 returned CL_TYPE_ERROR\n");
+ fmunmap(*ctx->fmap);
+ ctx->fmap--;
return CL_EREAD;
}
- lseek(desc, 0, SEEK_SET);
+ lseek(desc, 0, SEEK_SET); /* FIXMEFMAP: remove ? */
if(type != CL_TYPE_IGNORED && ctx->engine->sdb) {
- if((ret = cli_scanraw(desc, ctx, type, 0, &dettype)) == CL_VIRUS)
+ if((ret = cli_scanraw(ctx, type, 0, &dettype)) == CL_VIRUS) {
+ fmunmap(*ctx->fmap);
+ ctx->fmap--;
return CL_VIRUS;
- lseek(desc, 0, SEEK_SET);
+ }
+ lseek(desc, 0, SEEK_SET); /* FIXMEFMAP: remove ? */
}
ctx->container_type = 0;
@@@ -1921,12 -1927,12 +1921,12 @@@
case CL_TYPE_ZIP:
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
- ret = cli_unzip(desc, ctx);
+ ret = cli_unzip(ctx);
break;
case CL_TYPE_GZ:
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
- ret = cli_scangzip(desc, ctx);
+ ret = cli_scangzip(ctx);
break;
case CL_TYPE_BZ:
@@@ -1960,17 -1966,17 +1960,17 @@@
case CL_TYPE_HTML:
if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
- ret = cli_scanhtml(desc, ctx);
+ ret = cli_scanhtml(ctx);
break;
case CL_TYPE_HTML_UTF16:
if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
- ret = cli_scanhtml_utf16(desc, ctx);
+ ret = cli_scanhtml_utf16(ctx);
break;
case CL_TYPE_SCRIPT:
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
- ret = cli_scanscript(desc, ctx);
+ ret = cli_scanscript(ctx);
break;
case CL_TYPE_RTF:
@@@ -1990,7 -1996,7 +1990,7 @@@
case CL_TYPE_UUENCODED:
if(DCONF_OTHER & OTHER_CONF_UUENC)
- ret = cli_scanuuencoded(desc, ctx);
+ ret = cli_scanuuencoded(ctx);
break;
case CL_TYPE_MSCHM:
@@@ -2000,7 -2006,7 +2000,7 @@@
case CL_TYPE_MSOLE2:
if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
- ret = cli_scanole2(desc, ctx);
+ ret = cli_scanole2(ctx);
break;
case CL_TYPE_7Z:
@@@ -2040,7 -2046,7 +2040,7 @@@
case CL_TYPE_BINHEX:
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
- ret = cli_scanbinhex(desc, ctx);
+ ret = cli_scanbinhex(ctx);
break;
case CL_TYPE_SCRENC:
@@@ -2060,7 -2066,7 +2060,7 @@@
case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
- ret = cli_scanpdf(desc, ctx, 0);
+ ret = cli_scanpdf(ctx, 0);
break;
case CL_TYPE_CRYPTFF:
@@@ -2070,7 -2076,7 +2070,7 @@@
case CL_TYPE_ELF:
if(SCAN_ELF && ctx->dconf->elf)
- ret = cli_scanelf(desc, ctx);
+ ret = cli_scanelf(ctx);
break;
case CL_TYPE_MACHO:
@@@ -2107,11 -2113,8 +2107,11 @@@
ctx->recursion--;
ctx->container_type = current_container;
- if(ret == CL_VIRUS)
+ if(ret == CL_VIRUS) {
+ fmunmap(*ctx->fmap);
+ ctx->fmap--;
return CL_VIRUS;
+ }
if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
if(sb.st_size > 1048576) {
@@@ -2122,11 -2125,8 +2122,11 @@@
/* CL_TYPE_HTML: raw HTML files are not scanned, unless safety measure activated via DCONF */
if(type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb) {
- if(cli_scanraw(desc, ctx, type, typercg, &dettype) == CL_VIRUS)
+ if(cli_scanraw(ctx, type, typercg, &dettype) == CL_VIRUS) {
+ fmunmap(*ctx->fmap);
+ ctx->fmap--;
return CL_VIRUS;
+ }
}
ctx->recursion++;
@@@ -2137,24 -2137,24 +2137,26 @@@
case CL_TYPE_TEXT_UTF16LE:
case CL_TYPE_TEXT_UTF8:
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
- ret = cli_scanscript(desc, ctx);
+ ret = cli_scanscript(ctx);
- if(ret != CL_VIRUS && ctx->container_type == CL_TYPE_MAIL)
+ if(ret != CL_VIRUS && ctx->container_type == CL_TYPE_MAIL) {
+ lseek(desc, 0, SEEK_SET);
ret = cli_scandesc(desc, ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR);
+ }
break;
/* Due to performance reasons all executables were first scanned
* in raw mode. Now we will try to unpack them
*/
case CL_TYPE_MSEXE:
if(SCAN_PE && ctx->dconf->pe)
- ret = cli_scanpe(desc, ctx);
+ ret = cli_scanpe(ctx);
break;
default:
break;
}
ctx->recursion--;
+ fmunmap(*ctx->fmap);
+ ctx->fmap--;
switch(ret) {
case CL_EFORMAT:
@@@ -2181,15 -2181,8 +2183,15 @@@ int cl_scandesc(int desc, const char **
ctx.found_possibly_unwanted = 0;
ctx.container_type = 0;
ctx.dconf = (struct cli_dconf *) engine->dconf;
+ ctx.fmap = cli_calloc(sizeof(struct F_MAP *), ctx.engine->maxreclevel + 1);
+ if(!ctx.fmap)
+ return CL_EMEM;
+ ctx.fmap--;
rc = cli_magic_scandesc(desc, &ctx);
+
+ ctx.fmap++;
+ free(ctx.fmap);
if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
rc = CL_VIRUS;
return rc;
@@@ -2234,6 -2227,7 +2236,6 @@@ int cl_scanfile(const char *filename, c
{
int fd, ret;
-
if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
return CL_EOPEN;
diff --combined libclamav/unzip.c
index c532f33,de17bf9..2f9697e
--- a/libclamav/unzip.c
+++ b/libclamav/unzip.c
@@@ -35,6 -35,12 +35,6 @@@
#endif
#include <stdlib.h>
-#if HAVE_MMAP
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-#endif /* HAVE_MMAP */
-
#include <stdio.h>
#include <zlib.h>
@@@ -48,7 -54,6 +48,7 @@@
#include "clamav.h"
#include "scanners.h"
#include "matcher.h"
+#include "fmap.h"
#define UNZIP_PRIVATE
#include "unzip.h"
@@@ -62,6 -67,15 +62,6 @@@ static int wrap_inflateinit2(void *a, i
return inflateInit2(a, b);
}
-static inline void destroy_map(void *map, size_t fsize) {
-#if HAVE_MMAP
- munmap(map, fsize);
-#else
- free(map);
-#endif
-}
-
-
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;
@@@ -92,7 -106,7 +92,7 @@@
}
if(res==1) {
if(ctx->engine->maxfilesize && csize > ctx->engine->maxfilesize) {
- cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->engine->maxfilesize);
+ cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (long unsigned int) ctx->engine->maxfilesize);
csize = ctx->engine->maxfilesize;
}
if(cli_writen(of, src, csize)!=(int)csize) ret = CL_EWRITE;
@@@ -153,7 -167,7 +153,7 @@@
if(*avail_out!=sizeof(obuf)) {
written+=sizeof(obuf)-(*avail_out);
if(ctx->engine->maxfilesize && written > ctx->engine->maxfilesize) {
- cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->engine->maxfilesize);
+ cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (long unsigned int) ctx->engine->maxfilesize);
res = Z_STREAM_END;
break;
}
@@@ -197,7 -211,7 +197,7 @@@
if(strm.avail_out!=sizeof(obuf)) {
written+=sizeof(obuf)-strm.avail_out;
if(ctx->engine->maxfilesize && written > ctx->engine->maxfilesize) {
- cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->engine->maxfilesize);
+ cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (unsigned long int) ctx->engine->maxfilesize);
res = BZ_STREAM_END;
break;
}
@@@ -234,7 -248,7 +234,7 @@@
if(strm.avail_out!=sizeof(obuf)) {
written+=sizeof(obuf)-strm.avail_out;
if(ctx->engine->maxfilesize && written > ctx->engine->maxfilesize) {
- cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->engine->maxfilesize);
+ cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (unsigned long int) ctx->engine->maxfilesize);
res = 0;
break;
}
@@@ -303,39 -317,33 +303,39 @@@
return ret;
}
-static unsigned int lhdr(uint8_t *zip, uint32_t zsize, unsigned int *fu, unsigned int fc, uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd, int fd) {
- uint8_t *lh = zip;
+static unsigned int lhdr(struct F_MAP *map, uint32_t loff,uint32_t zsize, unsigned int *fu, unsigned int fc, uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd) {
+ uint8_t *lh, *zip;
char name[256];
uint32_t csize, usize;
struct cli_meta_node *meta = ctx->engine->zip_mlist;
- if(zsize<=SIZEOF_LH) {
- cli_dbgmsg("cli_unzip: lh - out of file\n");
- return 0;
+ if(!(lh = fmap_need_off(map, loff, SIZEOF_LH))) {
+ cli_dbgmsg("cli_unzip: lh - out of file\n");
+ return 0;
}
if(LH_magic != 0x04034b50) {
if (!ch) cli_dbgmsg("cli_unzip: lh - wrkcomplete\n");
else cli_dbgmsg("cli_unzip: lh - bad magic\n");
+ fmap_unneed_off(map, loff, SIZEOF_LH);
return 0;
}
- zip+=SIZEOF_LH;
+ zip = lh + SIZEOF_LH;
zsize-=SIZEOF_LH;
if(zsize<=LH_flen) {
cli_dbgmsg("cli_unzip: lh - fname out of file\n");
+ fmap_need_off(map, loff, SIZEOF_LH);
return 0;
}
if(meta || cli_debug_flag) {
- uint32_t nsize = (LH_flen>=sizeof(name))?sizeof(name)-1:LH_flen;
- memcpy(name, zip, nsize);
- name[nsize]='\0';
+ uint32_t nsize = (LH_flen>=sizeof(name))?sizeof(name)-1:LH_flen;
+ char *src;
+ if(nsize && (src = fmap_need_ptr_once(map, zip, nsize))) {
+ memcpy(name, zip, nsize);
+ name[nsize]='\0';
+ } else
+ name[0] = '\0';
}
zip+=LH_flen;
zsize-=LH_flen;
@@@ -356,20 -364,18 +356,20 @@@
)
) meta = meta->next;
if(meta) {
- if(!cli_checkfp(fd, ctx)) {
+ if(!cli_checkfp(map->fd, ctx)) {
*ctx->virname = meta->virname;
*ret = CL_VIRUS;
} else
*ret = CL_CLEAN;
+ fmap_need_off(map, loff, SIZEOF_LH);
return 0;
}
if(LH_flags & F_MSKED) {
cli_dbgmsg("cli_unzip: lh - header has got unusable masked data\n");
/* FIXME: need to find/craft a sample */
+ fmap_need_off(map, loff, SIZEOF_LH);
return 0;
}
@@@ -377,76 -383,63 +377,76 @@@
cli_dbgmsg("cli_unzip: Encrypted files found in archive.\n");
*ctx->virname = "Encrypted.Zip";
*ret = CL_VIRUS;
+ fmap_need_off(map, loff, SIZEOF_LH);
return 0;
}
if(LH_flags & F_USEDD) {
cli_dbgmsg("cli_unzip: lh - has data desc\n");
- if(!ch) return 0;
+ if(!ch) {
+ fmap_need_off(map, loff, SIZEOF_LH);
+ return 0;
+ }
else { usize = CH_usize; csize = CH_csize; }
} else { usize = LH_usize; csize = LH_csize; }
if(zsize<=LH_elen) {
cli_dbgmsg("cli_unzip: lh - extra out of file\n");
+ fmap_need_off(map, loff, SIZEOF_LH);
return 0;
}
zip+=LH_elen;
zsize-=LH_elen;
if (!csize) { /* FIXME: what's used for method0 files? csize or usize? Nothing in the specs, needs testing */
- cli_dbgmsg("cli_unzip: lh - skipping empty file\n");
+ cli_dbgmsg("cli_unzip: lh - skipping empty file\n");
} else {
- if(zsize<csize) {
- cli_dbgmsg("cli_unzip: lh - stream out of file\n");
- return 0;
- }
- if(LH_flags & F_ENCR) {
- cli_dbgmsg("cli_unzip: lh - skipping encrypted file\n");
- } else *ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd);
- zip+=csize;
- zsize-=csize;
+ if(zsize<csize) {
+ cli_dbgmsg("cli_unzip: lh - stream out of file\n");
+ fmap_need_off(map, loff, SIZEOF_LH);
+ return 0;
+ }
+ if(LH_flags & F_ENCR) {
+ cli_dbgmsg("cli_unzip: lh - skipping encrypted file\n");
+ } else {
+ if(fmap_need_ptr_once(map, zip, csize))
+ *ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd);
+ }
+ zip+=csize;
+ zsize-=csize;
}
+ fmap_need_off(map, loff, SIZEOF_LH); /* unneed now. block is guaranteed to exists till the next need */
if(LH_flags & F_USEDD) {
- if(zsize<12) {
- cli_dbgmsg("cli_unzip: lh - data desc out of file\n");
- return 0;
- }
- zsize-=12;
- if(cli_readint32(zip)==0x08074b50) {
- if(zsize<4) {
- cli_dbgmsg("cli_unzip: lh - data desc out of file\n");
- return 0;
+ if(zsize<12) {
+ cli_dbgmsg("cli_unzip: lh - data desc out of file\n");
+ return 0;
}
- zip+=4;
- }
- zip+=12;
+ zsize-=12;
+ if(fmap_need_ptr_once(map, zip, 4)) {
+ if(cli_readint32(zip)==0x08074b50) {
+ if(zsize<4) {
+ cli_dbgmsg("cli_unzip: lh - data desc out of file\n");
+ return 0;
+ }
+ zip+=4;
+ }
+ }
+ zip+=12;
}
return zip-lh;
}
-static unsigned int chdr(uint8_t *zip, uint32_t coff, uint32_t zsize, unsigned int *fu, unsigned int fc, int *ret, cli_ctx *ctx, char *tmpd, int fd) {
- uint8_t *ch = &zip[coff];
+static unsigned int chdr(struct F_MAP *map, uint32_t coff, uint32_t zsize, unsigned int *fu, unsigned int fc, int *ret, cli_ctx *ctx, char *tmpd) {
char name[256];
int last = 0;
+ int8_t *ch;
- if(zsize-coff<=SIZEOF_CH || CH_magic != 0x02014b50) {
- cli_dbgmsg("cli_unzip: ch - wrkcomplete\n");
- return 0;
+ if(!(ch = fmap_need_off(map, coff, SIZEOF_CH)) || CH_magic != 0x02014b50) {
+ if(ch) fmap_unneed_ptr(map, ch, SIZEOF_CH);
+ cli_dbgmsg("cli_unzip: ch - wrkcomplete\n");
+ return 0;
}
coff+=SIZEOF_CH;
@@@ -457,13 -450,10 +457,13 @@@
last=1;
}
if(cli_debug_flag && !last) {
- unsigned int size = (CH_flen>=sizeof(name))?sizeof(name)-1:CH_flen;
- memcpy(name, &zip[coff], size);
- name[size]='\0';
- cli_dbgmsg("cli_unzip: ch - fname: %s\n", name);
+ unsigned int size = (CH_flen>=sizeof(name))?sizeof(name)-1:CH_flen;
+ char *src = fmap_need_off_once(map, coff, size);
+ if(src) {
+ memcpy(name, src, size);
+ name[size]='\0';
+ cli_dbgmsg("cli_unzip: ch - fname: %s\n", name);
+ }
}
coff+=CH_flen;
@@@ -480,23 -470,27 +480,23 @@@
coff+=CH_clen;
if(CH_off<zsize-SIZEOF_LH) {
- lhdr(&zip[CH_off], zsize-CH_off, fu, fc, ch, ret, ctx, tmpd, fd);
+ lhdr(map, CH_off, zsize-CH_off, fu, fc, ch, ret, ctx, tmpd);
} else cli_dbgmsg("cli_unzip: ch - local hdr out of file\n");
+ fmap_unneed_ptr(map, ch, SIZEOF_CH);
return last?0:coff;
}
-int cli_unzip(int f, cli_ctx *ctx) {
+int cli_unzip(cli_ctx *ctx) {
unsigned int fc=0, fu=0;
int ret=CL_CLEAN;
uint32_t fsize, lhoff = 0, coff = 0;
- struct stat st;
- uint8_t *map;
- char *tmpd;
+ struct F_MAP *map = *ctx->fmap;
+ char *tmpd, *ptr;
cli_dbgmsg("in cli_unzip\n");
- if (fstat(f, &st)==-1) {
- cli_warnmsg("cli_unzip: fstat() failed\n");
- return CL_ESTAT;
- }
- fsize = (uint32_t)st.st_size;
- if(sizeof(off_t)!=sizeof(uint32_t) && (off_t)fsize!=st.st_size) {
+ fsize = (uint32_t)map->len;
+ if(sizeof(off_t)!=sizeof(uint32_t) && (off_t)fsize!=map->len) {
cli_dbgmsg("cli_unzip: file too big\n");
return CL_CLEAN;
}
@@@ -504,39 -498,59 +504,39 @@@
cli_dbgmsg("cli_unzip: file too short\n");
return CL_CLEAN;
}
-
-#if HAVE_MMAP
- if ((map = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, f, 0))==MAP_FAILED) {
- cli_dbgmsg("cli_unzip: mmap failed\n");
- return CL_EMAP;
- }
-#else
- if(fsize > CLI_MAX_ALLOCATION) {
- cli_warnmsg("cli_unzip: mmap not available and file is too big\n");
- return CL_CLEAN;
- }
- lseek(f, 0, SEEK_SET);
- if(!(map = cli_malloc(fsize)))
- return CL_EMEM;
- if(cli_readn(f, map, fsize)!=fsize) {
- free(map);
- return CL_EREAD;
- }
-#endif
-
if (!(tmpd = cli_gentemp(ctx->engine->tmpdir))) {
- destroy_map(map, fsize);
return CL_ETMPDIR;
}
if (mkdir(tmpd, 0700)) {
cli_dbgmsg("cli_unzip: Can't create temporary directory %s\n", tmpd);
- destroy_map(map, fsize);
free(tmpd);
return CL_ETMPDIR;
}
for(coff=fsize-22 ; coff>0 ; coff--) { /* sizeof(EOC)==22 */
- if(cli_readint32(&map[coff])==0x06054b50) {
- uint32_t chptr = cli_readint32(&map[coff+16]);
- if(!CLI_ISCONTAINED(map, fsize, map+chptr, SIZEOF_CH)) continue;
- coff=chptr;
- break;
- }
+ if(!(ptr = fmap_need_off_once(map, coff, 20)))
+ continue;
+ if(cli_readint32(ptr)==0x06054b50) {
+ uint32_t chptr = cli_readint32(&ptr[16]);
+ if(!CLI_ISCONTAINED(0, fsize, chptr, SIZEOF_CH)) continue;
+ coff=chptr;
+ break;
+ }
}
if(coff) {
- cli_dbgmsg("cli_unzip: central @%x\n", coff);
- while(ret==CL_CLEAN && (coff=chdr(map, coff, fsize, &fu, fc+1, &ret, ctx, tmpd, f))) {
- fc++;
- if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) {
- cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles);
- ret=CL_EMAXFILES;
+ cli_dbgmsg("cli_unzip: central @%x\n", coff);
+ while(ret==CL_CLEAN && (coff=chdr(map, coff, fsize, &fu, fc+1, &ret, ctx, tmpd))) {
+ fc++;
+ if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) {
+ cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles);
+ ret=CL_EMAXFILES;
+ }
}
} else cli_dbgmsg("cli_unzip: central not found, using localhdrs\n");
if(fu<=(fc/4)) { /* FIXME: make up a sane ratio or remove the whole logic */
fc = 0;
- while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(&map[lhoff], fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd, f))) {
+ while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(map, lhoff, fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd))) {
fc++;
lhoff+=coff;
if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) {
@@@ -546,21 -560,27 +546,21 @@@
}
}
- destroy_map(map, fsize);
if (!ctx->engine->keeptmp) cli_rmdirs(tmpd);
free(tmpd);
return ret;
}
-int cli_unzip_single(int f, cli_ctx *ctx, off_t lhoffl) {
+int cli_unzip_single(cli_ctx *ctx, off_t lhoffl) {
int ret=CL_CLEAN;
unsigned int fu=0;
- struct stat st;
uint32_t fsize;
- uint8_t *map;
+ struct F_MAP *map = *ctx->fmap;
cli_dbgmsg("in cli_unzip_single\n");
- if (fstat(f, &st)==-1) {
- cli_warnmsg("cli_unzip: fstat() failed\n");
- return CL_ESTAT;
- }
- fsize = (uint32_t)(st.st_size - lhoffl);
- if (lhoffl<0 || lhoffl>st.st_size || (sizeof(off_t)!=sizeof(uint32_t) && (off_t)fsize!=st.st_size - lhoffl)) {
+ fsize = (uint32_t)(map->len - lhoffl);
+ if (lhoffl<0 || lhoffl>map->len || (sizeof(off_t)!=sizeof(uint32_t) && (off_t)fsize!=map->len - lhoffl)) {
cli_dbgmsg("cli_unzip: bad offset\n");
return CL_CLEAN;
}
@@@ -569,7 -589,26 +569,7 @@@
return CL_CLEAN;
}
-#if HAVE_MMAP
- if ((map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0))==MAP_FAILED) {
- cli_dbgmsg("cli_unzip: mmap() failed\n");
- return CL_EMAP;
- }
-#else
- if(st.st_size > CLI_MAX_ALLOCATION) {
- cli_warnmsg("cli_unzip: mmap not available and file is too big\n");
- return CL_CLEAN;
- }
- lseek(f, 0, SEEK_SET);
- if(!(map = cli_malloc(st.st_size)))
- return CL_EMEM;
- if(cli_readn(f, map, st.st_size)!=st.st_size) {
- free(map);
- return CL_EREAD;
- }
-#endif
- lhdr(&map[lhoffl], fsize, &fu, 0, NULL, &ret, ctx, NULL, f);
+ lhdr(map, lhoffl, fsize, &fu, 0, NULL, &ret, ctx, NULL);
- destroy_map(map, st.st_size);
return ret;
}
--
Debian repository for ClamAV
More information about the Pkg-clamav-commits
mailing list