diff --git a/libclamav/apm.c b/libclamav/apm.c index e3499e8a8..3b9b50101 100644 --- a/libclamav/apm.c +++ b/libclamav/apm.c @@ -53,7 +53,7 @@ int cli_scanapm(cli_ctx *ctx) struct apm_partition_info aptable, apentry; int ret = CL_CLEAN, detection = CL_CLEAN, old_school = 0; size_t sectorsize, maplen, partsize; - off_t pos = 0, partoff = 0; + size_t pos = 0, partoff = 0; unsigned i; uint32_t max_prtns = 0; @@ -219,8 +219,8 @@ int cli_scanapm(cli_ctx *ctx) cli_dbgmsg("Type: %s\n", (char *)apentry.type); cli_dbgmsg("Signature: %x\n", apentry.signature); cli_dbgmsg("Partition Count: %u\n", apentry.numPartitions); - cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n", - apentry.pBlockStart, apentry.pBlockCount, (long unsigned)partoff, (long unsigned)partsize); + cli_dbgmsg("Blocks: [%u, +%u), ([%zu, +%zu))\n", + apentry.pBlockStart, apentry.pBlockCount, partoff, partsize); /* send the partition to cli_magic_scan_nested_fmap_type */ ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, (const char *)apentry.name); @@ -245,7 +245,7 @@ static int apm_partition_intersection(cli_ctx *ctx, struct apm_partition_info *a struct apm_partition_info apentry; unsigned i, pitxn; int ret = CL_CLEAN, tmp = CL_CLEAN; - off_t pos; + size_t pos; uint32_t max_prtns = 0; int virus_found = 0; diff --git a/libclamav/cpio.c b/libclamav/cpio.c index b6f994615..7aee23140 100644 --- a/libclamav/cpio.c +++ b/libclamav/cpio.c @@ -103,7 +103,7 @@ int cli_scancpio_old(cli_ctx *ctx) unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize; int ret = CL_CLEAN, conv; - off_t pos = 0; + size_t pos = 0; int virus_found = 0; memset(name, 0, sizeof(name)); @@ -195,7 +195,7 @@ int cli_scancpio_odc(cli_ctx *ctx) unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize; int ret = CL_CLEAN; - off_t pos = 0; + size_t pos = 0; int virus_found = 0; while (fmap_readn(*ctx->fmap, &hdr_odc, pos, sizeof(hdr_odc)) == sizeof(hdr_odc)) { @@ -281,7 +281,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc) unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize, pad; int ret = CL_CLEAN; - off_t pos = 0; + size_t pos = 0; int virus_found = 0; memset(name, 0, 513); diff --git a/libclamav/dmg.c b/libclamav/dmg.c index dd02da2f8..fd9f22166 100644 --- a/libclamav/dmg.c +++ b/libclamav/dmg.c @@ -97,7 +97,7 @@ int cli_scandmg(cli_ctx *ctx) struct dmg_koly_block hdr; int ret; size_t maplen, nread; - off_t pos = 0; + size_t pos = 0; char *dirname; const char *outdata; unsigned int file = 0; @@ -114,11 +114,11 @@ int cli_scandmg(cli_ctx *ctx) } maplen = (*ctx->fmap)->real_len; - pos = maplen - 512; - if (pos <= 0) { - cli_dbgmsg("cli_scandmg: Sizing problem for DMG archive.\n"); + if (maplen <= 512) { + cli_dbgmsg("cli_scandmg: DMG smaller than DMG koly block!\n"); return CL_CLEAN; } + pos = maplen - 512; /* Grab koly block */ if (fmap_readn(*ctx->fmap, &hdr, pos, sizeof(hdr)) != sizeof(hdr)) { @@ -129,7 +129,7 @@ int cli_scandmg(cli_ctx *ctx) /* Check magic */ hdr.magic = be32_to_host(hdr.magic); if (hdr.magic == 0x6b6f6c79) { - cli_dbgmsg("cli_scandmg: Found koly block @ %ld\n", (long)pos); + cli_dbgmsg("cli_scandmg: Found koly block @ %zu\n", pos); } else { cli_dbgmsg("cli_scandmg: No koly magic, %8x\n", hdr.magic); return CL_EFORMAT; @@ -179,7 +179,7 @@ int cli_scandmg(cli_ctx *ctx) } /* scan XML with cli_magic_scan_nested_fmap_type */ - ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, (off_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, (size_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx, CL_TYPE_ANY, NULL); if (ret != CL_CLEAN) { cli_dbgmsg("cli_scandmg: retcode from scanning TOC xml: %s\n", cl_strerror(ret)); if (!ctx->engine->keeptmp) @@ -844,7 +844,7 @@ static int dmg_stripe_inflate(cli_ctx *ctx, int fd, uint32_t index, struct dmg_m } if (strm.avail_out != sizeof(obuf)) { - if (cli_writen(fd, obuf, sizeof(obuf) - strm.avail_out) < 0) { + if (cli_writen(fd, obuf, sizeof(obuf) - strm.avail_out) == (size_t)-1) { cli_errmsg("dmg_stripe_inflate: failed write to output file\n"); inflateEnd(&strm); return CL_EWRITE; diff --git a/libclamav/fmap.c b/libclamav/fmap.c index 06ef1b039..a5376ce3a 100644 --- a/libclamav/fmap.c +++ b/libclamav/fmap.c @@ -111,8 +111,7 @@ static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset) fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name) { STATBUF st; - fmap_t *m = NULL; - unsigned char hash[16] = {'\0'}; + fmap_t *m = NULL; *empty = 0; if (FSTAT(fd, &st)) { @@ -133,15 +132,7 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha m = cl_fmap_open_handle((void *)(ssize_t)fd, offset, len, pread_cb, 1); if (!m) return NULL; - m->mtime = st.st_mtime; - m->handle_is_fd = 1; - - /* Calculate the fmap hash to be used by the FP check later */ - if (CL_SUCCESS != fmap_get_MD5(hash, m)) { - funmap(m); - return NULL; - } - memcpy(m->maphash, hash, 16); + m->mtime = st.st_mtime; if (NULL != name) { m->name = cli_strdup(name); @@ -180,7 +171,6 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha const void *data; HANDLE fh; HANDLE mh; - unsigned char hash[16] = {'\0'}; *empty = 0; if (FSTAT(fd, &st)) { @@ -224,18 +214,11 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha return NULL; } m->handle = (void *)(size_t)fd; - m->handle_is_fd = 1; + m->handle_is_fd = 1; /* This is probably(?) needed so `fmap_fd()` can return the file descriptor. */ m->fh = fh; m->mh = mh; m->unmap = unmap_win32; - /* Calculate the fmap hash to be used by the FP check later */ - if (CL_SUCCESS != fmap_get_MD5(hash, m)) { - funmap(m); - return NULL; - } - memcpy(m->maphash, hash, 16); - if (NULL != name) { m->name = cli_strdup(name); if (NULL == m->name) { @@ -250,11 +233,15 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha /* vvvvv SHARED STUFF BELOW vvvvv */ -fmap_t *fmap_duplicate(cl_fmap_t *map, off_t offset, size_t length, const char *name) +fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char *name) { cl_error_t status = CL_ERROR; cl_fmap_t *duplicate_map = NULL; - unsigned char hash[16] = {'\0'}; + + if (NULL == map) { + cli_warnmsg("fmap_duplicate: map is NULL!\n"); + goto done; + } duplicate_map = cli_malloc(sizeof(cl_fmap_t)); if (!duplicate_map) { @@ -265,31 +252,39 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, off_t offset, size_t length, const char * /* Duplicate the state of the original map */ memcpy(duplicate_map, map, sizeof(cl_fmap_t)); - /* Set the new offset and length for the new map */ - /* can't change offset because then we'd have to discard/move cached - * data, instead use another offset to reuse the already cached data */ - duplicate_map->nested_offset += offset; - duplicate_map->len = length; - duplicate_map->real_len = duplicate_map->nested_offset + length; - - if (!CLI_ISCONTAINED(map->nested_offset, map->len, - duplicate_map->nested_offset, duplicate_map->len)) { - uint64_t len1, len2; - len1 = map->nested_offset + map->len; - len2 = duplicate_map->nested_offset + duplicate_map->len; - cli_warnmsg("fmap_duplicate: internal map error: %zu, " STDu64 "; %zu, " STDu64 "\n", - (size_t)map->nested_offset, - (uint64_t)len1, - (size_t)duplicate_map->offset, - (uint64_t)len2); - } - - /* Calculate the fmap hash to be used by the FP check later */ - if (CL_SUCCESS != fmap_get_MD5(hash, duplicate_map)) { - cli_warnmsg("fmap_duplicate: failed to get fmap MD5\n"); + if (offset > map->len) { + /* invalid offset, exceeds length of map */ + cli_warnmsg("fmap_duplicate: requested offset exceeds end of map\n"); goto done; } - memcpy(duplicate_map->maphash, hash, 16); + + if (offset > 0 || length < map->len) { + /* Caller requested a window into the current map, not the whole map */ + unsigned char hash[16] = {'\0'}; + + /* Set the new nested offset and (nested) length for the new map */ + /* can't change offset because then we'd have to discard/move cached + * data, instead use nested_offset to reuse the already cached data */ + duplicate_map->nested_offset += offset; + duplicate_map->len = MIN(length, map->len - offset); + + if (!CLI_ISCONTAINED2(map->nested_offset, map->len, + duplicate_map->nested_offset, duplicate_map->len)) { + size_t len1, len2; + len1 = map->nested_offset + map->len; + len2 = duplicate_map->nested_offset + duplicate_map->len; + cli_warnmsg("fmap_duplicate: internal map error: %zu, %zu; %zu, %zu\n", + map->nested_offset, len1, + duplicate_map->offset, len2); + } + + /* Calculate the fmap hash to be used by the FP check later */ + if (CL_SUCCESS != fmap_get_MD5(hash, duplicate_map)) { + cli_warnmsg("fmap_duplicate: failed to get fmap MD5\n"); + goto done; + } + memcpy(duplicate_map->maphash, hash, 16); + } if (NULL != name) { duplicate_map->name = cli_strdup(name); @@ -356,6 +351,8 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len, cl_fmap_t *m = NULL; int pgsz = cli_getpagesize(); + unsigned char hash[16] = {'\0'}; + if ((off_t)offset < 0 || offset != fmap_align_to(offset, pgsz)) { cli_warnmsg("fmap: attempted mapping with unaligned offset\n"); goto done; @@ -429,6 +426,14 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len, m->need_offstr = handle_need_offstr; m->gets = handle_gets; m->unneed_off = handle_unneed_off; + m->handle_is_fd = 1; + + /* Calculate the fmap hash to be used by the FP check later */ + if (CL_SUCCESS != fmap_get_MD5(hash, m)) { + cli_warnmsg("fmap: failed to get MD5\n"); + goto done; + } + memcpy(m->maphash, hash, 16); status = CL_SUCCESS; @@ -828,6 +833,8 @@ static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len); fmap_t *fmap_open_memory(const void *start, size_t len, const char *name) { + unsigned char hash[16] = {'\0'}; + int pgsz = cli_getpagesize(); cl_fmap_t *m = cli_calloc(1, sizeof(*m)); if (!m) { @@ -853,6 +860,16 @@ fmap_t *fmap_open_memory(const void *start, size_t len, const char *name) } } + /* Calculate the fmap hash to be used by the FP check later */ + if (CL_SUCCESS != fmap_get_MD5(hash, m)) { + if (NULL != m->name) { + free(m->name); + } + free(m); + return NULL; + } + memcpy(m->maphash, hash, 16); + return m; } diff --git a/libclamav/fmap.h b/libclamav/fmap.h index d79d0a98c..580e597ec 100644 --- a/libclamav/fmap.h +++ b/libclamav/fmap.h @@ -130,7 +130,7 @@ fmap_t *fmap_open_memory(const void *start, size_t len, const char *name); * @param name (optional) Original name of the file (to set fmap name metadata) * @return fmap_t* NULL if failure or a special fmap that the caller must free with free_duplicate_fmap() */ -fmap_t *fmap_duplicate(cl_fmap_t *map, off_t offset, size_t length, const char *name); +fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char *name); /** * @brief Deallocate a _duplicated_ fmap. Does not unmap the mapped region. diff --git a/libclamav/gif.c b/libclamav/gif.c index d0ebfc0dd..df67825ee 100644 --- a/libclamav/gif.c +++ b/libclamav/gif.c @@ -222,7 +222,7 @@ cl_error_t cli_parsegif(cli_ctx *ctx) if (screen_desc.flags & GIF_SCREEN_DESC_FLAGS_MASK_HAVE_GLOBAL_COLOR_TABLE) { global_color_table_size = 3 * (1 << ((screen_desc.flags & GIF_SCREEN_DESC_FLAGS_MASK_SIZE_OF_GLOBAL_COLOR_TABLE) + 1)); - cli_dbgmsg("GIF: Global Color Table size: %u\n", global_color_table_size); + cli_dbgmsg("GIF: Global Color Table size: %zu\n", global_color_table_size); if (offset + (size_t)global_color_table_size > map->len) { cli_errmsg("GIF: EOF in the middle of the global color table, file truncated?\n"); @@ -349,7 +349,7 @@ cl_error_t cli_parsegif(cli_ctx *ctx) if (image_desc.flags & GIF_IMAGE_DESC_FLAGS_MASK_HAVE_LOCAL_COLOR_TABLE) { local_color_table_size = 3 * (1 << ((image_desc.flags & GIF_IMAGE_DESC_FLAGS_MASK_SIZE_OF_LOCAL_COLOR_TABLE) + 1)); - cli_dbgmsg("GIF: Found a Local Color Table (size: %u)\n", local_color_table_size); + cli_dbgmsg("GIF: Found a Local Color Table (size: %zu)\n", local_color_table_size); offset += local_color_table_size; } else { cli_dbgmsg("GIF: No Local Color Table.\n"); diff --git a/libclamav/gpt.c b/libclamav/gpt.c index dfb820801..ed6aeefc0 100644 --- a/libclamav/gpt.c +++ b/libclamav/gpt.c @@ -262,7 +262,7 @@ static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t secto struct gpt_partition_entry gpe; int ret = CL_CLEAN, detection = CL_CLEAN; size_t maplen, part_size = 0; - off_t pos = 0, part_off = 0; + size_t pos = 0, part_off = 0; unsigned i = 0, j = 0; uint32_t max_prtns = 0; @@ -482,7 +482,7 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto static int gpt_check_mbr(cli_ctx *ctx, size_t sectorsize) { struct mbr_boot_record pmbr; - off_t pos = 0, mbr_base = 0; + size_t pos = 0, mbr_base = 0; int ret = CL_CLEAN; unsigned i = 0; @@ -533,7 +533,7 @@ static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize) { #ifdef DEBUG_GPT_PARSE struct gpt_header phdr, shdr; - off_t ppos = 0, spos = 0; + size_t ppos = 0, spos = 0; size_t pptable_len, sptable_len, maplen; uint64_t ptableLastLBA, stableLastLBA; @@ -586,7 +586,7 @@ static int gpt_partition_intersection(cli_ctx *ctx, struct gpt_header hdr, size_ struct gpt_partition_entry gpe; unsigned i, pitxn; int ret = CL_CLEAN, tmp = CL_CLEAN; - off_t pos; + size_t pos; size_t maplen; uint32_t max_prtns = 0; int virus_found = 0; diff --git a/libclamav/ishield.c b/libclamav/ishield.c index 88790a263..425975b60 100644 --- a/libclamav/ishield.c +++ b/libclamav/ishield.c @@ -773,7 +773,7 @@ static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t cs zret = inflate(&z, 0); if (zret == Z_OK || zret == Z_STREAM_END || zret == Z_BUF_ERROR) { unsigned int umpd = IS_CABBUFSZ - z.avail_out; - if (cli_writen(ofd, outbuf, umpd) < umpd) + if (cli_writen(ofd, outbuf, umpd) != umpd) break; outsz += umpd; if (zret == Z_STREAM_END || z.avail_out == IS_CABBUFSZ /* FIXMEISHIELD: is the latter ok? */) { diff --git a/libclamav/jpeg.c b/libclamav/jpeg.c index 7fdfe4bba..0eb34c188 100644 --- a/libclamav/jpeg.c +++ b/libclamav/jpeg.c @@ -252,15 +252,15 @@ typedef enum { // clang-format on -static cl_error_t jpeg_check_photoshop_8bim(cli_ctx *ctx, off_t *off) +static cl_error_t jpeg_check_photoshop_8bim(cli_ctx *ctx, size_t *off) { cl_error_t retval; const unsigned char *buf; uint16_t ntmp; uint8_t nlength, id[2]; uint32_t size; - off_t offset = *off; - fmap_t *map = *ctx->fmap; + size_t offset = *off; + fmap_t *map = *ctx->fmap; if (!(buf = fmap_need_off_once(map, offset, 4 + 2 + 1))) { cli_dbgmsg("read bim failed\n"); @@ -577,8 +577,8 @@ cl_error_t cli_parsejpeg(cli_ctx *ctx) if ((fmap_readn(map, buff, offset - len + sizeof(len_u16), strlen("Photoshop 3.0") + 1) == strlen("Photoshop 3.0") + 1) && (0 == memcmp(buff, "Photoshop 3.0\0", strlen("Photoshop 3.0") + 1))) { /* Found a Photoshop file */ - off_t photoshop_data_offset = offset - len + sizeof(len_u16) + strlen("Photoshop 3.0") + 1; - off_t old_offset; + size_t photoshop_data_offset = offset - len + sizeof(len_u16) + strlen("Photoshop 3.0") + 1; + size_t old_offset; cli_dbgmsg("Found Photoshop segment\n"); do { diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map index 98093c22a..e51d0cc68 100644 --- a/libclamav/libclamav.map +++ b/libclamav/libclamav.map @@ -263,6 +263,8 @@ CLAMAV_PRIVATE { cli_realpath; cli_codepage_to_utf8; cli_get_filepath_from_filedesc; + fmap_duplicate; + free_duplicate_fmap; __cli_strcasestr; __cli_strndup; diff --git a/libclamav/mbr.c b/libclamav/mbr.c index a9480165e..26ff25166 100644 --- a/libclamav/mbr.c +++ b/libclamav/mbr.c @@ -64,17 +64,17 @@ enum MBR_STATE { SEEN_EMPTY }; -static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, +static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extlba, size_t extlbasize, size_t sectorsize); static int mbr_check_mbr(struct mbr_boot_record *record, size_t maplen, size_t sectorsize); static int mbr_check_ebr(struct mbr_boot_record *record); static int mbr_primary_partition_intersection(cli_ctx *ctx, struct mbr_boot_record mbr, size_t sectorsize); -static int mbr_extended_partition_intersection(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t sectorsize); +static int mbr_extended_partition_intersection(cli_ctx *ctx, unsigned *prtncount, size_t extlba, size_t sectorsize); int cli_mbr_check(const unsigned char *buff, size_t len, size_t maplen) { struct mbr_boot_record mbr; - off_t mbr_base = 0; + size_t mbr_base = 0; size_t sectorsize = 512; if (len < sectorsize) { @@ -94,7 +94,7 @@ int cli_mbr_check(const unsigned char *buff, size_t len, size_t maplen) int cli_mbr_check2(cli_ctx *ctx, size_t sectorsize) { struct mbr_boot_record mbr; - off_t pos = 0, mbr_base = 0; + size_t pos = 0, mbr_base = 0; size_t maplen; if (!ctx || !ctx->fmap) { @@ -140,7 +140,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize) struct mbr_boot_record mbr; enum MBR_STATE state = SEEN_NOTHING; int ret = CL_CLEAN, detection = CL_CLEAN; - off_t pos = 0, mbr_base = 0, partoff = 0; + size_t pos = 0, mbr_base = 0, partoff = 0; unsigned i = 0, prtncount = 0; size_t maplen, partsize; @@ -210,10 +210,10 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize) cli_dbgmsg("MBR Partition Entry %u:\n", i); cli_dbgmsg("Status: %u\n", mbr.entries[i].status); cli_dbgmsg("Type: %x\n", mbr.entries[i].type); - cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n", + cli_dbgmsg("Blocks: [%u, +%u), ([%zu, +%zu))\n", mbr.entries[i].firstLBA, mbr.entries[i].numLBA, - (unsigned long)(mbr.entries[i].firstLBA * sectorsize), - (unsigned long)(mbr.entries[i].numLBA * sectorsize)); + mbr.entries[i].firstLBA * sectorsize, + mbr.entries[i].numLBA * sectorsize); /* Handle MBR entry based on type */ if (mbr.entries[i].type == MBR_EMPTY) { @@ -257,12 +257,12 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize) return detection; } -static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t extlbasize, size_t sectorsize) +static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extlba, size_t extlbasize, size_t sectorsize) { struct mbr_boot_record ebr; enum MBR_STATE state = SEEN_NOTHING; int ret = CL_CLEAN, detection = CL_CLEAN; - off_t pos = 0, mbr_base = 0, logiclba = 0, extoff = 0, partoff = 0; + size_t pos = 0, mbr_base = 0, logiclba = 0, extoff = 0, partoff = 0; size_t partsize, extsize; unsigned i = 0, j = 0; @@ -424,7 +424,7 @@ void mbr_convert_to_host(struct mbr_boot_record *record) static int mbr_check_mbr(struct mbr_boot_record *record, size_t maplen, size_t sectorsize) { unsigned i = 0; - off_t partoff = 0; + size_t partoff = 0; size_t partsize = 0; for (i = 0; i < MBR_MAX_PARTITION_ENTRIES; ++i) { @@ -540,13 +540,13 @@ leave: } /* checks internal logical partitions */ -static int mbr_extended_partition_intersection(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t sectorsize) +static int mbr_extended_partition_intersection(cli_ctx *ctx, unsigned *prtncount, size_t extlba, size_t sectorsize) { struct mbr_boot_record ebr; partition_intersection_list_t prtncheck; unsigned i, pitxn; int ret = CL_CLEAN, tmp = CL_CLEAN, mbr_base = 0; - off_t pos = 0, logiclba = 0; + size_t pos = 0, logiclba = 0; int virus_found = 0; mbr_base = sectorsize - sizeof(struct mbr_boot_record); diff --git a/libclamav/others.h b/libclamav/others.h index 2cc5aeb3e..ed6bc56fe 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -80,38 +80,36 @@ extern uint8_t cli_debug_flag; extern uint8_t cli_always_gen_section_hash; /* - * CLI_ISCONTAINED(bb, bb_size, sb, sb_size) checks if sb (sub buffer) is contained - * within bb (buffer). + * CLI_ISCONTAINED(bb, bb_size, sb, sb_size) checks if sb (small buffer) is + * within bb (big buffer). * * bb and sb are pointers (or offsets) for the main buffer and the * sub-buffer respectively, and bb_size and sb_size are their sizes * * The macro can be used to protect against wraps. */ -#define CLI_ISCONTAINED(bb, bb_size, sb, sb_size) \ - ( \ - (size_t)(bb_size) > 0 && (size_t)(sb_size) > 0 && \ - (size_t)(sb_size) <= (size_t)(bb_size) && \ - (ptrdiff_t)(sb) >= (ptrdiff_t)(bb) && \ - (ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) <= (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size) && \ - (ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) > (ptrdiff_t)(bb) && \ - (ptrdiff_t)(sb) < (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size)) +#define CLI_ISCONTAINED(bb, bb_size, sb, sb_size) \ + ((size_t)(bb_size) > 0 && (size_t)(sb_size) > 0 && \ + (size_t)(sb_size) <= (size_t)(bb_size) && \ + (size_t)(sb) >= (size_t)(bb) && \ + (size_t)(sb) + (size_t)(sb_size) <= (size_t)(bb) + (size_t)(bb_size) && \ + (size_t)(sb) + (size_t)(sb_size) > (size_t)(bb) && \ + (size_t)(sb) < (size_t)(bb) + (size_t)(bb_size)) /* - * CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) checks if sb (sub buffer) is contained - * within bb (buffer). + * CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) checks if sb (small buffer) is + * within bb (big buffer). * - * CLI_ISCONTAINED2 is the same as CLI_ISCONTAINED except that it allows for sub- - * buffers with sb_size == 0. + * CLI_ISCONTAINED2 is the same as CLI_ISCONTAINED except that it allows for + * small-buffers with sb_size == 0. */ -#define CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) \ - ( \ - (size_t)(bb_size) > 0 && (size_t)(sb_size) >= 0 && \ - (size_t)(sb_size) <= (size_t)(bb_size) && \ - (ptrdiff_t)(sb) >= (ptrdiff_t)(bb) && \ - (ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) <= (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size) && \ - (ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) >= (ptrdiff_t)(bb) && \ - (ptrdiff_t)(sb) < (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size)) +#define CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) \ + ((size_t)(bb_size) > 0 && \ + (size_t)(sb_size) <= (size_t)(bb_size) && \ + (size_t)(sb) >= (size_t)(bb) && \ + (size_t)(sb) + (size_t)(sb_size) <= (size_t)(bb) + (size_t)(bb_size) && \ + (size_t)(sb) + (size_t)(sb_size) >= (size_t)(bb) && \ + (size_t)(sb) <= (size_t)(bb) + (size_t)(bb_size)) #define CLI_MAX_ALLOCATION (182 * 1024 * 1024) diff --git a/libclamav/png.c b/libclamav/png.c index de5899d1d..460cba7b2 100644 --- a/libclamav/png.c +++ b/libclamav/png.c @@ -426,7 +426,7 @@ scan_overlay: /* Check if there's an overlay, and scan it if one exists. */ if (map->len - offset > 0) { cli_dbgmsg("PNG: Found " STDu64 " additional data after end of PNG! Scanning as a nested file.\n", map->len - offset); - status = cli_magic_scan_nested_fmap_type(map, offset, map->len - offset, ctx, CL_TYPE_ANY, NULL); + status = cli_magic_scan_nested_fmap_type(map, (size_t)offset, map->len - offset, ctx, CL_TYPE_ANY, NULL); goto done; } diff --git a/libclamav/scanners.c b/libclamav/scanners.c index b8dbd936d..8c06e132c 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -4583,15 +4583,15 @@ cl_error_t cl_scandesc(int desc, const char *filename, const char **virname, uns * @param name (optional) Original name of the file (to set fmap name metadata) * @return int CL_SUCCESS, or an error code. */ -static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name) +static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name) { cl_error_t ret = CL_CLEAN; cli_dbgmsg("magic_scan_nested_fmap_type: [%zu, +%zu), [" STDi64 ", +%zu)\n", map->nested_offset, map->len, (int64_t)offset, length); - if (offset < 0 || (size_t)offset >= map->len) { - cli_dbgmsg("Invalid offset: %ld\n", (long)offset); + if (offset >= map->len) { + cli_dbgmsg("Invalid offset: %zu\n", offset); return CL_CLEAN; } @@ -4599,8 +4599,8 @@ static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size length = map->len - offset; if (length > map->len - offset) { cli_dbgmsg("Data truncated: %zu -> %zu\n", - length, map->len - (size_t)offset); - length = map->len - (size_t)offset; + length, map->len - offset); + length = map->len - offset; } if (length <= 5) { @@ -4625,16 +4625,15 @@ static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size } /* For map scans that may be forced to disk */ -cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name) +cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name) { - off_t old_off = map->nested_offset; + size_t old_off = map->nested_offset; size_t old_len = map->len; cl_error_t ret = CL_CLEAN; - cli_dbgmsg("cli_magic_scan_nested_fmap_type: [%ld, +%lu)\n", - (long)offset, (unsigned long)length); - if (offset < 0 || (size_t)offset >= old_len) { - cli_dbgmsg("Invalid offset: %ld\n", (long)offset); + cli_dbgmsg("cli_magic_scan_nested_fmap_type: [%zu, +%zu)\n", offset, length); + if (offset >= old_len) { + cli_dbgmsg("Invalid offset: %zu\n", offset); return CL_CLEAN; } @@ -4649,8 +4648,7 @@ cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size_t if (!length) length = old_len - offset; if (length > old_len - offset) { - cli_dbgmsg("cli_magic_scan_nested_fmap_type: Data truncated: %lu -> %lu\n", - (unsigned long)length, (unsigned long)(old_len - offset)); + cli_dbgmsg("cli_magic_scan_nested_fmap_type: Data truncated: %zu -> %zu\n", length, old_len - offset); length = old_len - offset; } if (length <= 5) { @@ -4658,8 +4656,7 @@ cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size_t return CL_CLEAN; } if (!CLI_ISCONTAINED(old_off, old_len, old_off + offset, length)) { - cli_dbgmsg("cli_magic_scan_nested_fmap_type: map error occurred [%ld, %zu]\n", - (long)old_off, old_len); + cli_dbgmsg("cli_magic_scan_nested_fmap_type: map error occurred [%zu, %zu]\n", old_off, old_len); return CL_CLEAN; } diff --git a/libclamav/scanners.h b/libclamav/scanners.h index b97781caf..d5f57bc56 100644 --- a/libclamav/scanners.h +++ b/libclamav/scanners.h @@ -77,7 +77,7 @@ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type); * @param name (optional) Original name of the file (to set fmap name metadata) * @return int CL_SUCCESS, or an error code. */ -cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name); +cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name); /** * @brief Convenience wrapper for cli_magic_scan_nested_fmap_type(). diff --git a/libclamav/tnef.c b/libclamav/tnef.c index 2b5c73f8d..49cf301c0 100644 --- a/libclamav/tnef.c +++ b/libclamav/tnef.c @@ -266,7 +266,7 @@ tnef_message(fmap_t *map, off_t *pos, uint16_t type, uint16_t tag, int32_t lengt /*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/ - if (!CLI_ISCONTAINED2(0, fsize, offset, (off_t)length)) { + if (!CLI_ISCONTAINED2(0, fsize, offset, length)) { cli_dbgmsg("TNEF: Incorrect length field in tnef_message\n"); return -1; } diff --git a/unit_tests/check_clamav.c b/unit_tests/check_clamav.c index 6a8842ab4..b650393ee 100644 --- a/unit_tests/check_clamav.c +++ b/unit_tests/check_clamav.c @@ -561,6 +561,288 @@ START_TEST(test_cl_scanmap_callback_handle) } END_TEST +START_TEST(test_fmap_duplicate) +{ + cl_fmap_t *map; + cl_fmap_t *dup_map = NULL; + cl_fmap_t *dup_dup_map = NULL; + char map_data[6] = {'a', 'b', 'c', 'd', 'e', 'f'}; + char tmp[6]; + size_t bread = 0; + + map = cl_fmap_open_memory(map_data, sizeof(map_data)); + ck_assert_msg(!!map, "cl_fmap_open_handle failed"); + + /* + * Test duplicate of entire map + */ + cli_dbgmsg("duplicating complete map\n"); + dup_map = fmap_duplicate(map, 0, map->len, "complete duplicate"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 0, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == map->len, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == map->len, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 6); + ck_assert(0 == memcmp(map_data, tmp, 6)); + + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + /* + * Test duplicate of map at offset 2 + */ + cli_dbgmsg("duplicating 2 bytes into map\n"); + dup_map = fmap_duplicate(map, 2, map->len, "offset duplicate"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 2, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == 4, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == 6, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 4); + ck_assert(0 == memcmp(map_data + 2, tmp, 4)); + + /* + * Test duplicate of duplicate map, also at offset 2 (total 4 bytes in) + */ + cli_dbgmsg("duplicating 2 bytes into dup_map\n"); + dup_dup_map = fmap_duplicate(dup_map, 2, dup_map->len, "double offset duplicate"); + ck_assert_msg(!!dup_dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_dup_map->nested_offset == 4, "dup_dup_map nested_offset is incorrect: %zu", dup_dup_map->nested_offset); + ck_assert_msg(dup_dup_map->len == 2, "dup_dup_map len is incorrect: %zu", dup_dup_map->len); + ck_assert_msg(dup_dup_map->real_len == 6, "dup_dup_map real len is incorrect: %zu", dup_dup_map->real_len); + + bread = fmap_readn(dup_dup_map, tmp, 0, 6); + ck_assert(bread == 2); + ck_assert(0 == memcmp(map_data + 4, tmp, 2)); + + cli_dbgmsg("freeing dup_dup_map\n"); + free_duplicate_fmap(dup_dup_map); + dup_dup_map = NULL; + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + /* + * Test duplicate of map omiting the last 2 bytes + */ + cli_dbgmsg("duplicating map with shorter len\n"); + dup_map = fmap_duplicate(map, 0, map->len - 2, "short duplicate"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 0, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == 4, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == 6, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 4); + ck_assert(0 == memcmp(map_data, tmp, 4)); + + /* + * Test duplicate of the duplicate omiting the last 2 bytes again (so just the first 2 bytes) + */ + cli_dbgmsg("duplicating dup_map with shorter len\n"); + dup_dup_map = fmap_duplicate(dup_map, 0, dup_map->len - 2, "double short duplicate"); + ck_assert_msg(!!dup_dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_dup_map->nested_offset == 0, "dup_dup_map nested_offset is incorrect: %zu", dup_dup_map->nested_offset); + ck_assert_msg(dup_dup_map->len == 2, "dup_dup_map len is incorrect: %zu", dup_dup_map->len); + ck_assert_msg(dup_dup_map->real_len == 6, "dup_dup_map real len is incorrect: %zu", dup_dup_map->real_len); + + bread = fmap_readn(dup_dup_map, tmp, 0, 6); + ck_assert(bread == 2); + ck_assert(0 == memcmp(map_data, tmp, 2)); + + cli_dbgmsg("freeing dup_dup_map\n"); + free_duplicate_fmap(dup_dup_map); + dup_dup_map = NULL; + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + /* + * Test duplicate of map at offset 2 + */ + cli_dbgmsg("duplicating 2 bytes into map\n"); + dup_map = fmap_duplicate(map, 2, map->len, "offset duplicate"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 2, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == 4, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == 6, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 4); + ck_assert(0 == memcmp(map_data + 2, tmp, 4)); + + /* + * Test duplicate of the duplicate omiting the last 2 bytes again (so just the middle 2 bytes) + */ + cli_dbgmsg("duplicating dup_map with shorter len\n"); + dup_dup_map = fmap_duplicate(dup_map, 0, dup_map->len - 2, "offset short duplicate"); + ck_assert_msg(!!dup_dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_dup_map->nested_offset == 2, "dup_dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_dup_map->len == 2, "dup_dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_dup_map->real_len == 6, "dup_dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_dup_map, tmp, 0, 6); + ck_assert(bread == 2); + ck_assert(0 == memcmp(map_data + 2, tmp, 2)); + + cli_dbgmsg("freeing dup_dup_map\n"); + free_duplicate_fmap(dup_dup_map); + dup_dup_map = NULL; + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + cli_dbgmsg("freeing map\n"); + cl_fmap_close(map); +} +END_TEST + +START_TEST(test_fmap_duplicate_out_of_bounds) +{ + cl_fmap_t *map; + cl_fmap_t *dup_map = NULL; + cl_fmap_t *dup_dup_map = NULL; + char map_data[6] = {'a', 'b', 'c', 'd', 'e', 'f'}; + char tmp[6]; + size_t bread = 0; + + map = cl_fmap_open_memory(map_data, sizeof(map_data)); + ck_assert_msg(!!map, "cl_fmap_open_handle failed"); + + /* + * Test 0-byte duplicate + */ + cli_dbgmsg("duplicating 0 bytes of map\n"); + dup_map = fmap_duplicate(map, 0, 0, "zero-byte dup"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 0, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == 0, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == map->len, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 0); + + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + /* + * Test duplicate of entire map + 1 + */ + cli_dbgmsg("duplicating complete map + 1 byte\n"); + dup_map = fmap_duplicate(map, 0, map->len + 1, "duplicate + 1"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 0, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == map->len, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == map->len, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 6); + ck_assert(0 == memcmp(map_data, tmp, 6)); + + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + /* + * Test duplicate of map at offset 4 + */ + cli_dbgmsg("duplicating 4 bytes into map\n"); + dup_map = fmap_duplicate(map, 4, map->len, "offset duplicate"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 4, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == 2, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == 6, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 2); + ck_assert(0 == memcmp(map_data + 4, tmp, 2)); + + /* + * Test duplicate of duplicate map, also at offset 4 (total 8 bytes in, which is 2 bytes too far) + */ + cli_dbgmsg("duplicating 4 bytes into dup_map\n"); + dup_dup_map = fmap_duplicate(dup_map, 4, dup_map->len, "out of bounds offset duplicate"); + ck_assert_msg(NULL == dup_dup_map, "fmap_duplicate should have failed!"); + + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + /* + * Test duplicate just 2 bytes of the original + */ + cli_dbgmsg("duplicating map with shorter len\n"); + dup_map = fmap_duplicate(map, 0, 2, "short duplicate"); + ck_assert_msg(!!dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_map->nested_offset == 0, "dup_map nested_offset is incorrect: %zu", dup_map->nested_offset); + ck_assert_msg(dup_map->len == 2, "dup_map len is incorrect: %zu", dup_map->len); + ck_assert_msg(dup_map->real_len == 6, "dup_map real len is incorrect: %zu", dup_map->real_len); + + bread = fmap_readn(dup_map, tmp, 0, 6); + ck_assert(bread == 2); + ck_assert(0 == memcmp(map_data, tmp, 2)); + + /* Note: Keeping the previous dup_map around for a sequence of double-dup tests. */ + + /* + * Test duplicate 1 bytes into the 2-byte duplicate, requesting 2 bytes + * This should result in a 1-byte double-dup + */ + cli_dbgmsg("duplicating 1 byte in, 1 too many\n"); + dup_dup_map = fmap_duplicate(dup_map, 1, 2, "1 byte in, 1 too many"); + ck_assert_msg(!!dup_dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_dup_map->nested_offset == 1, "dup_dup_map nested_offset is incorrect: %zu", dup_dup_map->nested_offset); + ck_assert_msg(dup_dup_map->len == 1, "dup_dup_map len is incorrect: %zu", dup_dup_map->len); + ck_assert_msg(dup_dup_map->real_len == 6, "dup_dup_map real len is incorrect: %zu", dup_dup_map->real_len); + + bread = fmap_readn(dup_dup_map, tmp, 0, 6); + ck_assert(bread == 1); + ck_assert(0 == memcmp(map_data + 1, tmp, 1)); + + cli_dbgmsg("freeing dup_dup_map\n"); + free_duplicate_fmap(dup_dup_map); + dup_dup_map = NULL; + + /* + * Test duplicate 2 bytes into the 2-byte duplicate, requesting 2 bytes + * This should result in a 0-byte double-dup + */ + cli_dbgmsg("duplicating 2 bytes in, 2 bytes too many\n"); + dup_dup_map = fmap_duplicate(dup_map, 2, 2, "2 bytes in, 2 bytes too many"); + ck_assert_msg(!!dup_dup_map, "fmap_duplicate failed"); + ck_assert_msg(dup_dup_map->nested_offset == 2, "dup_dup_map nested_offset is incorrect: %zu", dup_dup_map->nested_offset); + ck_assert_msg(dup_dup_map->len == 0, "dup_dup_map len is incorrect: %zu", dup_dup_map->len); + ck_assert_msg(dup_dup_map->real_len == 6, "dup_dup_map real len is incorrect: %zu", dup_dup_map->real_len); + + bread = fmap_readn(dup_dup_map, tmp, 0, 6); + ck_assert(bread == 0); + + cli_dbgmsg("freeing dup_dup_map\n"); + free_duplicate_fmap(dup_dup_map); + dup_dup_map = NULL; + + /* + * Test duplicate 3 bytes into the 2-byte duplicate, requesting 2 bytes + */ + cli_dbgmsg("duplicating 0-byte of duplicate\n"); + dup_dup_map = fmap_duplicate(dup_map, 3, 2, "2 bytes in, 3 bytes too many"); + ck_assert_msg(NULL == dup_dup_map, "fmap_duplicate should have failed!"); + + /* Ok, we're done with this dup_map */ + cli_dbgmsg("freeing dup_map\n"); + free_duplicate_fmap(dup_map); + dup_map = NULL; + + cli_dbgmsg("freeing map\n"); + cl_fmap_close(map); +} +END_TEST + START_TEST(test_cl_scanmap_callback_handle_allscan) { const char *virname = NULL; @@ -710,6 +992,8 @@ static Suite *test_cl_suite(void) tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle_allscan, 0, expect); tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem, 0, expect); tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expect); + tcase_add_loop_test(tc_cl_scan, test_fmap_duplicate, 0, expect); + tcase_add_loop_test(tc_cl_scan, test_fmap_duplicate_out_of_bounds, 0, expect); user_timeout = getenv("T"); if (user_timeout) {