Skip to content

Commit

Permalink
Remove max-allocation limits where not required
Browse files Browse the repository at this point in the history
The cli_max_malloc, cli_max_calloc, and cli_max_realloc functions
provide a way to protect against allocating too much memory
when the size of the allocation is derived from the untrusted input.
Specifically, we worry about values in the file being scanned being
manipulated to exhaust the RAM and crash the application.

There is no need to check the limits if the size of the allocation
is fixed, or if the size of the allocation is necessary for signature
loading, or the general operation of the applications.
E.g. checking the max-allocation limit for the size of a hash, or
for the size of the scan recursion stack, is a complete waste of
time.

Although we significantly increased the max-allocation limit in
a recent release, it is best not to check an allocation if the
allocation will be safe. It would be a waste of time.

I am also hopeful that if we can reduce the number allocations
that require a limit-check to those that require it for the safe
scan of a file, then eventually we can store the limit in the scan-
context, and make it configurable.
  • Loading branch information
micahsnyder committed Mar 15, 2024
1 parent 73c6d46 commit 9026239
Show file tree
Hide file tree
Showing 15 changed files with 54 additions and 59 deletions.
2 changes: 1 addition & 1 deletion clambc/bcrun.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ int main(int argc, char *argv[])
cctx.evidence = evidence_new();

cctx.recursion_stack_size = cctx.engine->max_recursion_level;
cctx.recursion_stack = cli_max_calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
cctx.recursion_stack = calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
if (!cctx.recursion_stack) {
fprintf(stderr, "Out of memory\n");
exit(3);
Expand Down
4 changes: 2 additions & 2 deletions clamonacc/inotif/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int onas_ht_init(struct onas_ht **ht, uint32_t size)
.nbckts = 0,
};

if (!((*ht)->htable = (struct onas_bucket **)cli_max_calloc(size, sizeof(struct onas_bucket *)))) {
if (!((*ht)->htable = (struct onas_bucket **)calloc(size, sizeof(struct onas_bucket *)))) {
onas_free_ht(*ht);
return CL_EMEM;
}
Expand Down Expand Up @@ -794,7 +794,7 @@ int onas_ht_rm_hierarchy(struct onas_ht *ht, const char *pathname, size_t len, i
curr = curr->next;

size_t size = len + strlen(curr->dirname) + 2;
char *child_path = (char *)cli_max_malloc(size);
char *child_path = (char *)malloc(size);
if (child_path == NULL)
return CL_EMEM;
if (hnode->pathname[len - 1] == '/')
Expand Down
10 changes: 5 additions & 5 deletions clamonacc/inotif/inotif.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static int onas_ddd_init_wdlt(uint64_t nwatches)

if (nwatches <= 0) return CL_EARG;

wdlt = (char **)cli_max_calloc(nwatches << 1, sizeof(char *));
wdlt = (char **)calloc(nwatches << 1, sizeof(char *));
if (!wdlt) return CL_EMEM;

wdlt_len = nwatches << 1;
Expand All @@ -121,7 +121,7 @@ static int onas_ddd_grow_wdlt(void)

char **ptr = NULL;

ptr = (char **)cli_max_realloc(wdlt, wdlt_len << 1);
ptr = (char **)cli_safer_realloc(wdlt, wdlt_len << 1);
if (ptr) {
wdlt = ptr;
memset(&ptr[wdlt_len], 0, sizeof(char *) * (wdlt_len - 1));
Expand Down Expand Up @@ -243,7 +243,7 @@ static int onas_ddd_watch_hierarchy(const char *pathname, size_t len, int fd, ui
curr = curr->next;

size_t size = len + strlen(curr->dirname) + 2;
char *child_path = (char *)cli_max_malloc(size);
char *child_path = (char *)malloc(size);
if (child_path == NULL) {
logg(LOGG_ERROR, "ClamInotif: out of memory when adding child for %s\n", hnode->pathname);
return CL_EMEM;
Expand Down Expand Up @@ -330,7 +330,7 @@ static int onas_ddd_unwatch_hierarchy(const char *pathname, size_t len, int fd,
curr = curr->next;

size_t size = len + strlen(curr->dirname) + 2;
char *child_path = (char *)cli_max_malloc(size);
char *child_path = (char *)malloc(size);
if (child_path == NULL)
return CL_EMEM;
if (hnode->pathname[len - 1] == '/')
Expand Down Expand Up @@ -679,7 +679,7 @@ void *onas_ddd_th(void *arg)
} else {
len = strlen(path);
size_t size = strlen(child) + len + 2;
char *child_path = (char *)cli_max_malloc(size);
char *child_path = (char *)malloc(size);
if (child_path == NULL) {
logg(LOGG_DEBUG, "ClamInotif: could not allocate space for child path ... aborting\n");
return NULL;
Expand Down
2 changes: 1 addition & 1 deletion clamonacc/misc/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ char **onas_get_opt_list(const char *fname, int *num_entries, cl_error_t *err)
}

(*num_entries)++;
rlc_ptr = cli_max_realloc(opt_list, sizeof(char *) * (*num_entries + 1));
rlc_ptr = cli_safer_realloc(opt_list, sizeof(char *) * (*num_entries + 1));
if (rlc_ptr) {
opt_list = rlc_ptr;
opt_list[*num_entries] = NULL;
Expand Down
6 changes: 3 additions & 3 deletions freshclam/freshclam.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ static fc_error_t string_list_add(const char *item, char ***stringList, uint32_t
}

nItems = *nListItems + 1;
newList = (char **)cli_max_realloc(*stringList, nItems * sizeof(char *));
newList = (char **)cli_safer_realloc(*stringList, nItems * sizeof(char *));
if (newList == NULL) {
mprintf(LOGG_ERROR, "string_list_add: Failed to allocate memory for optional database list entry.\n");
status = FC_EMEM;
Expand Down Expand Up @@ -1142,7 +1142,7 @@ fc_error_t select_from_official_databases(
goto done;
}

selectedDatabases = cli_max_calloc(nStandardDatabases + nOptionalDatabases, sizeof(char *));
selectedDatabases = calloc(nStandardDatabases + nOptionalDatabases, sizeof(char *));

/*
* Select desired standard databases.
Expand Down Expand Up @@ -1261,7 +1261,7 @@ fc_error_t select_specific_databases(
*databaseList = NULL;
*nDatabases = 0;

selectedDatabases = cli_max_calloc(nSpecificDatabases, sizeof(char *));
selectedDatabases = calloc(nSpecificDatabases, sizeof(char *));

/*
* Get lists of available databases.
Expand Down
4 changes: 2 additions & 2 deletions libclamav/cvd.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static int cli_untgz(int fd, const char *destdir)
return -1;
}

path = (char *)cli_max_calloc(sizeof(char), pathlen);
path = (char *)calloc(sizeof(char), pathlen);
if (!path) {
cli_errmsg("cli_untgz: Can't allocate memory for path\n");
cli_untgz_cleanup(NULL, infile, NULL, fdd);
Expand Down Expand Up @@ -259,7 +259,7 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un
}

dbio->bufsize = CLI_DEFAULT_DBIO_BUFSIZE;
dbio->buf = cli_max_malloc(dbio->bufsize);
dbio->buf = malloc(dbio->bufsize);
if (!dbio->buf) {
cli_errmsg("cli_tgzload: Can't allocate memory for dbio->buf\n");
cli_tgzload_cleanup(compr, dbio, fdd);
Expand Down
2 changes: 1 addition & 1 deletion libclamav/dsig.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static unsigned char *cli_decodesig(const char *sig, unsigned int plen, BIGNUM *
bn_bytes, plen);
goto done;
}
plain = cli_max_calloc(plen, sizeof(unsigned char));
plain = calloc(plen, sizeof(unsigned char));
if (!plain) {
cli_errmsg("cli_decodesig: Can't allocate memory for 'plain'\n");
goto done;
Expand Down
25 changes: 12 additions & 13 deletions libclamav/others.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ static void *get_module_function(HMODULE handle, const char *name)
static void *get_module_function(void *handle, const char *name)
{
void *procAddress = NULL;
procAddress = dlsym(handle, name);
procAddress = dlsym(handle, name);
if (NULL == procAddress) {
const char *err = dlerror();
if (NULL == err) {
Expand Down Expand Up @@ -1665,25 +1665,25 @@ size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index)
/*
* Windows doesn't allow you to delete a directory while it is still open
*/
int cli_rmdirs(const char *name)
int cli_rmdirs(const char *dirname)
{
int rc;
STATBUF statb;
DIR *dd;
struct dirent *dent;
char err[128];

if (CLAMSTAT(name, &statb) < 0) {
cli_warnmsg("cli_rmdirs: Can't locate %s: %s\n", name, cli_strerror(errno, err, sizeof(err)));
if (CLAMSTAT(dirname, &statb) < 0) {
cli_warnmsg("cli_rmdirs: Can't locate %s: %s\n", dirname, cli_strerror(errno, err, sizeof(err)));
return -1;
}

if (!S_ISDIR(statb.st_mode)) {
if (cli_unlink(name)) return -1;
if (cli_unlink(dirname)) return -1;
return 0;
}

if ((dd = opendir(name)) == NULL)
if ((dd = opendir(dirname)) == NULL)
return -1;

rc = 0;
Expand All @@ -1696,15 +1696,14 @@ int cli_rmdirs(const char *name)
if (strcmp(dent->d_name, "..") == 0)
continue;

path = cli_max_malloc(strlen(name) + strlen(dent->d_name) + 2);

path = malloc(strlen(dirname) + strlen(dent->d_name) + 2);
if (path == NULL) {
cli_errmsg("cli_rmdirs: Unable to allocate memory for path %u\n", strlen(name) + strlen(dent->d_name) + 2);
cli_errmsg("cli_rmdirs: Unable to allocate memory for path %u\n", strlen(dirname) + strlen(dent->d_name) + 2);
closedir(dd);
return -1;
}

sprintf(path, "%s\\%s", name, dent->d_name);
sprintf(path, "%s\\%s", dirname, dent->d_name);
rc = cli_rmdirs(path);
free(path);
if (rc != 0)
Expand All @@ -1713,8 +1712,8 @@ int cli_rmdirs(const char *name)

closedir(dd);

if (rmdir(name) < 0) {
cli_errmsg("cli_rmdirs: Can't remove temporary directory %s: %s\n", name, cli_strerror(errno, err, sizeof(err)));
if (rmdir(dirname) < 0) {
cli_errmsg("cli_rmdirs: Can't remove temporary directory %s: %s\n", dirname, cli_strerror(errno, err, sizeof(err)));
return -1;
}

Expand Down Expand Up @@ -1742,7 +1741,7 @@ int cli_rmdirs(const char *dirname)
while ((dent = readdir(dd))) {
if (dent->d_ino) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
path = cli_max_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
path = malloc(strlen(dirname) + strlen(dent->d_name) + 2);
if (!path) {
cli_errmsg("cli_rmdirs: Unable to allocate memory for path %llu\n", (long long unsigned)(strlen(dirname) + strlen(dent->d_name) + 2));
closedir(dd);
Expand Down
12 changes: 4 additions & 8 deletions libclamav/others_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,7 @@ void *cli_max_malloc(size_t size)
void *alloc;

if (0 == size || size > CLI_MAX_ALLOCATION) {
cli_warnmsg("cli_max_malloc(): File or section is too large to scan (%zu bytes). \
For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
cli_warnmsg("cli_max_malloc(): File or section is too large to scan (%zu bytes). For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
size, CLI_MAX_ALLOCATION);
return NULL;
}
Expand All @@ -243,8 +242,7 @@ void *cli_max_calloc(size_t nmemb, size_t size)
void *alloc;

if (!nmemb || 0 == size || size > CLI_MAX_ALLOCATION || nmemb > CLI_MAX_ALLOCATION || (nmemb * size > CLI_MAX_ALLOCATION)) {
cli_warnmsg("cli_max_calloc(): File or section is too large to scan (%zu bytes). \
For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
cli_warnmsg("cli_max_calloc(): File or section is too large to scan (%zu bytes). For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
size, CLI_MAX_ALLOCATION);
return NULL;
}
Expand Down Expand Up @@ -311,8 +309,7 @@ void *cli_max_realloc(void *ptr, size_t size)
void *alloc;

if (0 == size || size > CLI_MAX_ALLOCATION) {
cli_warnmsg("cli_max_realloc(): File or section is too large to scan (%zu bytes). \
For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
cli_warnmsg("cli_max_realloc(): File or section is too large to scan (%zu bytes). For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
size, CLI_MAX_ALLOCATION);
return NULL;
}
Expand All @@ -333,8 +330,7 @@ void *cli_max_realloc2(void *ptr, size_t size)
void *alloc;

if (0 == size || size > CLI_MAX_ALLOCATION) {
cli_warnmsg("cli_max_realloc2(): File or section is too large to scan (%zu bytes). \
For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
cli_warnmsg("cli_max_realloc2(): File or section is too large to scan (%zu bytes). For your safety, ClamAV limits how much memory an operation can allocate to %d bytes\n",
size, CLI_MAX_ALLOCATION);
return NULL;
}
Expand Down
12 changes: 6 additions & 6 deletions libclamav/pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -2297,7 +2297,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str
break; \
} \
\
fname = cli_max_calloc(funclen + dlllen + 3, sizeof(char)); \
fname = cli_max_calloc(funclen + dlllen + 3, sizeof(char)); \
if (fname == NULL) { \
cli_dbgmsg("scan_pe: cannot allocate memory for imphash string\n"); \
ret = CL_EMEM; \
Expand Down Expand Up @@ -2335,7 +2335,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str

thuoff += sizeof(struct pe_image_thunk32);

temp = EC32(thunk32.u.Ordinal);
temp = EC32(thunk32.u.Ordinal);
thunk32.u.Ordinal = temp;

if (!(thunk32.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG32)) {
Expand Down Expand Up @@ -5849,22 +5849,22 @@ cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_sect
case 1:
genhash[CLI_HASH_MD5] = 1;
hlen = hashlen[CLI_HASH_MD5];
hash = hashset[CLI_HASH_MD5] = cli_max_calloc(hlen, sizeof(char));
hash = hashset[CLI_HASH_MD5] = calloc(hlen, sizeof(char));
break;
case 2:
genhash[CLI_HASH_SHA1] = 1;
hlen = hashlen[CLI_HASH_SHA1];
hash = hashset[CLI_HASH_SHA1] = cli_max_calloc(hlen, sizeof(char));
hash = hashset[CLI_HASH_SHA1] = calloc(hlen, sizeof(char));
break;
default:
genhash[CLI_HASH_SHA256] = 1;
hlen = hashlen[CLI_HASH_SHA256];
hash = hashset[CLI_HASH_SHA256] = cli_max_calloc(hlen, sizeof(char));
hash = hashset[CLI_HASH_SHA256] = calloc(hlen, sizeof(char));
break;
}

if (!hash) {
cli_errmsg("cli_genhash_pe: cli_max_calloc failed!\n");
cli_errmsg("cli_genhash_pe: calloc failed!\n");
cli_exe_info_destroy(peinfo);
return CL_EMEM;
}
Expand Down
2 changes: 1 addition & 1 deletion libfreshclam/libfreshclam.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ fc_error_t fc_initialize(fc_config *fcConfig)
#else
if (fcConfig->databaseDirectory[strlen(fcConfig->databaseDirectory) - 1] != '/') {
#endif
g_databaseDirectory = cli_max_malloc(strlen(fcConfig->databaseDirectory) + strlen(PATHSEP) + 1);
g_databaseDirectory = malloc(strlen(fcConfig->databaseDirectory) + strlen(PATHSEP) + 1);
snprintf(
g_databaseDirectory,
strlen(fcConfig->databaseDirectory) + strlen(PATHSEP) + 1,
Expand Down
4 changes: 2 additions & 2 deletions sigtool/sigtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2762,7 +2762,7 @@ static int decodehex(const char *hexsig)
trigger[tlen] = '\0';

/* get the regex expression */
regex = cli_max_calloc(rlen + 1, sizeof(char));
regex = calloc(rlen + 1, sizeof(char));
if (!regex) {
mprintf(LOGG_ERROR, "cannot allocate memory for regex expression\n");
free(trigger);
Expand All @@ -2773,7 +2773,7 @@ static int decodehex(const char *hexsig)

/* get the compile flags */
if (clen) {
cflags = cli_max_calloc(clen + 1, sizeof(char));
cflags = calloc(clen + 1, sizeof(char));
if (!cflags) {
mprintf(LOGG_ERROR, "cannot allocate memory for compile flags\n");
free(trigger);
Expand Down
8 changes: 4 additions & 4 deletions unit_tests/check_bytecode.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
cctx.dconf = cctx.engine->dconf;

cctx.recursion_stack_size = cctx.engine->max_recursion_level;
cctx.recursion_stack = cli_max_calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
ck_assert_msg(!!cctx.recursion_stack, "cli_max_calloc() for recursion_stack failed");
cctx.recursion_stack = calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
ck_assert_msg(!!cctx.recursion_stack, "calloc() for recursion_stack failed");

// ctx was memset, so recursion_level starts at 0.
cctx.recursion_stack[cctx.recursion_level].fmap = NULL;
Expand Down Expand Up @@ -509,8 +509,8 @@ static void runload(const char *dbname, struct cl_engine *engine, unsigned signo
/* when run from automake srcdir is set, but if run manually then not */
srcdir = SRCDIR;
}
str = cli_max_malloc(strlen(srcdir) + 1 + strlen(dbname) + 1);
ck_assert_msg(!!str, "cli_max_malloc");
str = malloc(strlen(srcdir) + 1 + strlen(dbname) + 1);
ck_assert_msg(!!str, "malloc");
sprintf(str, "%s" PATHSEP "%s", srcdir, dbname);

rc = cl_load(str, engine, &signo, CL_DB_STDOPT);
Expand Down
12 changes: 6 additions & 6 deletions unit_tests/check_clamav.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,8 @@ static void init_testfiles(void)
if (strncmp(dirent->d_name, "clam", 4))
continue;
i++;
testfiles = cli_max_realloc(testfiles, i * sizeof(*testfiles));
ck_assert_msg(!!testfiles, "cli_max_realloc");
testfiles = cli_safer_realloc(testfiles, i * sizeof(*testfiles));
ck_assert_msg(!!testfiles, "cli_safer_realloc");
testfiles[i - 1] = strdup(dirent->d_name);
}
testfiles_n = i;
Expand Down Expand Up @@ -1921,8 +1921,8 @@ int open_testfile(const char *name, int flags)
srcdir = SRCDIR;
}

str = cli_max_malloc(strlen(name) + strlen(srcdir) + 2);
ck_assert_msg(!!str, "cli_max_malloc");
str = malloc(strlen(name) + strlen(srcdir) + 2);
ck_assert_msg(!!str, "malloc");
sprintf(str, "%s" PATHSEP "%s", srcdir, name);

fd = open(str, flags);
Expand All @@ -1935,7 +1935,7 @@ void diff_file_mem(int fd, const char *ref, size_t len)
{
char c1, c2;
size_t p, reflen = len;
char *buf = cli_max_malloc(len);
char *buf = malloc(len);

ck_assert_msg(!!buf, "unable to malloc buffer: %zu", len);
p = read(fd, buf, len);
Expand Down Expand Up @@ -1964,7 +1964,7 @@ void diff_files(int fd, int ref_fd)
off_t siz = lseek(ref_fd, 0, SEEK_END);
ck_assert_msg(siz != -1, "lseek failed");

ref = cli_max_malloc(siz);
ref = malloc(siz);
ck_assert_msg(!!ref, "unable to malloc buffer: " STDi64, (int64_t)siz);

ck_assert_msg(lseek(ref_fd, 0, SEEK_SET) == 0, "lseek failed");
Expand Down
Loading

0 comments on commit 9026239

Please sign in to comment.