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.
This commit is contained in:
micasnyd
2021-12-22 13:29:18 -08:00
committed by Micah Snyder
parent 278ba2923e
commit d70adcb8b0
3 changed files with 51 additions and 23 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)