Skip to content

Commit ffd9579

Browse files
committed
Add options: --cache-size, CacheSize
* Add new clamd and clamscan option --cache-size This option allows you to set the number of entries the cache can store. Additionally, introduce CacheSize as a clamd.conf synonym for --cache-size. Fixes Cisco-Talos#867
1 parent 4c5d548 commit ffd9579

8 files changed

Lines changed: 48 additions & 24 deletions

File tree

clamd/clamd.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ int main(int argc, char **argv)
466466
break;
467467
}
468468

469+
if ((opt = optget(opts, "cache-size"))->enabled)
470+
cl_engine_set_num(engine, CL_ENGINE_CACHE_SIZE, opt->numarg);
469471
if (optget(opts, "disable-cache")->enabled)
470472
cl_engine_set_num(engine, CL_ENGINE_DISABLE_CACHE, 1);
471473

clamscan/manager.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,8 @@ int scanmanager(const struct optstruct *opts)
11181118

11191119
if (optget(opts, "disable-cache")->enabled)
11201120
cl_engine_set_num(engine, CL_ENGINE_DISABLE_CACHE, 1);
1121+
if ((opt = optget(opts, "cache-size"))->enabled)
1122+
cl_engine_set_num(engine, CL_ENGINE_CACHE_SIZE, opt->numarg);
11211123

11221124
if (optget(opts, "detect-pua")->enabled) {
11231125
dboptions |= CL_DB_PUA;

common/optparser.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ const struct clam_option __clam_options[] = {
248248
/* config file/cmdline options */
249249
{"AlertExceedsMax", "alert-exceeds-max", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
250250

251+
{"CacheSize", "cache-size", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 65536, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Number of entries the cache can store.", "65536"},
252+
251253
{"PreludeEnable", "prelude-enable", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Enable prelude", ""},
252254

253255
{"PreludeAnalyzerName", "prelude-analyzer-name", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Name of the analyzer as seen in prewikka", ""},

docs/man/clamd.conf.5.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ By default, the engine will store an MD5 in a cache of any files that are not fl
543543
.br
544544
Default: no
545545
.TP
546+
\fBCacheSize\fR
547+
This option allows you to set the number of entries the cache can store.
548+
.br
549+
Default: 65536
550+
.TP
546551
\fBForceToDisk\fR
547552
This option causes memory or nested map scans to dump the content to disk.
548553
.br

libclamav/cache.c

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,21 @@
3131
#include "mpool.h"
3232
#include "clamav.h"
3333
#include "cache.h"
34+
#include "math.h"
3435
#include "fmap.h"
3536

3637
#include "clamav_rust.h"
3738

38-
/* The number of root trees and the chooser function
39+
/* The chooser function
3940
Each tree is protected by a mutex against concurrent access */
40-
/* #define TREES 1 */
41-
/* static inline unsigned int getkey(uint8_t *hash) { return 0; } */
42-
#define TREES 256
43-
static inline unsigned int getkey(uint8_t *hash)
41+
static inline unsigned int getkey(uint8_t *hash, size_t trees)
4442
{
4543
if (hash) {
46-
return *hash;
44+
return (hash[0] | (((unsigned int)hash[1]) << 8)) % trees;
4745
}
4846

4947
return 0;
5048
}
51-
/* #define TREES 4096 */
52-
/* static inline unsigned int getkey(uint8_t *hash) { return hash[0] | ((unsigned int)(hash[1] & 0xf)<<8) ; } */
53-
/* #define TREES 65536 */
54-
/* static inline unsigned int getkey(uint8_t *hash) { return hash[0] | (((unsigned int)hash[1])<<8) ; } */
55-
56-
/* The number of nodes in each tree */
57-
#define NODES 256
5849

5950
/* SPLAY --------------------------------------------------------------------- */
6051
struct node { /* a node */
@@ -77,33 +68,35 @@ struct cache_set { /* a tree */
7768

7869
struct CACHE {
7970
struct cache_set cacheset;
71+
size_t trees;
72+
size_t nodes_per_tree;
8073
#ifdef CL_THREAD_SAFE
8174
pthread_mutex_t mutex;
8275
#endif
8376
};
8477

8578
/* Allocates all the nodes and sets up the replacement chain */
86-
static int cacheset_init(struct cache_set *cs, mpool_t *mempool)
79+
static int cacheset_init(struct cache_set *cs, mpool_t *mempool, size_t nodes_per_tree)
8780
{
8881
unsigned int i;
8982

9083
#ifndef USE_MPOOL
9184
UNUSEDPARAM(mempool);
9285
#endif
9386

94-
cs->data = MPOOL_CALLOC(mempool, NODES, sizeof(*cs->data));
87+
cs->data = MPOOL_CALLOC(mempool, nodes_per_tree, sizeof(*cs->data));
9588
cs->root = NULL;
9689

9790
if (!cs->data)
9891
return 1;
9992

100-
for (i = 1; i < NODES; i++) {
93+
for (i = 1; i < nodes_per_tree; i++) {
10194
cs->data[i - 1].next = &cs->data[i];
10295
cs->data[i].prev = &cs->data[i - 1];
10396
}
10497

10598
cs->first = cs->data;
106-
cs->last = &cs->data[NODES - 1];
99+
cs->last = &cs->data[nodes_per_tree - 1];
107100

108101
return 0;
109102
}
@@ -540,7 +533,7 @@ static int cache_lookup_hash(unsigned char *md5, size_t len, struct CACHE *cache
540533
return ret;
541534
}
542535

543-
key = getkey(md5);
536+
key = getkey(md5, cache->trees);
544537

545538
c = &cache[key];
546539

@@ -575,12 +568,20 @@ int clean_cache_init(struct cl_engine *engine)
575568
return 0;
576569
}
577570

578-
if (!(cache = MPOOL_MALLOC(engine->mempool, sizeof(struct CACHE) * TREES))) {
571+
size_t trees = ceil(sqrt(engine->cache_size));
572+
size_t nodes_per_tree = ceil(sqrt(engine->cache_size));
573+
574+
cli_dbgmsg("clean_cache_init: Requested cache size: %d. Actual cache size: %d. Trees: %d. Nodes per tree: %d.\n", engine->cache_size, trees * nodes_per_tree, trees, nodes_per_tree);
575+
576+
if (!(cache = MPOOL_MALLOC(engine->mempool, sizeof(struct CACHE) * trees))) {
579577
cli_errmsg("clean_cache_init: mpool malloc fail\n");
580578
return 1;
581579
}
582580

583-
for (i = 0; i < TREES; i++) {
581+
cache->trees = trees;
582+
cache->nodes_per_tree = nodes_per_tree;
583+
584+
for (i = 0; i < trees; i++) {
584585
#ifdef CL_THREAD_SAFE
585586
if (pthread_mutex_init(&cache[i].mutex, NULL)) {
586587
cli_errmsg("clean_cache_init: mutex init fail\n");
@@ -590,7 +591,7 @@ int clean_cache_init(struct cl_engine *engine)
590591
return 1;
591592
}
592593
#endif
593-
if (cacheset_init(&cache[i].cacheset, engine->mempool)) {
594+
if (cacheset_init(&cache[i].cacheset, engine->mempool, cache->nodes_per_tree)) {
594595
for (j = 0; j < i; j++) cacheset_destroy(&cache[j].cacheset, engine->mempool);
595596
#ifdef CL_THREAD_SAFE
596597
for (j = 0; j <= i; j++) pthread_mutex_destroy(&cache[j].mutex);
@@ -615,7 +616,7 @@ void clean_cache_destroy(struct cl_engine *engine)
615616
return;
616617
}
617618

618-
for (i = 0; i < TREES; i++) {
619+
for (i = 0; i < cache->trees; i++) {
619620
cacheset_destroy(&cache[i].cacheset, engine->mempool);
620621
#ifdef CL_THREAD_SAFE
621622
pthread_mutex_destroy(&cache[i].mutex);
@@ -667,7 +668,7 @@ void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx)
667668

668669
level = (ctx->fmap && ctx->fmap->dont_cache_flag) ? ctx->recursion_level : 0;
669670

670-
key = getkey(md5);
671+
key = getkey(md5, ctx->engine->cache->trees);
671672
c = &ctx->engine->cache[key];
672673

673674
#ifdef CL_THREAD_SAFE
@@ -709,7 +710,7 @@ void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine
709710
return;
710711
}
711712

712-
key = getkey(md5);
713+
key = getkey(md5, engine->cache->trees);
713714

714715
c = &engine->cache[key];
715716
#ifdef CL_THREAD_SAFE

libclamav/clamav.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ enum cl_engine_field {
301301
CL_ENGINE_MAX_SCRIPTNORMALIZE, /* uint64_t */
302302
CL_ENGINE_MAX_ZIPTYPERCG, /* uint64_t */
303303
CL_ENGINE_FORCETODISK, /* uint32_t */
304+
CL_ENGINE_CACHE_SIZE, /* uint32_t */
304305
CL_ENGINE_DISABLE_CACHE, /* uint32_t */
305306
CL_ENGINE_DISABLE_PE_STATS, /* uint32_t */
306307
CL_ENGINE_STATS_TIMEOUT, /* uint32_t */

libclamav/others.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,11 @@ cl_error_t cl_engine_set_num(struct cl_engine *engine, enum cl_engine_field fiel
730730
clean_cache_init(engine);
731731
}
732732
break;
733+
case CL_ENGINE_CACHE_SIZE:
734+
if (num) {
735+
engine->cache_size = (uint32_t)num;
736+
}
737+
break;
733738
case CL_ENGINE_DISABLE_PE_STATS:
734739
if (num) {
735740
engine->engine_options |= ENGINE_OPTIONS_DISABLE_PE_STATS;
@@ -846,6 +851,8 @@ long long cl_engine_get_num(const struct cl_engine *engine, enum cl_engine_field
846851
return engine->bytecode_mode;
847852
case CL_ENGINE_DISABLE_CACHE:
848853
return engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE;
854+
case CL_ENGINE_CACHE_SIZE:
855+
return engine->cache_size;
849856
case CL_ENGINE_STATS_TIMEOUT:
850857
return ((cli_intel_t *)(engine->stats_data))->timeout;
851858
case CL_ENGINE_MAX_PARTITIONS:
@@ -976,6 +983,7 @@ struct cl_settings *cl_engine_settings_copy(const struct cl_engine *engine)
976983
settings->cb_meta = engine->cb_meta;
977984
settings->cb_file_props = engine->cb_file_props;
978985
settings->engine_options = engine->engine_options;
986+
settings->cache_size = engine->cache_size;
979987

980988
settings->cb_stats_add_sample = engine->cb_stats_add_sample;
981989
settings->cb_stats_remove_sample = engine->cb_stats_remove_sample;
@@ -1020,6 +1028,7 @@ cl_error_t cl_engine_settings_apply(struct cl_engine *engine, const struct cl_se
10201028
engine->bytecode_timeout = settings->bytecode_timeout;
10211029
engine->bytecode_mode = settings->bytecode_mode;
10221030
engine->engine_options = settings->engine_options;
1031+
engine->cache_size = settings->cache_size;
10231032

10241033
if (engine->tmpdir)
10251034
MPOOL_FREE(engine->mempool, engine->tmpdir);

libclamav/others.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ struct cl_engine {
327327
char *tmpdir;
328328
uint32_t keeptmp;
329329
uint64_t engine_options;
330+
uint32_t cache_size;
330331

331332
/* Limits */
332333
uint32_t maxscantime; /* Time limit (in milliseconds) */
@@ -492,6 +493,7 @@ struct cl_settings {
492493
enum bytecode_mode bytecode_mode;
493494
char *pua_cats;
494495
uint64_t engine_options;
496+
uint32_t cache_size;
495497

496498
/* callbacks */
497499
clcb_pre_cache cb_pre_cache;

0 commit comments

Comments
 (0)