mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
Fix fmap-duplicate performance issue
The fmap_duplicate function is used create a new fmap with a view into an existing fmap. When the new view is a different size than the old fmap, a new hash must be calculated for the duplicate fmap. However, when the duplicated fmap is the same size as the original fmap, the hash will be the same and there's no point recalculating. The issue is apparent when scanning large EXE files because the hash was being calculated at the beginning and end of the scan. Digging into this issue revealed that hash calculations for fmaps were also being performed at the wrong place. For scans of maps we use fmap_duplicate() early in the process to apply the name API argument to the duplicate fmap. Fixing the logic so we doing recalculate the hash revealed that we never calculated hashes for fmap's created from buffers in the first place, so that also had to be fixed be relocating where the hash is calculated. I also found that fmap_duplicate()'s offset argument used an off_t, though it and all caller offsets are not allowed to be negative. This was a bit of tangent to fix a bunch of off_t variables and paramters that should've been size_t. Added a couple unit tests to verify that making duplicate fmaps, and duplicate-duplicate fmaps works as expected after the change. Changed CLI_ISCONTAINED() and CLI_ISCONTAINED2() macros to cast to size_t, because pointers and buffer sizes may not be negative, and these two macros do not rely on substraction.
This commit is contained in:
parent
c40f03ade6
commit
e4e3149368
17 changed files with 423 additions and 125 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
107
libclamav/fmap.c
107
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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? */) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue