diff --git a/libclamav/cpio.c b/libclamav/cpio.c index 45e0c209d..3593d283d 100644 --- a/libclamav/cpio.c +++ b/libclamav/cpio.c @@ -157,7 +157,7 @@ int cli_scancpio_old(cli_ctx *ctx) if(ret == CL_EMAXFILES) { return ret; } else if(ret == CL_SUCCESS) { - ret = cli_dumpscan(*ctx->fmap, pos, filesize, ctx); + ret = cli_map_scandesc(*ctx->fmap, pos, filesize, ctx); if(ret == CL_VIRUS) return ret; } @@ -234,7 +234,7 @@ int cli_scancpio_odc(cli_ctx *ctx) if(ret == CL_EMAXFILES) { return ret; } else if(ret == CL_SUCCESS) { - ret = cli_dumpscan(*ctx->fmap, pos, filesize, ctx); + ret = cli_map_scandesc(*ctx->fmap, pos, filesize, ctx); if(ret == CL_VIRUS) return ret; } @@ -313,7 +313,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc) if(ret == CL_EMAXFILES) { return ret; } else if(ret == CL_SUCCESS) { - ret = cli_dumpscan(*ctx->fmap, pos, filesize, ctx); + ret = cli_map_scandesc(*ctx->fmap, pos, filesize, ctx); if(ret == CL_VIRUS) return ret; } diff --git a/libclamav/fmap.c b/libclamav/fmap.c index 767f2540e..33e5be384 100644 --- a/libclamav/fmap.c +++ b/libclamav/fmap.c @@ -257,7 +257,8 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len, m->pread_cb = pread_cb; m->aging = use_aging; m->offset = offset; - m->len = len; + m->len = len;/* m->nested_offset + m->len = m->real_len */ + m->real_len = len; m->pages = pages; m->hdrsz = hdrsz; m->pgsz = pgsz; @@ -451,8 +452,8 @@ static int fmap_readpage(fmap_t *m, unsigned int first_page, unsigned int count, pptr = (char *)m + page * m->pgsz + m->hdrsz; first_page = page; } - if((page == m->pages - 1) && (m->len % m->pgsz)) - readsz += m->len % m->pgsz; + if((page == m->pages - 1) && (m->real_len % m->pgsz)) + readsz += m->real_len % m->pgsz; else readsz += m->pgsz; if(lock) /* lock requested: set paged, lock page and set lock count to 1 */ @@ -472,7 +473,9 @@ static const void *handle_need(fmap_t *m, size_t at, size_t len, int lock) { if(!len) return NULL; - if(!CLI_ISCONTAINED(0, m->len, at, len)) + at += m->nested_offset; + + if(!CLI_ISCONTAINED(0, m->real_len, at, len)) return NULL; fmap_aging(m); @@ -519,7 +522,7 @@ static void handle_unneed_off(fmap_t *m, size_t at, size_t len) { return; } - if(!CLI_ISCONTAINED(0, m->len, at, len)) { + if(!CLI_ISCONTAINED(0, m->real_len, at, len)) { cli_warnmsg("fmap: attempted oof unneed\n"); return; } @@ -550,10 +553,10 @@ static const void *handle_need_offstr(fmap_t *m, size_t at, size_t len_hint) { unsigned int i, first_page, last_page; void *ptr = (void *)((char *)m + m->hdrsz + at); - if(!len_hint || len_hint > m->len - at) - len_hint = m->len - at; + if(!len_hint || len_hint > m->real_len - at) + len_hint = m->real_len - at; - if(!CLI_ISCONTAINED(0, m->len, at, len_hint)) + if(!CLI_ISCONTAINED(0, m->real_len, at, len_hint)) return NULL; fmap_aging(m); @@ -588,9 +591,9 @@ static const void *handle_need_offstr(fmap_t *m, size_t at, size_t len_hint) { static const void *handle_gets(fmap_t *m, char *dst, size_t *at, size_t max_len) { unsigned int i, first_page, last_page; char *src = (void *)((char *)m + m->hdrsz + *at), *endptr = NULL; - size_t len = MIN(max_len-1, m->len - *at), fullen = len; + size_t len = MIN(max_len-1, m->real_len - *at), fullen = len; - if(!len || !CLI_ISCONTAINED(0, m->len, *at, len)) + if(!len || !CLI_ISCONTAINED(0, m->real_len, *at, len)) return NULL; fmap_aging(m); @@ -650,6 +653,7 @@ extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len) } m->data = start; m->len = len; + m->real_len = len; m->pgsz = pgsz; m->pages = fmap_align_items(len, pgsz); m->unmap = unmap_none; @@ -665,7 +669,8 @@ static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock) { /* WIN if(!len) { return NULL; } - if(!CLI_ISCONTAINED(0, m->len, at, len)) { + at += m->nested_offset; + if(!CLI_ISCONTAINED(0, m->real_len, at, len)) { return NULL; } @@ -677,10 +682,10 @@ static void mem_unneed_off(fmap_t *m, size_t at, size_t len) {} static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint) { char *ptr = (char *)m->data + at; - if(!len_hint || len_hint > m->len - at) - len_hint = m->len - at; + if(!len_hint || len_hint > m->real_len - at) + len_hint = m->real_len - at; - if(!CLI_ISCONTAINED(0, m->len, at, len_hint)) + if(!CLI_ISCONTAINED(0, m->real_len, at, len_hint)) return NULL; if(memchr(ptr, 0, len_hint)) @@ -690,9 +695,9 @@ static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint) { static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len) { char *src = (char *)m->data + *at, *endptr = NULL; - size_t len = MIN(max_len-1, m->len - *at); + size_t len = MIN(max_len-1, m->real_len - *at); - if(!len || !CLI_ISCONTAINED(0, m->len, *at, len)) + if(!len || !CLI_ISCONTAINED(0, m->real_len, *at, len)) return NULL; if((endptr = memchr(src, '\n', len))) { diff --git a/libclamav/fmap.h b/libclamav/fmap.h index a47992704..ef72655be 100644 --- a/libclamav/fmap.h +++ b/libclamav/fmap.h @@ -52,8 +52,18 @@ struct cl_fmap { const void *data; /* common interface */ - size_t offset; - size_t len; + size_t offset;/* file offset */ + size_t nested_offset;/* buffer offset for nested scan*/ + size_t real_len;/* amount of data mapped from file, starting at offset */ + size_t len;/* length of data accessible via current fmap */ + + /* real_len = nested_offset + len + * file_offset = offset + nested_offset + need_offset + * maximum offset, length accessible via fmap API: len + * offset in cached buffer: nested_offset + need_offset + * + * This allows to scan a portion of an already mapped file without dumping + * to disk and remapping (for uncompressed archives for example) */ /* vtable for implementation */ void (*unmap)(fmap_t*); diff --git a/libclamav/macho.c b/libclamav/macho.c index c83d5a6b5..1c592b3a8 100644 --- a/libclamav/macho.c +++ b/libclamav/macho.c @@ -552,7 +552,7 @@ int cli_scanmacho_unibin(cli_ctx *ctx) cli_dbgmsg("UNIBIN: Binary %u of %u\n", i + 1, fat_header.nfats); cli_dbgmsg("UNIBIN: File offset: %u\n", fat_arch.offset); cli_dbgmsg("UNIBIN: File size: %u\n", fat_arch.size); - ret = cli_dumpscan(map, fat_arch.offset, fat_arch.size, ctx); + ret = cli_map_scandesc(map, fat_arch.offset, fat_arch.size, ctx); if(ret == CL_VIRUS) break; } diff --git a/libclamav/others.c b/libclamav/others.c index 4e5fe21f0..b96a474c5 100644 --- a/libclamav/others.c +++ b/libclamav/others.c @@ -915,60 +915,6 @@ int cli_rmdirs(const char *dirname) } #endif -int cli_dumpscan(fmap_t *map, off_t offset, size_t size, cli_ctx *ctx) -{ - int newfd, sum = 0, ret; - ssize_t bread; - char *name; - const char *buff; - - if(!(name = cli_gentemp(ctx->engine->tmpdir))) - return CL_EMEM; - - if((newfd = open(name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL, S_IRWXU)) < 0) { - cli_errmsg("cli_dumpscan: Can't create file %s\n", name); - free(name); - return CL_ECREAT; - } - - while (( buff = fmap_need_off_once_len(map, offset, FILEBUFF, &bread) )) { - offset += bread; - if((uint32_t) (sum + bread) >= size) { - if(cli_writen(newfd, buff, size - sum) == -1) { - cli_errmsg("cli_dumpscan: Can't write to %s\n", name); - close(newfd); - cli_unlink(name); - free(name); - return CL_EWRITE; - } - break; - } else { - if(cli_writen(newfd, buff, bread) == -1) { - cli_errmsg("cli_dumpscan: Can't write to %s\n", name); - close(newfd); - cli_unlink(name); - free(name); - return CL_EWRITE; - } - } - sum += bread; - } - cli_dbgmsg("DUMP&SCAN: File extracted to %s\n", name); - lseek(newfd, 0, SEEK_SET); - if((ret = cli_magic_scandesc(newfd, ctx)) == CL_VIRUS) - cli_dbgmsg("cli_dumpscan: Infected with %s\n", *ctx->virname); - - close(newfd); - if(!ctx->engine->keeptmp) { - if(cli_unlink(name)) { - free(name); - return CL_EUNLINK; - } - } - free(name); - return ret; -} - /* Implement a generic bitset, trog@clamav.net */ #define BITS_PER_CHAR (8) diff --git a/libclamav/others.h b/libclamav/others.h index 16d4e60aa..a8d3a6df5 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -522,7 +522,7 @@ char *cli_gentemp(const char *dir); int cli_gentempfd(const char *dir, char **name, int *fd); unsigned int cli_rndnum(unsigned int max); int cli_filecopy(const char *src, const char *dest); -int cli_dumpscan(fmap_t *map, off_t offset, size_t size, cli_ctx *ctx); +int cli_mapscan(fmap_t *map, off_t offset, size_t size, cli_ctx *ctx); bitset_t *cli_bitset_init(void); void cli_bitset_free(bitset_t *bs); int cli_bitset_set(bitset_t *bs, unsigned long bit_offset); diff --git a/libclamav/scanners.c b/libclamav/scanners.c index 546da9c30..fd76eb132 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -2537,20 +2537,48 @@ int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, cons return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL); } -static int cli_map_scandesc(cl_fmap_t *map, cli_ctx *ctx) +/* length = 0, till the end */ +int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx) { + off_t old_off = map->nested_offset; + size_t old_len = map->len; int ret; - if (map->len <= 5) { - cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) map->len); + cli_dbgmsg("cli_map_scandesc: [%ld, +%ld), [%ld, +%ld)\n", + old_off, old_len, offset, length); + if (offset < 0 || offset >= length) { + cli_dbgmsg("Invalid offset: %ld\n", (long)offset); + return CL_CLEAN; + } + + if (!length) length = old_len - offset; + if (length > old_len - offset) { + cli_dbgmsg("Data truncated: %ld -> %ld\n", + length, old_len - offset); + length = old_len - offset; + } + + if (length <= 5) { + cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) length); return CL_CLEAN; } ctx->fmap++; *ctx->fmap = map; - - ret = magic_scandesc(ctx, CL_TYPE_ANY); + /* can't change offset because then we'd have to discard/move cached + * data, instead use another offset to reuse the already cached data */ + map->nested_offset += offset; + map->len = length; + map->real_len = map->nested_offset + length; + if (CLI_ISCONTAINED(old_off, old_len, map->nested_offset, map->len)) { + ret = magic_scandesc(ctx, CL_TYPE_ANY); + } else { + cli_warnmsg("internal map error: %ld, %ld; %ld, %ld\n", old_off, old_off + old_len, + map->offset,map->nested_offset+map->len); + } ctx->fmap--; + map->nested_offset = old_off; + map->len = old_len; return ret; } @@ -2594,7 +2622,7 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned #endif cli_logg_setup(&ctx); - rc = map ? cli_map_scandesc(map, &ctx) : cli_magic_scandesc(desc, &ctx); + rc = map ? cli_map_scandesc(map, 0, map->len, &ctx) : cli_magic_scandesc(desc, &ctx); cli_bitset_free(ctx.hook_lsig_matches); free(ctx.fmap); diff --git a/libclamav/scanners.h b/libclamav/scanners.h index ee0f07313..1804f8e5a 100644 --- a/libclamav/scanners.h +++ b/libclamav/scanners.h @@ -27,6 +27,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx); int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type); +int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx); int cli_found_possibly_unwanted(cli_ctx* ctx); #endif diff --git a/libclamav/swf.c b/libclamav/swf.c index cf73329c1..0d5a3ae1a 100644 --- a/libclamav/swf.c +++ b/libclamav/swf.c @@ -242,22 +242,12 @@ static const char *tagname(tag_id id) static int dumpscan(fmap_t *map, unsigned int offset, unsigned int size, const char *obj, int version, cli_ctx *ctx) { - int newfd, ret = CL_CLEAN; - unsigned int bread, sum = 0; - char buff[FILEBUFF]; - char *name; + int ret = CL_CLEAN; + char buff[16]; - if(!(name = cli_gentemp(ctx->engine->tmpdir))) - return CL_EMEM; - - if((newfd = open(name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { - cli_errmsg("dumpscan: Can't create file %s\n", name); - free(name); - return CL_ECREAT; - } - - while((bread = fmap_readn(map, buff, offset, sizeof(buff))) > 0) { - if(!sum && ctx->img_validate) { + memset(buff, 0, sizeof(buff)); + fmap_readn(map, buff, offset, sizeof(buff)); + if(ctx->img_validate) { if(!memcmp(buff, "\xff\xd8", 2)) { cli_dbgmsg("SWF: JPEG image data\n"); } else if(!memcmp(buff, "\xff\xd9\xff\xd8", 4)) { @@ -284,46 +274,10 @@ static int dumpscan(fmap_t *map, unsigned int offset, unsigned int size, const c ret = CL_VIRUS; } if(ret == CL_VIRUS) { - close(newfd); - cli_unlink(name); - free(name); return ret; } - } - if(sum + bread >= size) { - if(cli_writen(newfd, buff, size - sum) == -1) { - cli_errmsg("dumpscan: Can't write to %s\n", name); - close(newfd); - cli_unlink(name); - free(name); - return CL_EWRITE; - } - break; - } else { - if(cli_writen(newfd, buff, bread) == -1) { - cli_errmsg("cli_dumpscan: Can't write to %s\n", name); - close(newfd); - cli_unlink(name); - free(name); - return CL_EWRITE; - } - } - sum += bread; - offset += bread; } - cli_dbgmsg("SWF: %s data extracted to %s\n", obj, name); - lseek(newfd, 0, SEEK_SET); - if((ret = cli_magic_scandesc(newfd, ctx)) == CL_VIRUS) - cli_dbgmsg("cli_dumpscan: Infected with %s\n", *ctx->virname); - - close(newfd); - if(!ctx->engine->keeptmp) { - if(cli_unlink(name)) { - free(name); - return CL_EUNLINK; - } - } - free(name); + ret = cli_map_scandesc(map, offset, size, ctx); if(ctx->img_validate && ret == CL_EPARSE && SCAN_ALGO) { *ctx->virname = "Heuristics.SWF.SuspectImage.E"; return CL_VIRUS;