mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 18:33:16 +00:00

Many of the core scanning functions' names no longer represent their specific purpose or arguments. This commit aims to make the names more intuitive. Names are now prefixed with "magic" if they involve file-typing and file-type parsing. In addition, each function now includes the type of input being scanned whether its "desc", "fmap", or "buff". Some of the APIs also now specify "type" to indicate that a type other than "ANY" may be passed in to select the type rather than use file type magic for type recognition. | current name | new name | | ------------------------- | --------------------------------- | | magic_scandesc() | cli_magic_scan() | | cli_magic_scandesc_type() | <delete> | | cli_magic_scandesc() | cli_magic_scan_desc() | | cli_base_scandesc() | cli_magic_scan_desc_type() | | cli_partition_scandesc() | <delete> | | cli_map_scandesc() | magic_scan_nested_fmap_type() | | cli_map_scan() | cli_magic_scan_nested_fmap_type() | | cli_mem_scandesc() | cli_magic_scan_buff() | | cli_scanbuff() | cli_scan_buff() | | cli_scandesc() | cli_scan_desc() | | cli_fmap_scandesc() | cli_scan_fmap() | | cli_scanfile() | cli_magic_scan_file() | | cli_scandir() | cli_magic_scan_dir() | | cli_filetype2() | cli_determine_fmap_type() | | cli_filetype() | cli_compare_ftm_file() | | cli_partitiontype() | cli_compare_ftm_partition() | | cli_scanraw() | scanraw() |
543 lines
14 KiB
C
543 lines
14 KiB
C
/*
|
|
* Author: 웃 Sebastian Andrzej Siewior
|
|
* Summary: Glue code for libmspack handling.
|
|
*
|
|
* Acknowledgements: ClamAV uses Stuart Caie's libmspack to parse as number of
|
|
* Microsoft file formats.
|
|
* ✉ sebastian @ breakpoint ̣cc
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#include <mspack.h>
|
|
|
|
#include "clamav.h"
|
|
#include "fmap.h"
|
|
#include "scanners.h"
|
|
#include "others.h"
|
|
|
|
enum mspack_type {
|
|
FILETYPE_DUNNO,
|
|
FILETYPE_FMAP,
|
|
FILETYPE_FILENAME,
|
|
};
|
|
|
|
struct mspack_name {
|
|
fmap_t *fmap;
|
|
off_t org;
|
|
};
|
|
|
|
struct mspack_system_ex {
|
|
struct mspack_system ops;
|
|
off_t max_size;
|
|
};
|
|
|
|
struct mspack_handle {
|
|
enum mspack_type type;
|
|
|
|
fmap_t *fmap;
|
|
off_t org;
|
|
off_t offset;
|
|
|
|
FILE *f;
|
|
off_t max_size;
|
|
};
|
|
|
|
static struct mspack_file *mspack_fmap_open(struct mspack_system *self,
|
|
const char *filename, int mode)
|
|
{
|
|
struct mspack_name *mspack_name;
|
|
struct mspack_handle *mspack_handle;
|
|
struct mspack_system_ex *self_ex;
|
|
const char *fmode;
|
|
const struct mspack_system *mptr = self;
|
|
|
|
if (!filename) {
|
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
|
return NULL;
|
|
}
|
|
mspack_handle = malloc(sizeof(*mspack_handle));
|
|
memset(mspack_handle, 0, (sizeof(*mspack_handle)));
|
|
if (!mspack_handle) {
|
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
|
return NULL;
|
|
}
|
|
memset(mspack_handle, 0, sizeof(*mspack_handle));
|
|
|
|
switch (mode) {
|
|
case MSPACK_SYS_OPEN_READ:
|
|
mspack_handle->type = FILETYPE_FMAP;
|
|
|
|
mspack_name = (struct mspack_name *)filename;
|
|
mspack_handle->fmap = mspack_name->fmap;
|
|
mspack_handle->org = mspack_name->org;
|
|
mspack_handle->offset = 0;
|
|
|
|
return (struct mspack_file *)mspack_handle;
|
|
|
|
case MSPACK_SYS_OPEN_WRITE:
|
|
fmode = "wb";
|
|
break;
|
|
case MSPACK_SYS_OPEN_UPDATE:
|
|
fmode = "r+b";
|
|
break;
|
|
case MSPACK_SYS_OPEN_APPEND:
|
|
fmode = "ab";
|
|
break;
|
|
default:
|
|
cli_dbgmsg("%s() wrong mode\n", __func__);
|
|
goto out_err;
|
|
}
|
|
|
|
mspack_handle->type = FILETYPE_FILENAME;
|
|
|
|
mspack_handle->f = fopen(filename, fmode);
|
|
if (!mspack_handle->f) {
|
|
cli_dbgmsg("%s() failed %d\n", __func__, __LINE__);
|
|
goto out_err;
|
|
}
|
|
|
|
self_ex = (struct mspack_system_ex *)((char *)mptr - offsetof(struct mspack_system_ex, ops));
|
|
mspack_handle->max_size = self_ex->max_size;
|
|
return (struct mspack_file *)mspack_handle;
|
|
|
|
out_err:
|
|
memset(mspack_handle, 0, (sizeof(*mspack_handle)));
|
|
free(mspack_handle);
|
|
mspack_handle = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
static void mspack_fmap_close(struct mspack_file *file)
|
|
{
|
|
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
|
|
|
if (!mspack_handle)
|
|
return;
|
|
|
|
if (mspack_handle->type == FILETYPE_FILENAME)
|
|
if (mspack_handle->f)
|
|
fclose(mspack_handle->f);
|
|
|
|
memset(mspack_handle, 0, (sizeof(*mspack_handle)));
|
|
free(mspack_handle);
|
|
mspack_handle = NULL;
|
|
return;
|
|
}
|
|
|
|
static int mspack_fmap_read(struct mspack_file *file, void *buffer, int bytes)
|
|
{
|
|
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
|
off_t offset;
|
|
size_t count;
|
|
int ret;
|
|
|
|
if (bytes < 0) {
|
|
cli_dbgmsg("%s() %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
if (!mspack_handle) {
|
|
cli_dbgmsg("%s() %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (mspack_handle->type == FILETYPE_FMAP) {
|
|
offset = mspack_handle->offset + mspack_handle->org;
|
|
|
|
ret = fmap_readn(mspack_handle->fmap, buffer, offset, bytes);
|
|
if (ret != bytes) {
|
|
cli_dbgmsg("%s() %d %d, %d\n", __func__, __LINE__, bytes, ret);
|
|
return ret;
|
|
}
|
|
|
|
mspack_handle->offset += bytes;
|
|
return bytes;
|
|
}
|
|
count = fread(buffer, bytes, 1, mspack_handle->f);
|
|
if (count < 1) {
|
|
cli_dbgmsg("%s() %d %d, %zu\n", __func__, __LINE__, bytes, count);
|
|
return -1;
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
static int mspack_fmap_write(struct mspack_file *file, void *buffer, int bytes)
|
|
{
|
|
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
|
size_t count;
|
|
off_t max_size;
|
|
|
|
if (bytes < 0 || !mspack_handle) {
|
|
cli_dbgmsg("%s() err %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (mspack_handle->type == FILETYPE_FMAP) {
|
|
cli_dbgmsg("%s() err %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (!bytes)
|
|
return 0;
|
|
|
|
max_size = mspack_handle->max_size;
|
|
if (!max_size)
|
|
return bytes;
|
|
|
|
max_size = max_size < (off_t)bytes ? max_size : (off_t)bytes;
|
|
|
|
mspack_handle->max_size -= max_size;
|
|
|
|
count = fwrite(buffer, max_size, 1, mspack_handle->f);
|
|
if (count < 1) {
|
|
cli_dbgmsg("%s() err %d <%zu %d>\n", __func__, __LINE__, count, bytes);
|
|
return -1;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
static int mspack_fmap_seek(struct mspack_file *file, off_t offset, int mode)
|
|
{
|
|
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
|
|
|
if (!mspack_handle) {
|
|
cli_dbgmsg("%s() err %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (mspack_handle->type == FILETYPE_FMAP) {
|
|
off_t new_pos;
|
|
|
|
switch (mode) {
|
|
case MSPACK_SYS_SEEK_START:
|
|
new_pos = offset;
|
|
break;
|
|
case MSPACK_SYS_SEEK_CUR:
|
|
new_pos = mspack_handle->offset + offset;
|
|
break;
|
|
case MSPACK_SYS_SEEK_END:
|
|
new_pos = mspack_handle->fmap->len + offset;
|
|
break;
|
|
default:
|
|
cli_dbgmsg("%s() err %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
if (new_pos < 0 || new_pos > (off_t)mspack_handle->fmap->len) {
|
|
cli_dbgmsg("%s() err %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
mspack_handle->offset = new_pos;
|
|
return 0;
|
|
}
|
|
|
|
switch (mode) {
|
|
case MSPACK_SYS_SEEK_START:
|
|
mode = SEEK_SET;
|
|
break;
|
|
case MSPACK_SYS_SEEK_CUR:
|
|
mode = SEEK_CUR;
|
|
break;
|
|
case MSPACK_SYS_SEEK_END:
|
|
mode = SEEK_END;
|
|
break;
|
|
default:
|
|
cli_dbgmsg("%s() err %d\n", __func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
return fseek(mspack_handle->f, offset, mode);
|
|
}
|
|
|
|
static off_t mspack_fmap_tell(struct mspack_file *file)
|
|
{
|
|
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
|
|
|
if (!mspack_handle)
|
|
return -1;
|
|
|
|
if (mspack_handle->type == FILETYPE_FMAP)
|
|
return mspack_handle->offset;
|
|
|
|
return (off_t)ftell(mspack_handle->f);
|
|
}
|
|
|
|
static void mspack_fmap_message(struct mspack_file *file, const char *fmt, ...)
|
|
{
|
|
UNUSEDPARAM(file);
|
|
|
|
if (UNLIKELY(cli_debug_flag)) {
|
|
va_list args;
|
|
char buff[BUFSIZ];
|
|
size_t len = sizeof("LibClamAV debug: ") - 1;
|
|
|
|
memset(buff, 0, BUFSIZ);
|
|
|
|
/* Add the prefix */
|
|
strncpy(buff, "LibClamAV debug: ", len);
|
|
|
|
va_start(args, fmt);
|
|
vsnprintf(buff + len, sizeof(buff) - len - 2, fmt, args);
|
|
va_end(args);
|
|
|
|
/* Add a newline and a null terminator */
|
|
buff[strlen(buff)] = '\n';
|
|
buff[strlen(buff) + 1] = '\0';
|
|
|
|
fputs(buff, stderr);
|
|
}
|
|
}
|
|
|
|
static void *mspack_fmap_alloc(struct mspack_system *self, size_t num)
|
|
{
|
|
UNUSEDPARAM(self);
|
|
void *addr = malloc(num);
|
|
if (addr) {
|
|
memset(addr, 0, num);
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
static void mspack_fmap_free(void *mem)
|
|
{
|
|
if (mem) {
|
|
free(mem);
|
|
mem = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void mspack_fmap_copy(void *src, void *dst, size_t num)
|
|
{
|
|
memcpy(dst, src, num);
|
|
}
|
|
|
|
static struct mspack_system mspack_sys_fmap_ops = {
|
|
.open = mspack_fmap_open,
|
|
.close = mspack_fmap_close,
|
|
.read = mspack_fmap_read,
|
|
.write = mspack_fmap_write,
|
|
.seek = mspack_fmap_seek,
|
|
.tell = mspack_fmap_tell,
|
|
.message = mspack_fmap_message,
|
|
.alloc = mspack_fmap_alloc,
|
|
.free = mspack_fmap_free,
|
|
.copy = mspack_fmap_copy,
|
|
};
|
|
|
|
int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
|
|
{
|
|
struct mscab_decompressor *cab_d;
|
|
struct mscabd_cabinet *cab_h;
|
|
struct mscabd_file *cab_f;
|
|
int ret = 0;
|
|
int files;
|
|
int virus_num = 0;
|
|
struct mspack_name mspack_fmap = {
|
|
.fmap = *ctx->fmap,
|
|
.org = sfx_offset,
|
|
};
|
|
struct mspack_system_ex ops_ex;
|
|
memset(&ops_ex, 0, sizeof(struct mspack_system_ex));
|
|
ops_ex.ops = mspack_sys_fmap_ops;
|
|
|
|
cab_d = mspack_create_cab_decompressor(&ops_ex.ops);
|
|
if (!cab_d) {
|
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
|
return CL_EUNPACK;
|
|
}
|
|
|
|
cab_d->set_param(cab_d, MSCABD_PARAM_FIXMSZIP, 1);
|
|
#if MSCABD_PARAM_SALVAGE
|
|
cab_d->set_param(cab_d, MSCABD_PARAM_SALVAGE, 1);
|
|
#endif
|
|
|
|
cab_h = cab_d->open(cab_d, (char *)&mspack_fmap);
|
|
if (!cab_h) {
|
|
ret = CL_EFORMAT;
|
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
|
goto out_dest;
|
|
}
|
|
files = 0;
|
|
for (cab_f = cab_h->files; cab_f; cab_f = cab_f->next) {
|
|
off_t max_size;
|
|
char *tmp_fname = NULL;
|
|
|
|
ret = cli_matchmeta(ctx, cab_f->filename, 0, cab_f->length, 0,
|
|
files, 0, NULL);
|
|
if (ret) {
|
|
if (ret == CL_VIRUS) {
|
|
virus_num++;
|
|
if (!SCAN_ALLMATCHES)
|
|
break;
|
|
}
|
|
goto out_close;
|
|
}
|
|
|
|
if (ctx->engine->maxscansize) {
|
|
if (ctx->scansize >= ctx->engine->maxscansize) {
|
|
ret = CL_CLEAN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ctx->engine->maxscansize &&
|
|
ctx->scansize + ctx->engine->maxfilesize >=
|
|
ctx->engine->maxscansize)
|
|
max_size = ctx->engine->maxscansize -
|
|
ctx->scansize;
|
|
else
|
|
max_size = ctx->engine->maxfilesize ? ctx->engine->maxfilesize : 0xffffffff;
|
|
|
|
tmp_fname = cli_gentemp(ctx->sub_tmpdir);
|
|
if (!tmp_fname) {
|
|
ret = CL_EMEM;
|
|
break;
|
|
}
|
|
|
|
ops_ex.max_size = max_size;
|
|
/* scan */
|
|
ret = cab_d->extract(cab_d, cab_f, tmp_fname);
|
|
if (ret)
|
|
/* Failed to extract. Try to scan what is there */
|
|
cli_dbgmsg("%s() failed to extract %d\n", __func__, ret);
|
|
|
|
ret = cli_magic_scan_file(tmp_fname, ctx, cab_f->filename);
|
|
if (CL_EOPEN == ret) {
|
|
ret = CL_CLEAN;
|
|
} else if (CL_VIRUS == ret) {
|
|
virus_num++;
|
|
}
|
|
|
|
if (!ctx->engine->keeptmp) {
|
|
if (!access(tmp_fname, R_OK) && cli_unlink(tmp_fname)) {
|
|
free(tmp_fname);
|
|
ret = CL_EUNLINK;
|
|
break;
|
|
}
|
|
}
|
|
free(tmp_fname);
|
|
files++;
|
|
if (ret == CL_VIRUS && SCAN_ALLMATCHES)
|
|
continue;
|
|
if (ret)
|
|
break;
|
|
}
|
|
|
|
out_close:
|
|
cab_d->close(cab_d, cab_h);
|
|
out_dest:
|
|
mspack_destroy_cab_decompressor(cab_d);
|
|
if (virus_num)
|
|
return CL_VIRUS;
|
|
return ret;
|
|
}
|
|
|
|
int cli_scanmschm(cli_ctx *ctx)
|
|
{
|
|
struct mschm_decompressor *mschm_d;
|
|
struct mschmd_header *mschm_h;
|
|
struct mschmd_file *mschm_f;
|
|
int ret = CL_CLEAN; // Default CLEAN in case CHM contains no files.
|
|
int files;
|
|
int virus_num = 0;
|
|
struct mspack_name mspack_fmap = {
|
|
.fmap = *ctx->fmap,
|
|
};
|
|
struct mspack_system_ex ops_ex;
|
|
memset(&ops_ex, 0, sizeof(struct mspack_system_ex));
|
|
ops_ex.ops = mspack_sys_fmap_ops;
|
|
|
|
mschm_d = mspack_create_chm_decompressor(&ops_ex.ops);
|
|
if (!mschm_d) {
|
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
|
return CL_EUNPACK;
|
|
}
|
|
|
|
mschm_h = mschm_d->open(mschm_d, (char *)&mspack_fmap);
|
|
if (!mschm_h) {
|
|
ret = CL_EFORMAT;
|
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
|
goto out_dest;
|
|
}
|
|
files = 0;
|
|
for (mschm_f = mschm_h->files; mschm_f; mschm_f = mschm_f->next) {
|
|
off_t max_size;
|
|
char *tmp_fname;
|
|
|
|
ret = cli_matchmeta(ctx, mschm_f->filename, 0, mschm_f->length,
|
|
0, files, 0, NULL);
|
|
if (ret) {
|
|
if (ret == CL_VIRUS) {
|
|
virus_num++;
|
|
if (!SCAN_ALLMATCHES)
|
|
break;
|
|
}
|
|
goto out_close;
|
|
}
|
|
|
|
if (ctx->engine->maxscansize) {
|
|
if (ctx->scansize >= ctx->engine->maxscansize) {
|
|
ret = CL_CLEAN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ctx->engine->maxscansize &&
|
|
ctx->scansize + ctx->engine->maxfilesize >=
|
|
ctx->engine->maxscansize)
|
|
max_size = ctx->engine->maxscansize -
|
|
ctx->scansize;
|
|
else
|
|
max_size = ctx->engine->maxfilesize ? ctx->engine->maxfilesize : 0xffffffff;
|
|
|
|
ops_ex.max_size = max_size;
|
|
|
|
tmp_fname = cli_gentemp(ctx->sub_tmpdir);
|
|
if (!tmp_fname) {
|
|
ret = CL_EMEM;
|
|
break;
|
|
}
|
|
|
|
/* scan */
|
|
ret = mschm_d->extract(mschm_d, mschm_f, tmp_fname);
|
|
if (ret)
|
|
/* Failed to extract. Try to scan what is there */
|
|
cli_dbgmsg("%s() failed to extract %d\n", __func__, ret);
|
|
|
|
ret = cli_magic_scan_file(tmp_fname, ctx, mschm_f->filename);
|
|
if (CL_EOPEN == ret) {
|
|
ret = CL_CLEAN;
|
|
} else if (CL_VIRUS == ret) {
|
|
virus_num++;
|
|
}
|
|
|
|
if (!ctx->engine->keeptmp) {
|
|
if (!access(tmp_fname, R_OK) && cli_unlink(tmp_fname)) {
|
|
free(tmp_fname);
|
|
ret = CL_EUNLINK;
|
|
break;
|
|
}
|
|
}
|
|
free(tmp_fname);
|
|
files++;
|
|
if (ret == CL_VIRUS && SCAN_ALLMATCHES)
|
|
continue;
|
|
if (ret)
|
|
break;
|
|
}
|
|
|
|
out_close:
|
|
mschm_d->close(mschm_d, mschm_h);
|
|
out_dest:
|
|
mspack_destroy_chm_decompressor(mschm_d);
|
|
if (virus_num)
|
|
return CL_VIRUS;
|
|
return ret;
|
|
}
|