From d70adcb8b00a7bf8420b7802e14183ea9c15126c Mon Sep 17 00:00:00 2001 From: micasnyd Date: Wed, 22 Dec 2021 13:29:18 -0800 Subject: [PATCH] Fix ability to disable filesize limit with libclamav C API You should be able to disable the maxfilesize limit by setting it to zero. When "disabled", ClamAV should defer to inherent limitations, which at this time is INT_MAX - 2 bytes. This works okay for ClamScan and ClamD because our option parser converts max-filesize=0 to 4294967295 (4GB). But it is presently broken for other applications using the libclamav C API, like this: ```c cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, 0); ``` The limit checks added for cl_scanmap_callback and cl_scanfile_callback in 0.103.4 and 0.104.1 broke this ability because we forgot to check if the `maxfilesize > 0` before enforcing it. This commit adds that guard so you can disable by setting to `0`. While working on this, I also found that the `max_size` variables in our libmspack scanner code are using an `off_t` type, which is a SIGNED integer that may be 32bit width even on some 64bit platforms, or may be a 64bit width. AND the default `max_size` when `maxfilesize == 0` was being set to UINT_MAX (0xffffffff), aka `-1` when `off_t` is 32bits. This commit addresses this related issue by: - changing the `max_size` to use `uint64_t`, like our other limits. - verifying that `maxfilesize > 0` before using it. - checking that using `UINT32_MAX` as a backup will not exceed the max-scansize in the same way that we do with the maxfilesize. --- libclamav/libmspack.c | 68 ++++++++++++++++++++++++++++++------------- libclamav/others.h | 2 +- libclamav/scanners.c | 4 +-- 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/libclamav/libmspack.c b/libclamav/libmspack.c index f1a537dfd..9dcbe6957 100644 --- a/libclamav/libmspack.c +++ b/libclamav/libmspack.c @@ -34,7 +34,7 @@ struct mspack_name { struct mspack_system_ex { struct mspack_system ops; - off_t max_size; + uint64_t max_size; }; struct mspack_handle { @@ -45,7 +45,7 @@ struct mspack_handle { off_t offset; FILE *f; - off_t max_size; + uint64_t max_size; }; static struct mspack_file *mspack_fmap_open(struct mspack_system *self, @@ -170,7 +170,7 @@ 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; + uint64_t max_size; if (bytes < 0 || !mspack_handle) { cli_dbgmsg("%s() err %d\n", __func__, __LINE__); @@ -189,7 +189,7 @@ static int mspack_fmap_write(struct mspack_file *file, void *buffer, int bytes) if (!max_size) return bytes; - max_size = max_size < (off_t)bytes ? max_size : (off_t)bytes; + max_size = max_size < (uint64_t)bytes ? max_size : (uint64_t)bytes; mspack_handle->max_size -= max_size; @@ -366,7 +366,7 @@ int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset) } files = 0; for (cab_f = cab_h->files; cab_f; cab_f = cab_f->next) { - off_t max_size; + uint64_t max_size; char *tmp_fname = NULL; ret = cli_matchmeta(ctx, cab_f->filename, 0, cab_f->length, 0, @@ -387,13 +387,27 @@ int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset) } } - 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; + if (ctx->engine->maxfilesize > 0) { + // max filesize has been set + if ((ctx->engine->maxscansize > 0) && + (ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)) { + // ... but would exceed max scansize, shrink it. + max_size = ctx->engine->maxscansize - ctx->scansize; + } else { + // ... and will work + max_size = ctx->engine->maxfilesize; + } + } else { + // max filesize not specified + if ((ctx->engine->maxscansize > 0) && + (ctx->scansize + UINT32_MAX >= ctx->engine->maxscansize)) { + // ... but UINT32_MAX would exceed max scansize, shrink it. + max_size = ctx->engine->maxscansize - ctx->scansize; + } else { + // ... use UINT32_MAX + max_size = UINT32_MAX; + } + } tmp_fname = cli_gentemp(ctx->sub_tmpdir); if (!tmp_fname) { @@ -468,7 +482,7 @@ int cli_scanmschm(cli_ctx *ctx) } files = 0; for (mschm_f = mschm_h->files; mschm_f; mschm_f = mschm_f->next) { - off_t max_size; + uint64_t max_size; char *tmp_fname; ret = cli_matchmeta(ctx, mschm_f->filename, 0, mschm_f->length, @@ -489,13 +503,27 @@ int cli_scanmschm(cli_ctx *ctx) } } - 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; + if (ctx->engine->maxfilesize > 0) { + // max filesize has been set + if ((ctx->engine->maxscansize > 0) && + (ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)) { + // ... but would exceed max scansize, shrink it. + max_size = ctx->engine->maxscansize - ctx->scansize; + } else { + // ... and will work + max_size = ctx->engine->maxfilesize; + } + } else { + // max filesize not specified + if ((ctx->engine->maxscansize > 0) && + (ctx->scansize + UINT32_MAX >= ctx->engine->maxscansize)) { + // ... but UINT32_MAX would exceed max scansize, shrink it. + max_size = ctx->engine->maxscansize - ctx->scansize; + } else { + // ... use UINT32_MAX + max_size = UINT32_MAX; + } + } ops_ex.max_size = max_size; diff --git a/libclamav/others.h b/libclamav/others.h index 4f72f1328..800c5fbc6 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -179,7 +179,7 @@ typedef struct cli_ctx_tag { unsigned long int *scanned; const struct cli_matcher *root; const struct cl_engine *engine; - unsigned long scansize; + uint64_t scansize; struct cl_scan_options *options; unsigned int scannedfiles; unsigned int found_possibly_unwanted; diff --git a/libclamav/scanners.c b/libclamav/scanners.c index eb682dc5f..e7afe5334 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -5462,7 +5462,7 @@ cl_error_t cl_scandesc_callback(int desc, const char *filename, const char **vir status = CL_CLEAN; goto done; } - if ((uint64_t)sb.st_size > engine->maxfilesize) { + if ((engine->maxfilesize > 0) && ((uint64_t)sb.st_size > engine->maxfilesize)) { cli_dbgmsg("cl_scandesc_callback: File too large (" STDu64 " bytes), ignoring\n", (uint64_t)sb.st_size); if (scanoptions->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX) { if (engine->cb_virus_found) @@ -5499,7 +5499,7 @@ done: cl_error_t cl_scanmap_callback(cl_fmap_t *map, const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *scanoptions, void *context) { - if (map->len > engine->maxfilesize) { + if ((engine->maxfilesize > 0) && (map->len > engine->maxfilesize)) { cli_dbgmsg("cl_scandesc_callback: File too large (%zu bytes), ignoring\n", map->len); if (scanoptions->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX) { if (engine->cb_virus_found)