From d7979d4ff7bab37d37fa32ff615e5a26d6ac1fb3 Mon Sep 17 00:00:00 2001 From: Micah Snyder Date: Fri, 20 Jul 2018 22:28:48 -0400 Subject: [PATCH] Restructured scan options flags from a single bitflag field to a structure containing multiple bitflag fields. This also required adding a new function to the bytecode API to get scan options a la carte, and modifying the existing function to hand back scan options in the old/deprecated uint32_t bitflag format. Re-generated bytecode iface header files. Updated libclamav documentation detailing new scan options structure. Renamed references to 'algorithmic' detection to 'heuristic' detection. Renaming references to 'properties' to 'collect metadata'. Renamed references to 'scan all' to 'scan all match'. Renamed a couple of 'Hueristic.*' signature names as 'Heuristics.*' signatures (plural) to match majority of other heuristics. --- NEWS.md | 10 +- clamconf/clamconf.c | 1 + clamd/onaccess_ddd.c | 36 ++- clamd/onaccess_ddd.h | 13 +- clamd/onaccess_fan.c | 26 +- clamd/onaccess_others.c | 2 +- clamd/onaccess_others.h | 3 +- clamd/onaccess_scth.c | 24 +- clamd/onaccess_scth.h | 8 +- clamd/scanner.c | 23 +- clamd/scanner.h | 7 +- clamd/server-th.c | 95 +++--- clamd/server.h | 12 +- clamd/session.c | 4 +- clamd/session.h | 2 +- clamscan/manager.c | 82 ++--- contrib/old-clamav-milter/clamav-milter.c | 5 +- docs/UserManual/libclamav.md | 131 +++++--- etc/clamd.conf.sample | 2 +- examples/ex1.c | 7 +- libclamav/7z_iface.c | 12 +- libclamav/apm.c | 8 +- libclamav/autoit.c | 4 +- libclamav/blob.c | 5 +- libclamav/bytecode.c | 8 +- libclamav/bytecode_api.c | 193 +++++++++++- libclamav/bytecode_api.h | 87 +++++- libclamav/bytecode_api_decl.c | 249 +++++++-------- libclamav/bytecode_api_impl.h | 3 +- libclamav/bytecode_hooks.h | 2 +- libclamav/cache.c | 2 +- libclamav/clamav.h | 135 ++++---- libclamav/clambc.h | 2 +- libclamav/cpio.c | 12 +- libclamav/dmg.c | 2 +- libclamav/elf.c | 24 +- libclamav/gpt.c | 20 +- libclamav/hfsplus.c | 8 +- libclamav/hwp.c | 44 +-- libclamav/ishield.c | 2 +- libclamav/iso9660.c | 4 +- libclamav/json_api.c | 2 +- libclamav/libmspack.c | 8 +- libclamav/macho.c | 2 +- libclamav/matcher-ac.c | 8 +- libclamav/matcher-bm.c | 4 +- libclamav/matcher-pcre.c | 2 +- libclamav/matcher.c | 36 +-- libclamav/mbox.c | 7 +- libclamav/mbr.c | 18 +- libclamav/msxml_parser.c | 18 +- libclamav/ole2_extract.c | 14 +- libclamav/others.c | 16 +- libclamav/others.h | 51 +-- libclamav/pdf.c | 74 +++-- libclamav/pdfdecode.c | 3 +- libclamav/pe.c | 42 +-- libclamav/phishcheck.c | 6 +- libclamav/scanners.c | 295 +++++++++--------- libclamav/tiff.c | 2 +- libclamav/untar.c | 4 +- libclamav/unzip.c | 10 +- libclamav/xar.c | 8 +- sigtool/sigtool.c | 18 +- unit_tests/check_bytecode.c | 6 +- unit_tests/check_clamav.c | 80 ++++- unit_tests/check_matchers.c | 18 +- unit_tests/check_regex.c | 8 +- .../clamav-for-windows/interface.c | 103 +++--- win32/conf_examples/clamd.conf.sample | 2 +- 70 files changed, 1379 insertions(+), 805 deletions(-) diff --git a/NEWS.md b/NEWS.md index 6b64b04b5..9d51f2432 100644 --- a/NEWS.md +++ b/NEWS.md @@ -86,7 +86,7 @@ ClamAV 0.100, including but not limited to: - Raw scanning of PostScript files. - Fix clamsubmit to use the new virus and false positive submission web interface. -- Optionally, flag files with the virus "Heuristic.Limits.Exceeded" when +- Optionally, flag files with the virus "Heuristics.Limits.Exceeded" when size limitations are exceeded. - Improved decoders for PDF files. - Reduced number of compile time warnings. @@ -1147,7 +1147,7 @@ Detailed list of changes: - Support for Sensory Networks' NodalCore hardware acceleration technology - Advanced phishing detection module (experimental) - Signatures are stored in separate trees depending on their target type - - Algorithmic detection can be controlled with CL_SCAN_ALGORITHMIC + - Algorithmic detection can be controlled with CL_SCAN_GENERAL_HEURISTICS - Support for new obfuscators: SUE, Y0da Cryptor, CryptFF - Support for new packers: NsPack, wwpack32, MEW, Upack - Support for SIS files (SymbianOS packages) @@ -1598,11 +1598,11 @@ the new version of ClamAV have detected and blocked 100% of Mydoom attacks! New features in this release include: - libclamav - - Portable Executable analyser (CL_SCAN_PE) featuring: + - Portable Executable analyser (CL_SCAN_PARSE_PE) featuring: - UPX decompression (all versions) - Petite decompression (2.x) - FSG decompression (1.3, 1.31, 1.33) - - detection of broken executables (CL_SCAN_BLOCKBROKEN) + - detection of broken executables (CL_SCAN_HEURISTIC_BROKEN) - new, memory efficient, pattern matching algorithm (multipattern variant of Boyer-Moore) - it's now primary matcher and Aho-Corasick is only used for regular expression extended signatures @@ -1618,7 +1618,7 @@ New features in this release include: - new method of mail files detection - all e-mail attachments are now scanned (previously only the first ten attachments were scanned) - - added support for scanning URLs in e-mails (CL_SCAN_MAILURL) + - added support for scanning URLs in e-mails (CL_SCAN_PARSE_MAILURL) - detection of Worm.Mydoom.M.log - updated API (still backward compatible but please consult clamdoc.pdf (Section 6) and adapt your software) diff --git a/clamconf/clamconf.c b/clamconf/clamconf.c index 64a4a0d66..be535cf5c 100644 --- a/clamconf/clamconf.c +++ b/clamconf/clamconf.c @@ -39,6 +39,7 @@ #include "shared/optparser.h" #include "shared/misc.h" +#include "clamav-config.h" #include "libclamav/str.h" #include "libclamav/clamav.h" #include "libclamav/others.h" diff --git a/clamd/onaccess_ddd.c b/clamd/onaccess_ddd.c index 28551be98..866bc7425 100644 --- a/clamd/onaccess_ddd.c +++ b/clamd/onaccess_ddd.c @@ -68,7 +68,7 @@ static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, const char *pa static void onas_ddd_handle_in_create(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask); static void onas_ddd_handle_in_moved_from(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd); static void onas_ddd_handle_in_delete(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd); -static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int options); +static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options); static void onas_ddd_exit(int sig); @@ -527,8 +527,9 @@ static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, return; } -static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int options) { +static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options) { + int thread_started = 1; struct scth_thrarg *scth_tharg = NULL; pthread_attr_t scth_attr; pthread_t scth_pid = 0; @@ -537,20 +538,37 @@ static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char if (pthread_attr_init(&scth_attr)) break; pthread_attr_setdetachstate(&scth_attr, PTHREAD_CREATE_JOINABLE); - if (!(scth_tharg = (struct scth_thrarg *) malloc(sizeof(struct scth_thrarg)))) break; + /* Allocate memory for arguments. Thread is responsible for freeing it. */ + if (!(scth_tharg = (struct scth_thrarg *) calloc(sizeof(struct scth_thrarg), 1))) break; + if (!(scth_tharg->options = (struct cl_scan_options *) calloc(sizeof(struct cl_scan_options), 1))) break; - scth_tharg->options = options; + (void) memcpy(scth_tharg->options, tharg->options, sizeof(struct cl_scan_options)); + + scth_tharg->extra_options = extra_options; scth_tharg->opts = tharg->opts; scth_tharg->pathname = strdup(pathname); scth_tharg->engine = tharg->engine; - if (!pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg)) break; - - free(scth_tharg); - scth_tharg = NULL; + thread_started = pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg); } while(0); - if (!scth_tharg) logg("!ScanOnAccess: Unable to kick off extra scanning.\n"); + if (0 != thread_started) { + /* Failed to create thread. Free anything we may have allocated. */ + logg("!ScanOnAccess: Unable to kick off extra scanning.\n"); + if (NULL != scth_tharg) { + if (NULL != scth_tharg->pathname){ + free(scth_tharg->pathname); + scth_tharg->pathname = NULL; + } + if (NULL != scth_tharg->options) { + free(scth_tharg->options); + scth_tharg->options = NULL; + } + free(scth_tharg); + scth_tharg = NULL; + } + } + return; } diff --git a/clamd/onaccess_ddd.h b/clamd/onaccess_ddd.h index 56a15e218..85e17efb0 100644 --- a/clamd/onaccess_ddd.h +++ b/clamd/onaccess_ddd.h @@ -22,19 +22,24 @@ #ifndef __ONAS_IN_H #define __ONAS_IN_H -#define ONAS_IN 0x01 -#define ONAS_FAN 0x02 +#include "shared/optparser.h" +#include "libclamav/clamav.h" + +/* + * Extra options for onas_scan_th(). + */ +#define ONAS_IN 0x01 +#define ONAS_FAN 0x02 #define MAX_WATCH_LEN 7 struct ddd_thrarg { int sid; - int options; + struct cl_scan_options *options; int fan_fd; uint64_t fan_mask; const struct optstruct *opts; const struct cl_engine *engine; - const struct cl_limits *limits; }; diff --git a/clamd/onaccess_fan.c b/clamd/onaccess_fan.c index 33d9f5386..143e62870 100644 --- a/clamd/onaccess_fan.c +++ b/clamd/onaccess_fan.c @@ -171,24 +171,36 @@ void *onas_fan_th(void *arg) } } else if (!optget(tharg->opts, "OnAccessDisableDDD")->enabled) { + int thread_started = 1; do { if(pthread_attr_init(&ddd_attr)) break; pthread_attr_setdetachstate(&ddd_attr, PTHREAD_CREATE_JOINABLE); - if(!(ddd_tharg = (struct ddd_thrarg *) malloc(sizeof(struct ddd_thrarg)))) break; + /* Allocate memory for arguments. Thread is responsible for freeing it. */ + if (!(ddd_tharg = (struct ddd_thrarg *) calloc(sizeof(struct ddd_thrarg), 1))) break; + if (!(ddd_tharg->options = (struct cl_scan_options *) calloc(sizeof(struct cl_scan_options), 1))) break; + (void) memcpy(ddd_tharg->options, tharg->options, sizeof(struct cl_scan_options)); ddd_tharg->fan_fd = onas_fan_fd; ddd_tharg->fan_mask = fan_mask; ddd_tharg->opts = tharg->opts; ddd_tharg->engine = tharg->engine; - ddd_tharg->options = tharg->options; - if(!pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg)) break; - - free(ddd_tharg); - ddd_tharg=NULL; + thread_started = pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg); } while(0); - if (!ddd_tharg) logg("!Unable to start dynamic directory determination.\n"); + + if (0 != thread_started) { + /* Failed to create thread. Free anything we may have allocated. */ + logg("!Unable to start dynamic directory determination.\n"); + if (NULL != ddd_tharg) { + if (NULL != ddd_tharg->options) { + free(ddd_tharg->options); + ddd_tharg->options = NULL; + } + free(ddd_tharg); + ddd_tharg = NULL; + } + } } else { if((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { diff --git a/clamd/onaccess_others.c b/clamd/onaccess_others.c index c0d243082..147cde52d 100644 --- a/clamd/onaccess_others.c +++ b/clamd/onaccess_others.c @@ -94,7 +94,7 @@ int onas_fan_checkowner(int pid, const struct optstruct *opts) return CHK_CLEAN; } -int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, int options, int extinfo) +int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo) { int ret = 0; struct cb_context context; diff --git a/clamd/onaccess_others.h b/clamd/onaccess_others.h index 39b2767e0..4a4239a97 100644 --- a/clamd/onaccess_others.h +++ b/clamd/onaccess_others.h @@ -22,6 +22,7 @@ #define __CLAMD_ONAS_OTHERS_H #include "shared/optparser.h" +#include "libclamav/clamav.h" typedef enum { CHK_CLEAN, @@ -30,6 +31,6 @@ typedef enum { } cli_check_t; int onas_fan_checkowner(int pid, const struct optstruct *opts); -int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, int options, int extinfo); +int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo); #endif diff --git a/clamd/onaccess_scth.c b/clamd/onaccess_scth.c index 5413adf47..0d48723bc 100644 --- a/clamd/onaccess_scth.c +++ b/clamd/onaccess_scth.c @@ -38,6 +38,7 @@ #include "priv_fts.h" #include "onaccess_scth.h" +#include "onaccess_others.h" #include "libclamav/clamav.h" @@ -132,16 +133,31 @@ void *onas_scan_th(void *arg) { sigaction(SIGUSR1, &act, NULL); sigaction(SIGSEGV, &act, NULL); - if (tharg->options & ONAS_SCTH_ISDIR) { + if (NULL == tharg || NULL == tharg->pathname || NULL == tharg->opts || NULL == tharg->engine) { + logg("ScanOnAccess: Invalid thread arguments for extra scanning\n"); + goto done; + } + + if (tharg->extra_options & ONAS_SCTH_ISDIR) { logg("*ScanOnAccess: Performing additional scanning on directory '%s'\n", tharg->pathname); onas_scth_handle_dir(tharg->pathname, tharg); - } else if (tharg->options & ONAS_SCTH_ISFILE) { + } else if (tharg->extra_options & ONAS_SCTH_ISFILE) { logg("*ScanOnAccess: Performing additional scanning on file '%s'\n", tharg->pathname); onas_scth_handle_file(tharg->pathname, tharg); } - free(tharg->pathname); - tharg->pathname = NULL; +done: + if (NULL != tharg->pathname){ + free(tharg->pathname); + tharg->pathname = NULL; + } + if (NULL != tharg->options) { + free(tharg->options); + tharg->options = NULL; + } + if (NULL != tharg) { + free(tharg); + } return NULL; } diff --git a/clamd/onaccess_scth.h b/clamd/onaccess_scth.h index d71a188c6..2284df1f0 100644 --- a/clamd/onaccess_scth.h +++ b/clamd/onaccess_scth.h @@ -21,13 +21,17 @@ #ifndef __ONAS_SCTH_H #define __ONAS_SCTH_H +#include "shared/optparser.h" +#include "libclamav/clamav.h" + #define ONAS_SCTH_ISDIR 0x01 #define ONAS_SCTH_ISFILE 0x02 struct scth_thrarg { - int options; + uint32_t extra_options; + struct cl_scan_options *options; const struct optstruct *opts; - const struct cl_engine *engine; + const struct cl_engine *engine; char *pathname; }; diff --git a/clamd/scanner.c b/clamd/scanner.c index 9e2f0feaf..6a694df97 100644 --- a/clamd/scanner.c +++ b/clamd/scanner.c @@ -117,7 +117,7 @@ void clamd_virus_found_cb(int fd, const char *virname, void *ctx) if (d == NULL) return; - if (!(d->options & CL_SCAN_ALLMATCHES) && !(d->options & CL_SCAN_HEURISTIC_PRECEDENCE)) + if (!(d->options->general & CL_SCAN_GENERAL_ALLMATCHES) && !(d->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)) return; if (virname == NULL) return; @@ -277,7 +277,7 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea if (ret == CL_VIRUS) { - if (scandata->options & CL_SCAN_ALLMATCHES || (scandata->infected && scandata->options & CL_SCAN_HEURISTIC_PRECEDENCE)) { + if (scandata->options->general & CL_SCAN_GENERAL_ALLMATCHES || (scandata->infected && scandata->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)) { if(optget(scandata->opts, "PreludeEnable")->enabled){ prelude_logging(filename, virname, context.virhash, context.virsize); } @@ -353,9 +353,14 @@ int scan_pathchk(const char *path, struct cli_ftw_cbdata *data) return 0; } -int scanfd(const client_conn_t *conn, unsigned long int *scanned, - const struct cl_engine *engine, - unsigned int options, const struct optstruct *opts, int odesc, int stream) +int scanfd( + const client_conn_t *conn, + unsigned long int *scanned, + const struct cl_engine *engine, + struct cl_scan_options *options, + const struct optstruct *opts, + int odesc, + int stream) { int ret, fd = conn->scanfd; const char *virname = NULL; @@ -418,7 +423,13 @@ int scanfd(const client_conn_t *conn, unsigned long int *scanned, return ret; } -int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, char term) +int scanstream( + int odesc, + unsigned long int *scanned, + const struct cl_engine *engine, + struct cl_scan_options *options, + const struct optstruct *opts, + char term) { int ret, sockfd, acceptd; int tmpd, bread, retval, firsttimeout, timeout, btread; diff --git a/clamd/scanner.h b/clamd/scanner.h index d315729d5..422934df3 100644 --- a/clamd/scanner.h +++ b/clamd/scanner.h @@ -24,6 +24,7 @@ #include +#include "libclamav/others.h" #include "libclamav/clamav.h" #include "shared/optparser.h" #include "thrmgr.h" @@ -42,7 +43,7 @@ struct scan_cb_data { const client_conn_t *conn; const char *toplevel_path; unsigned long scanned; - unsigned int options; + struct cl_scan_options *options; struct cl_engine *engine; const struct optstruct *opts; threadpool_t *thr_pool; @@ -57,8 +58,8 @@ struct cb_context { struct scan_cb_data *scandata; }; -int scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int odesc, int stream); -int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, char term); +int scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, int odesc, int stream); +int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term); int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data); int scan_pathchk(const char *path, struct cli_ftw_cbdata *data); void hash_callback(int fd, unsigned long long size, const unsigned char *md5, const char *virname, void *ctx); diff --git a/clamd/server-th.c b/clamd/server-th.c index 5268978e1..e6e66c1a7 100644 --- a/clamd/server-th.c +++ b/clamd/server-th.c @@ -718,7 +718,7 @@ static int handle_stream(client_conn_t *conn, struct fd_buf *buf, const struct o int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts) { int max_threads, max_queue, readtimeout, ret = 0; - unsigned int options = 0; + struct cl_scan_options options; char timestr[32]; #ifndef _WIN32 struct sigaction sigact; @@ -742,7 +742,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi threadpool_t *thr_pool; #if defined(FANOTIFY) || defined(CLAMAUTH) - pthread_t fan_pid; + pthread_t fan_pid = 0; pthread_attr_t fan_attr; struct thrarg *tharg = NULL; /* shut up gcc */ #endif @@ -751,6 +751,9 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi memset(&sigact, 0, sizeof(struct sigaction)); #endif + /* Initalize scan options struct */ + memset(&options, 0, sizeof(struct cl_scan_options)); + /* set up limits */ if((opt = optget(opts, "MaxScanSize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) { @@ -922,11 +925,11 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if(optget(opts, "ScanArchive")->enabled) { logg("Archive support enabled.\n"); - options |= CL_SCAN_ARCHIVE; + options.parse |= CL_SCAN_PARSE_ARCHIVE; if(optget(opts, "ArchiveBlockEncrypted")->enabled) { logg("Archive: Blocking encrypted archives.\n"); - options |= CL_SCAN_BLOCKENCRYPTED; + options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED; } } else { @@ -935,28 +938,28 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if (optget(opts, "BlockMax")->enabled) { logg("BlockMax heuristic detection enabled.\n"); - options |= CL_SCAN_BLOCKMAX; + options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX; } else { logg("BlockMax heuristic detection disabled.\n"); } if(optget(opts, "AlgorithmicDetection")->enabled) { logg("Algorithmic detection enabled.\n"); - options |= CL_SCAN_ALGORITHMIC; + options.general |= CL_SCAN_GENERAL_HEURISTICS; } else { logg("Algorithmic detection disabled.\n"); } if(optget(opts, "ScanPE")->enabled) { logg("Portable Executable support enabled.\n"); - options |= CL_SCAN_PE; + options.parse |= CL_SCAN_PARSE_PE; } else { logg("Portable Executable support disabled.\n"); } if(optget(opts, "ScanELF")->enabled) { logg("ELF support enabled.\n"); - options |= CL_SCAN_ELF; + options.parse |= CL_SCAN_PARSE_ELF; } else { logg("ELF support disabled.\n"); } @@ -964,17 +967,17 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if(optget(opts, "ScanPE")->enabled || optget(opts, "ScanELF")->enabled) { if(optget(opts, "DetectBrokenExecutables")->enabled) { logg("Detection of broken executables enabled.\n"); - options |= CL_SCAN_BLOCKBROKEN; + options.heuristic |= CL_SCAN_HEURISTIC_BROKEN; } } if(optget(opts, "ScanMail")->enabled) { logg("Mail files support enabled.\n"); - options |= CL_SCAN_MAIL; + options.parse |= CL_SCAN_PARSE_MAIL; if(optget(opts, "ScanPartialMessages")->enabled) { logg("Mail: RFC1341 handling enabled.\n"); - options |= CL_SCAN_PARTIAL_MESSAGE; + options.mail |= CL_SCAN_MAIL_PARTIAL_MESSAGE; } } else { @@ -983,10 +986,10 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if(optget(opts, "ScanOLE2")->enabled) { logg("OLE2 support enabled.\n"); - options |= CL_SCAN_OLE2; + options.parse |= CL_SCAN_PARSE_OLE2; if(optget(opts, "OLE2BlockMacros")->enabled) { logg("OLE2: Blocking all VBA macros.\n"); - options |= CL_SCAN_BLOCKMACROS; + options.heuristic |= CL_SCAN_HEURISTIC_MACROS; } } else { logg("OLE2 support disabled.\n"); @@ -994,35 +997,35 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if(optget(opts, "ScanPDF")->enabled) { logg("PDF support enabled.\n"); - options |= CL_SCAN_PDF; + options.parse |= CL_SCAN_PARSE_PDF; } else { logg("PDF support disabled.\n"); } if(optget(opts, "ScanSWF")->enabled) { logg("SWF support enabled.\n"); - options |= CL_SCAN_SWF; + options.parse |= CL_SCAN_PARSE_SWF; } else { logg("SWF support disabled.\n"); } if(optget(opts, "ScanHTML")->enabled) { logg("HTML support enabled.\n"); - options |= CL_SCAN_HTML; + options.parse |= CL_SCAN_PARSE_HTML; } else { logg("HTML support disabled.\n"); } if(optget(opts, "ScanXMLDOCS")->enabled) { logg("XMLDOCS support enabled.\n"); - options |= CL_SCAN_XMLDOCS; + options.parse |= CL_SCAN_PARSE_XMLDOCS; } else { logg("XMLDOCS support disabled.\n"); } if(optget(opts, "ScanHWP3")->enabled) { logg("HWP3 support enabled.\n"); - options |= CL_SCAN_HWP3; + options.parse |= CL_SCAN_PARSE_HWP3; } else { logg("HWP3 support disabled.\n"); } @@ -1030,28 +1033,28 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi if(optget(opts,"PhishingScanURLs")->enabled) { if(optget(opts,"PhishingAlwaysBlockCloak")->enabled) { - options |= CL_SCAN_PHISHING_BLOCKCLOAK; + options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_CLOAK; logg("Phishing: Always checking for cloaked urls\n"); } if(optget(opts,"PhishingAlwaysBlockSSLMismatch")->enabled) { - options |= CL_SCAN_PHISHING_BLOCKSSL; + options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH; logg("Phishing: Always checking for ssl mismatches\n"); } } if(optget(opts,"PartitionIntersection")->enabled) { - options |= CL_SCAN_PARTITION_INTXN; + options.heuristic |= CL_SCAN_HEURISTIC_PARTITION_INTXN; logg("Raw DMG: Always checking for partitions intersections\n"); } if(optget(opts,"HeuristicScanPrecedence")->enabled) { - options |= CL_SCAN_HEURISTIC_PRECEDENCE; + options.general |= CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE; logg("Heuristic: precedence enabled\n"); } if(optget(opts, "StructuredDataDetection")->enabled) { - options |= CL_SCAN_STRUCTURED; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED; if((opt = optget(opts, "StructuredMinCreditCardCount"))->enabled) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) { @@ -1074,15 +1077,15 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi logg("Structured: Minimum Social Security Number Count set to %u\n", (unsigned int) val); if(optget(opts, "StructuredSSNFormatNormal")->enabled) - options |= CL_SCAN_STRUCTURED_SSN_NORMAL; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL; if(optget(opts, "StructuredSSNFormatStripped")->enabled) - options |= CL_SCAN_STRUCTURED_SSN_STRIPPED; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED; } #ifdef HAVE__INTERNAL__SHA_COLLECT if(optget(opts, "DevCollectHashes")->enabled) - options |= CL_SCAN_INTERNAL_COLLECT_SHA; + options.dev |= CL_SCAN_DEV_COLLECT_SHA; #endif selfchk = optget(opts, "SelfCheck")->numarg; @@ -1209,18 +1212,34 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi #if defined(FANOTIFY) || defined(CLAMAUTH) { + int thread_started = 1; do { - if(pthread_attr_init(&fan_attr)) break; - pthread_attr_setdetachstate(&fan_attr, PTHREAD_CREATE_JOINABLE); - if(!(tharg = (struct thrarg *) malloc(sizeof(struct thrarg)))) break; - tharg->opts = opts; - tharg->engine = engine; - tharg->options = options; - if(!pthread_create(&fan_pid, &fan_attr, onas_fan_th, tharg)) break; - free(tharg); - tharg=NULL; - } while(0); - if (!tharg) logg("!Unable to start on-access scan\n"); + if(pthread_attr_init(&fan_attr)) break; + pthread_attr_setdetachstate(&fan_attr, PTHREAD_CREATE_JOINABLE); + + /* Allocate memory for arguments. Thread is responsible for freeing it. */ + if (!(tharg = (struct thrarg *) calloc(sizeof(struct thrarg), 1))) break; + if (!(tharg->options = (struct cl_scan_options *) calloc(sizeof(struct cl_scan_options), 1))) break; + + (void) memcpy(tharg->options, &options, sizeof(struct cl_scan_options)); + tharg->opts = opts; + tharg->engine = engine; + + thread_started = pthread_create(&fan_pid, &fan_attr, onas_fan_th, tharg); + } while(0); + + if (0 != thread_started) { + /* Failed to create thread. Free anything we may have allocated. */ + logg("!Unable to start on-access scan.\n"); + if (NULL != tharg) { + if (NULL != tharg->options) { + free(tharg->options); + tharg->options = NULL; + } + free(tharg); + tharg = NULL; + } + } } #else logg("!On-access scan is not available\n"); @@ -1384,7 +1403,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi conn.scanfd = buf->recvfd; buf->recvfd = -1; conn.sd = buf->fd; - conn.options = options; + conn.options = &options; conn.opts = opts; conn.thrpool = thr_pool; conn.engine = engine; diff --git a/clamd/server.h b/clamd/server.h index 93ee2031d..c1a7fe852 100644 --- a/clamd/server.h +++ b/clamd/server.h @@ -32,19 +32,9 @@ #include "session.h" struct thrarg { int sid; - int options; + struct cl_scan_options *options; const struct optstruct *opts; const struct cl_engine *engine; - const struct cl_limits *limits; -}; - -/* thread watcher arguments */ -struct thrwarg { - int socketd; - struct cl_engine **engine; - const struct optstruct *opts; - const struct cl_limits *limits; - unsigned int options; }; int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts); diff --git a/clamd/session.c b/clamd/session.c index d619e90d2..deffa7dcd 100644 --- a/clamd/session.c +++ b/clamd/session.c @@ -191,7 +191,7 @@ int command(client_conn_t *conn, int *virus) { int desc = conn->sd; struct cl_engine *engine = conn->engine; - unsigned int options = conn->options; + struct cl_scan_options *options = conn->options; const struct optstruct *opts = conn->opts; enum scan_type type = TYPE_INIT; int maxdirrec; @@ -369,7 +369,7 @@ int command(client_conn_t *conn, int *virus) return 1; } thrmgr_setactivetask(NULL, "ALLMATCHSCAN"); - scandata.options |= CL_SCAN_ALLMATCHES; + scandata.options->general |= CL_SCAN_GENERAL_ALLMATCHES; type = TYPE_SCAN; break; default: diff --git a/clamd/session.h b/clamd/session.h index 8b36a489a..d4b78cb41 100644 --- a/clamd/session.h +++ b/clamd/session.h @@ -82,7 +82,7 @@ typedef struct client_conn_tag { char *filename; int scanfd; int sd; - unsigned int options; + struct cl_scan_options *options; const struct optstruct *opts; struct cl_engine *engine; time_t engine_timestamp; diff --git a/clamscan/manager.c b/clamscan/manager.c index 31b1f3db1..f090243dd 100644 --- a/clamscan/manager.c +++ b/clamscan/manager.c @@ -289,7 +289,7 @@ static void clamscan_virus_found_cb(int fd, const char *virname, void *context) return; } -static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options) +static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options) { int ret = 0, fd, included; unsigned i; @@ -427,7 +427,7 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc action(filename); } -static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev) +static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options, unsigned int depth, dev_t dev) { DIR *dd; struct dirent *dent; @@ -540,7 +540,7 @@ static void scandirs(const char *dirname, struct cl_engine *engine, const struct } } -static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, int options) +static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options) { int ret; unsigned int fsize = 0; @@ -615,7 +615,8 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt int scanmanager(const struct optstruct *opts) { int ret = 0, i; - unsigned int options = 0, dboptions = 0, dirlnk = 1, filelnk = 1; + struct cl_scan_options options; + unsigned int dboptions = 0, dirlnk = 1, filelnk = 1; struct cl_engine *engine; STATBUF sb; char *file, cwd[1024], *pua_cats = NULL; @@ -625,6 +626,9 @@ int scanmanager(const struct optstruct *opts) struct rlimit rlim; #endif + /* Initalize scan options struct */ + memset(&options, 0, sizeof(struct cl_scan_options)); + dirlnk = optget(opts, "follow-dir-symlinks")->numarg; if(dirlnk > 2) { logg("!--follow-dir-symlinks: Invalid argument\n"); @@ -794,7 +798,7 @@ int scanmanager(const struct optstruct *opts) /* JSON check to prevent engine loading if specified without libjson-c */ #if HAVE_JSON if (optget(opts, "gen-json")->enabled) - options |= CL_SCAN_FILE_PROPERTIES; + options.general |= CL_SCAN_GENERAL_COLLECT_METADATA; #else if (optget(opts, "gen-json")->enabled) { logg("!Can't generate json (gen-json). libjson-c dev library was missing or misconfigured when ClamAV was built.\n"); @@ -1010,95 +1014,95 @@ int scanmanager(const struct optstruct *opts) /* set scan options */ if(optget(opts, "allmatch")->enabled) { - options |= CL_SCAN_ALLMATCHES; + options.general |= CL_SCAN_GENERAL_ALLMATCHES; } if(optget(opts,"phishing-ssl")->enabled) - options |= CL_SCAN_PHISHING_BLOCKSSL; + options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH; if(optget(opts,"phishing-cloak")->enabled) - options |= CL_SCAN_PHISHING_BLOCKCLOAK; + options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_CLOAK; if(optget(opts,"partition-intersection")->enabled) - options |= CL_SCAN_PARTITION_INTXN; + options.heuristic |= CL_SCAN_HEURISTIC_PARTITION_INTXN; if(optget(opts,"heuristic-scan-precedence")->enabled) - options |= CL_SCAN_HEURISTIC_PRECEDENCE; + options.general |= CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE; if(optget(opts, "scan-archive")->enabled) - options |= CL_SCAN_ARCHIVE; + options.parse |= CL_SCAN_PARSE_ARCHIVE; if(optget(opts, "detect-broken")->enabled) - options |= CL_SCAN_BLOCKBROKEN; + options.heuristic |= CL_SCAN_HEURISTIC_BROKEN; if(optget(opts, "block-encrypted")->enabled) - options |= CL_SCAN_BLOCKENCRYPTED; + options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED; if(optget(opts, "block-macros")->enabled) - options |= CL_SCAN_BLOCKMACROS; + options.heuristic |= CL_SCAN_HEURISTIC_MACROS; if(optget(opts, "scan-pe")->enabled) - options |= CL_SCAN_PE; + options.parse |= CL_SCAN_PARSE_PE; if(optget(opts, "scan-elf")->enabled) - options |= CL_SCAN_ELF; + options.parse |= CL_SCAN_PARSE_ELF; if(optget(opts, "scan-ole2")->enabled) - options |= CL_SCAN_OLE2; + options.parse |= CL_SCAN_PARSE_OLE2; if(optget(opts, "scan-pdf")->enabled) - options |= CL_SCAN_PDF; + options.parse |= CL_SCAN_PARSE_PDF; if(optget(opts, "scan-swf")->enabled) - options |= CL_SCAN_SWF; + options.parse |= CL_SCAN_PARSE_SWF; if(optget(opts, "scan-html")->enabled && optget(opts, "normalize")->enabled) - options |= CL_SCAN_HTML; + options.parse |= CL_SCAN_PARSE_HTML; if(optget(opts, "scan-mail")->enabled) - options |= CL_SCAN_MAIL; + options.parse |= CL_SCAN_PARSE_MAIL; if(optget(opts, "scan-xmldocs")->enabled) - options |= CL_SCAN_XMLDOCS; + options.parse |= CL_SCAN_PARSE_XMLDOCS; if(optget(opts, "scan-hwp3")->enabled) - options |= CL_SCAN_HWP3; + options.parse |= CL_SCAN_PARSE_HWP3; if(optget(opts, "algorithmic-detection")->enabled) - options |= CL_SCAN_ALGORITHMIC; + options.general |= CL_SCAN_GENERAL_HEURISTICS; if(optget(opts, "block-max")->enabled) { - options |= CL_SCAN_BLOCKMAX; + options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX; } #ifdef HAVE__INTERNAL__SHA_COLLECT if(optget(opts, "dev-collect-hashes")->enabled) - options |= CL_SCAN_INTERNAL_COLLECT_SHA; + options.dev |= CL_SCAN_DEV_COLLECT_SHA; #endif if(optget(opts, "dev-performance")->enabled) - options |= CL_SCAN_PERFORMANCE_INFO; + options.general |= CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO; if(optget(opts, "detect-structured")->enabled) { - options |= CL_SCAN_STRUCTURED; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED; if((opt = optget(opts, "structured-ssn-format"))->enabled) { switch(opt->numarg) { case 0: - options |= CL_SCAN_STRUCTURED_SSN_NORMAL; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL; break; case 1: - options |= CL_SCAN_STRUCTURED_SSN_STRIPPED; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED; break; case 2: - options |= (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED); + options.heuristic |= (CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL | CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED); break; default: logg("!Invalid argument for --structured-ssn-format\n"); return 2; } } else { - options |= CL_SCAN_STRUCTURED_SSN_NORMAL; + options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL; } if((opt = optget(opts, "structured-ssn-count"))->active) { @@ -1118,7 +1122,7 @@ int scanmanager(const struct optstruct *opts) } } } else { - options &= ~CL_SCAN_STRUCTURED; + options.heuristic &= ~CL_SCAN_HEURISTIC_STRUCTURED; } #ifdef C_LINUX @@ -1135,11 +1139,11 @@ int scanmanager(const struct optstruct *opts) ret = 2; } else { CLAMSTAT(cwd, &sb); - scandirs(cwd, engine, opts, options, 1, sb.st_dev); + scandirs(cwd, engine, opts, &options, 1, sb.st_dev); } } else if(opts->filename && !optget(opts, "file-list")->enabled && !strcmp(opts->filename[0], "-")) { /* read data from stdin */ - ret = scanstdin(engine, opts, options); + ret = scanstdin(engine, opts, &options); } else { if(opts->filename && optget(opts, "file-list")->enabled) logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n"); @@ -1163,18 +1167,18 @@ int scanmanager(const struct optstruct *opts) logg("%s: Symbolic link\n", file); } else if(CLAMSTAT(file, &sb) != -1) { if(S_ISREG(sb.st_mode) && filelnk) { - scanfile(file, engine, opts, options); + scanfile(file, engine, opts, &options); } else if(S_ISDIR(sb.st_mode) && dirlnk) { - scandirs(file, engine, opts, options, 1, sb.st_dev); + scandirs(file, engine, opts, &options, 1, sb.st_dev); } else { if(!printinfected) logg("%s: Symbolic link\n", file); } } } else if(S_ISREG(sb.st_mode)) { - scanfile(file, engine, opts, options); + scanfile(file, engine, opts, &options); } else if(S_ISDIR(sb.st_mode)) { - scandirs(file, engine, opts, options, 1, sb.st_dev); + scandirs(file, engine, opts, &options, 1, sb.st_dev); } else { logg("^%s: Not supported file type\n", file); ret = 2; diff --git a/contrib/old-clamav-milter/clamav-milter.c b/contrib/old-clamav-milter/clamav-milter.c index 4d1a86f4b..9c37e30bc 100644 --- a/contrib/old-clamav-milter/clamav-milter.c +++ b/contrib/old-clamav-milter/clamav-milter.c @@ -382,7 +382,10 @@ uint32_t maxreclevel; uint32_t maxfiles; static struct cl_stat dbstat; -static int options = CL_SCAN_STDOPT; +static struct cl_scan_options options; + +memset(&options, 0, sizeof(struct cl_scan_options)); +options.parse |= ~0; /* enable all parsers */ #ifdef BOUNCE static int bflag = 0; /* diff --git a/docs/UserManual/libclamav.md b/docs/UserManual/libclamav.md index fffeff987..0c92b7df7 100644 --- a/docs/UserManual/libclamav.md +++ b/docs/UserManual/libclamav.md @@ -250,59 +250,104 @@ The first argument points to the database directory, the second one specifies wh It’s possible to scan a file or descriptor using: ```c - int cl_scanfile(const char *filename, const char **virname, - unsigned long int *scanned, const struct cl_engine *engine, - unsigned int options); + int cl_scanfile( + const char *filename, + const char **virname, + unsigned long int *scanned, + const struct cl_engine *engine, + struct cl_scan_options *options); + + int cl_scandesc( + int desc, + const char **virname, + unsigned long int *scanned, + const struct cl_engine *engine, + struct cl_scan_options *options); +``` + +Both functions will store a virus name under the pointer `virname`, the virus name is part of the engine structure and must not be released directly. If the third argument (`scanned`) is not NULL, the functions will increase its value with the size of scanned data (in `CL_COUNT_PRECISION` units). The last argument (`options`) requires a pointer to a data structure that specifies the scan options. The data structure should be `memset()` Each variable in the structure is a bit-flag field. The structure definition is: - int cl_scandesc(int desc, const char **virname, unsigned - long int *scanned, const struct cl_engine *engine, - unsigned int options); +```c + struct cl_scan_options { + uint32_t general; + uint32_t parse; + uint32_t alert; + uint32_t heuristic_alert; + uint32_t mail; + uint32_t dev; + }; ``` -Both functions will store a virus name under the pointer `virname`, the virus name is part of the engine structure and must not be released directly. If the third argument (`scanned`) is not NULL, the functions will increase its value with the size of scanned data (in `CL_COUNT_PRECISION` units). The last argument (`options`) specified the scan options and supports the following flags (which can be combined using bit operators): +Supported flags for each of the fields are as follows: + +`general` - General scanning options. + +- **CL_SCAN_GENERAL_ALLMATCHES** + Scan in all-match mode +- **CL_SCAN_GENERAL_COLLECT_METADATA** + Collect metadata (--gen-json) +- **CL_SCAN_GENERAL_HEURISTICS** + Option to enable heuristic alerts. Required for any of the heuristic alerting options to work. + +`parse` - Options to enable/disable specific parsing capabilities. Generally you will want to enable all parsers. The easiest way to do this is to set the parse flags to ~0. -- **CL_SCAN_STDOPT** - This is an alias for a recommended set of scan options. You should use it to make your software ready for new features in the future versions of libclamav. -- **CL_SCAN_RAW** - Use it alone if you want to disable support for special files. -- **CL_SCAN_ARCHIVE** +- **CL_SCAN_PARSE_ARCHIVE** This flag enables transparent scanning of various archive formats. -- **CL_SCAN_BLOCKENCRYPTED** - With this flag the library will mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR). -- **CL_SCAN_MAIL** - Enable support for mail files. -- **CL_SCAN_OLE2** - Enables support for OLE2 containers (used by MS Office and .msi files). -- **CL_SCAN_PDF** +- **CL_SCAN_PARSE_ELF** + Enable support for ELF files. +- **CL_SCAN_PARSE_PDF** Enables scanning within PDF files. -- **CL_SCAN_SWF** +- **CL_SCAN_PARSE_SWF** Enables scanning within SWF files, notably compressed SWF. -- **CL_SCAN_PE** +- **CL_SCAN_PARSE_HWP** + Enables scanning of Hangul Word Processor (HWP) files. +- **CL_SCAN_PARSE_XMLDOCS** + Enables scanning of XML-formatted documents (e.g. Word, Excel, Powerpoint, HWP). +- **CL_SCAN_PARSE_MAIL** + Enable support for mail files. +- **CL_SCAN_PARSE_OLE2** + Enables support for OLE2 containers (used by MS Office and .msi files). +- **CL_SCAN_PARSE_HTML** + This flag enables HTML normalisation (including ScrEnc decryption). +- **CL_SCAN_PARSE_PE** This flag enables deep scanning of Portable Executable files and allows libclamav to unpack executables compressed with run-time unpackers. -- **CL_SCAN_ELF** - Enable support for ELF files. -- **CL_SCAN_BLOCKBROKEN** + +`heuristic` - Options to enable specific heuristic alerts + +- **CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE** + Allow heuristic match to take precedence. When enabled, if a heuristic scan (such as phishingScan) detects a possible virus/phish it will stop scan immediately. Recommended, saves CPU scan-time. When *disabled*, virus/phish detected by heuristic scans will be reported only at the end of a scan. If an archive contains both a heuristically detected virus/phishing, and a real malware, the real malware will be reported. +- **CL_SCAN_HEURISTIC_ENCRYPTED** + With this flag the library will mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR). +- **CL_SCAN_HEURISTIC_BROKEN** libclamav will try to detect broken executables and mark them as Broken.Executable. -- **CL_SCAN_HTML** - This flag enables HTML normalisation (including ScrEnc decryption). -- **CL_SCAN_ALGORITHMIC** - Enable algorithmic detection of viruses. -- **CL_SCAN_PHISHING_BLOCKSSL** - Phishing module: always block SSL mismatches in URLs. -- **CL_SCAN_PHISHING_BLOCKCLOAK** +- **CL_SCAN_HEURISTIC_EXCEEDS_MAX** + Alert when the scan of any file exceeds maximums such as max filesize, max scansize, max recursion level. +- **CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH** + Heuristic for Phishing module: always block SSL mismatches in URLs. +- **CL_SCAN_HEURISTIC_PHISHING_CLOAK** Phishing module: always block cloaked URLs. -- **CL_SCAN_STRUCTURED** - Enable the DLP module which scans for credit card and SSN numbers. -- **CL_SCAN_STRUCTURED_SSN_NORMAL** - Search for SSNs formatted as xx-yy-zzzz. -- **CL_SCAN_STRUCTURED_SSN_STRIPPED** - Search for SSNs formatted as xxyyzzzz. -- **CL_SCAN_PARTIAL_MESSAGE** - Scan RFC1341 messages split over many emails. You will need to periodically clean up `$TemporaryDirectory/clamav-partial` directory. -- **CL_SCAN_HEURISTIC_PRECEDENCE** - Allow heuristic match to take precedence. When enabled, if a heuristic scan (such as phishingScan) detects a possible virus/phish it will stop scan immediately. Recommended, saves CPU scan-time. When disabled, virus/phish detected by heuristic scans will be reported only at the end of a scan. If an archive contains both a heuristically detected virus/phishing, and a real malware, the real malware will be reported. -- **CL_SCAN_BLOCKMACROS** +- **CL_SCAN_HEURISTIC_MACROS** OLE2 containers, which contain VBA macros will be marked infected (Heuristics.OLE2.ContainsMacros). +- **CL_SCAN_HEURISTIC_PARTITION_INTXN** + alert if partition table size doesn't make sense +- **CL_SCAN_HEURISTIC_STRUCTURED** + Enable the data loss prevention (DLP) module which scans for credit card and SSN numbers. i.e. alert when detecting personal information +- **CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL** + Search for [and alert when detecting] SSNs formatted as xx-yy-zzzz. +- **CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED** + Search for [and alert when detecting] SSNs formatted as xxyyzzzz. + +`mail` - Options to enable specific mail parsing features + +- **CL_SCAN_MAIL_PARTIAL_MESSAGE** + Scan RFC1341 messages split over many emails. You will need to periodically clean up `$TemporaryDirectory/clamav-partial` directory. + +`dev` - Options designed for use by ClamAV developers + +- **CL_SCAN_DEV_COLLECT_SHA** + Enables hash output in sha-collect builds - for internal use only +- **CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO** + Collect performance timings All functions return `CL_CLEAN` when the file seems clean, `CL_VIRUS` when a virus is detected and another value on failure. @@ -311,7 +356,7 @@ All functions return `CL_CLEAN` when the file seems clean, `CL_VIRUS` when a vir const char *virname; if((ret = cl_scanfile("/tmp/test.exe", &virname, NULL, engine, - CL_SCAN_STDOPT)) == CL_VIRUS) { + &options)) == CL_VIRUS) { printf("Virus detected: %s\n", virname); } else { printf("No virus detected.\n"); diff --git a/etc/clamd.conf.sample b/etc/clamd.conf.sample index 26f2ec3d9..47155d2f2 100644 --- a/etc/clamd.conf.sample +++ b/etc/clamd.conf.sample @@ -591,7 +591,7 @@ Example # When BlockMax is set, files exceeding the MaxFileSize, MaxScanSize, or # MaxRecursion limit will be flagged with the virus -# "Heuristic.Limits.Exceeded". +# "Heuristics.Limits.Exceeded". # Default: no #BlockMax yes diff --git a/examples/ex1.c b/examples/ex1.c index 602030de9..d7e9e5092 100644 --- a/examples/ex1.c +++ b/examples/ex1.c @@ -45,6 +45,7 @@ int main(int argc, char **argv) long double mb; const char *virname; struct cl_engine *engine; + struct cl_scan_options options; if(argc != 2) { printf("Usage: %s file\n", argv[0]); @@ -85,7 +86,11 @@ int main(int argc, char **argv) } /* scan file descriptor */ - if((ret = cl_scandesc(fd, &virname, &size, engine, CL_SCAN_STDOPT)) == CL_VIRUS) { + memset(&options, 0, sizeof(struct cl_scan_options)); + options.parse |= ~0; /* enable all parsers */ + options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */ + + if((ret = cl_scandesc(fd, &virname, &size, engine, &options)) == CL_VIRUS) { printf("Virus detected: %s\n", virname); } else { if(ret == CL_CLEAN) { diff --git a/libclamav/7z_iface.c b/libclamav/7z_iface.c index 9cd2516f4..1bc72267c 100644 --- a/libclamav/7z_iface.c +++ b/libclamav/7z_iface.c @@ -106,7 +106,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) { SzArEx_Init(&db); res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp); - if(res == SZ_ERROR_ENCRYPTED && DETECT_ENCRYPTED) { + if(res == SZ_ERROR_ENCRYPTED && SCAN_HEURISTIC_ENCRYPTED) { cli_dbgmsg("cli_7unz: Encrypted header found in archive.\n"); found = cli_append_virus(ctx, "Heuristics.Encrypted.7Zip"); } else if(res == SZ_OK) { @@ -158,12 +158,12 @@ int cli_7unz (cli_ctx *ctx, size_t offset) { res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &allocImp, &allocTempImp); if(res == SZ_ERROR_ENCRYPTED) { encrypted = 1; - if(DETECT_ENCRYPTED) { + if(SCAN_HEURISTIC_ENCRYPTED) { cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n"); found = cli_append_virus(ctx, "Heuristics.Encrypted.7Zip"); if (found != CL_CLEAN) { if (found == CL_VIRUS) { - if (SCAN_ALL) + if (SCAN_ALLMATCHES) viruses_found++; } else break; @@ -173,7 +173,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) { if(cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) { found = CL_VIRUS; viruses_found++; - if (!SCAN_ALL) + if (!SCAN_ALLMATCHES) break; } if (res != SZ_OK) @@ -194,7 +194,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) { free(name); if(found != CL_CLEAN) - if (!(SCAN_ALL && found == CL_VIRUS)) + if (!(SCAN_ALLMATCHES && found == CL_VIRUS)) break; } } @@ -217,7 +217,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) { else cli_dbgmsg("cli_7unz: error %d\n", res); - if (SCAN_ALL && viruses_found) + if (SCAN_ALLMATCHES && viruses_found) return CL_VIRUS; return found; } diff --git a/libclamav/apm.c b/libclamav/apm.c index 13b8a5a4b..899f149de 100644 --- a/libclamav/apm.c +++ b/libclamav/apm.c @@ -133,10 +133,10 @@ int cli_scanapm(cli_ctx *ctx) } /* check that the partition table fits in the space specified - HEURISTICS */ - if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) { + if (SCAN_HEURISTIC_PARTITION_INTXN && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) { ret = apm_prtn_intxn(ctx, &aptable, sectorsize, old_school); if (ret != CL_CLEAN) { - if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) + if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) detection = CL_VIRUS; else return ret; @@ -226,7 +226,7 @@ int cli_scanapm(cli_ctx *ctx) /* send the partition to cli_map_scan */ ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY); if (ret != CL_CLEAN) { - if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) + if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) detection = CL_VIRUS; else return ret; @@ -296,7 +296,7 @@ static int apm_prtn_intxn(cli_ctx *ctx, struct apm_partition_info *aptable, size ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION); if (ret == CL_VIRUS) virus_found = 1; - if (SCAN_ALL || ret == CL_CLEAN) + if (SCAN_ALLMATCHES || ret == CL_CLEAN) tmp = 0; else goto leave; diff --git a/libclamav/autoit.c b/libclamav/autoit.c index 695b9ccd2..3383a27fe 100644 --- a/libclamav/autoit.c +++ b/libclamav/autoit.c @@ -394,7 +394,7 @@ static int ea05(cli_ctx *ctx, const uint8_t *base, char *tmpd) { return CL_ESEEK; } if(cli_magic_scandesc(i, ctx) == CL_VIRUS) { - if (!SCAN_ALL) { + if (!SCAN_ALLMATCHES) { close(i); if(!ctx->engine->keeptmp) if(cli_unlink(tempfile)) return CL_EUNLINK; @@ -921,7 +921,7 @@ static int ea06(cli_ctx *ctx, const uint8_t *base, char *tmpd) { return CL_ESEEK; } if(cli_magic_scandesc(i, ctx) == CL_VIRUS) { - if (!SCAN_ALL) { + if (!SCAN_ALLMATCHES) { close(i); if(!ctx->engine->keeptmp) if (cli_unlink(tempfile)) return CL_EUNLINK; diff --git a/libclamav/blob.c b/libclamav/blob.c index f5c8df056..226600288 100644 --- a/libclamav/blob.c +++ b/libclamav/blob.c @@ -618,8 +618,9 @@ int fileblobScan(const fileblob *fb) { int rc; + cli_ctx *ctx = fb->ctx; STATBUF sb; - int virus_found = 0; + int virus_found = 0; if(fb->isInfected) return CL_VIRUS; @@ -638,7 +639,7 @@ fileblobScan(const fileblob *fb) lseek(fb->fd, 0, SEEK_SET); FSTAT(fb->fd, &sb); if(cli_matchmeta(fb->ctx, fb->b.name, sb.st_size, sb.st_size, 0, 0, 0, NULL) == CL_VIRUS) { - if (!(fb->ctx->options & CL_SCAN_ALLMATCHES)) + if (!SCAN_ALLMATCHES) return CL_VIRUS; virus_found = 1; } diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c index 91f124bc4..7f9bbc161 100644 --- a/libclamav/bytecode.c +++ b/libclamav/bytecode.c @@ -1834,7 +1834,7 @@ int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, stru /* need to be called here to catch any extracted but not yet scanned files */ - if (ctx->outfd && (ret != CL_VIRUS || cctx->options & CL_SCAN_ALLMATCHES)) + if (ctx->outfd && (ret != CL_VIRUS || cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)) cli_bcapi_extract_new(ctx, -1); } if (bc->state == bc_jit || test_mode) { @@ -1854,7 +1854,7 @@ int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, stru /* need to be called here to catch any extracted but not yet scanned files */ - if (ctx->outfd && (ret != CL_VIRUS || cctx->options & CL_SCAN_ALLMATCHES)) + if (ctx->outfd && (ret != CL_VIRUS || cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)) cli_bcapi_extract_new(ctx, -1); } cli_event_time_stop(g_sigevents, bc->sigtime_id); @@ -2866,7 +2866,7 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c if (ctx->virname) { cli_dbgmsg("Bytecode runhook found virus: %s\n", ctx->virname); cli_append_virus(cctx, ctx->virname); - if (!(cctx->options & CL_SCAN_ALLMATCHES)) { + if (!(cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)) { cli_bytecode_context_clear(ctx); return CL_VIRUS; } @@ -2906,7 +2906,7 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c if (ret != CL_CLEAN) { if (ret == CL_VIRUS) { cli_dbgmsg("Scanning unpacked file by bytecode %u found a virus\n", bc->id); - if (cctx->options & CL_SCAN_ALLMATCHES) { + if (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES) { cli_bytecode_context_reset(ctx); continue; } diff --git a/libclamav/bytecode_api.c b/libclamav/bytecode_api.c index 87d156958..eab2e9d9b 100644 --- a/libclamav/bytecode_api.c +++ b/libclamav/bytecode_api.c @@ -1275,7 +1275,198 @@ uint32_t cli_bcapi_engine_dconf_level(struct cli_bc_ctx *ctx) uint32_t cli_bcapi_engine_scan_options(struct cli_bc_ctx *ctx) { cli_ctx *cctx = (cli_ctx*)ctx->ctx; - return cctx->options; + uint32_t options = CL_SCAN_RAW; + + if (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES) + options |= CL_SCAN_ALLMATCHES; + if (cctx->options->general & CL_SCAN_GENERAL_HEURISTICS) + options |= CL_SCAN_ALGORITHMIC; + if (cctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) + options |= CL_SCAN_FILE_PROPERTIES; + if (cctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE) + options |= CL_SCAN_HEURISTIC_PRECEDENCE; + + if (cctx->options->parse & CL_SCAN_PARSE_ARCHIVE) + options |= CL_SCAN_ARCHIVE; + if (cctx->options->parse & CL_SCAN_PARSE_ELF) + options |= CL_SCAN_ELF; + if (cctx->options->parse & CL_SCAN_PARSE_PDF) + options |= CL_SCAN_PDF; + if (cctx->options->parse & CL_SCAN_PARSE_SWF) + options |= CL_SCAN_SWF; + if (cctx->options->parse & CL_SCAN_PARSE_HWP3) + options |= CL_SCAN_HWP3; + if (cctx->options->parse & CL_SCAN_PARSE_XMLDOCS) + options |= CL_SCAN_XMLDOCS; + if (cctx->options->parse & CL_SCAN_PARSE_MAIL) + options |= CL_SCAN_MAIL; + if (cctx->options->parse & CL_SCAN_PARSE_OLE2) + options |= CL_SCAN_OLE2; + if (cctx->options->parse & CL_SCAN_PARSE_HTML) + options |= CL_SCAN_HTML; + if (cctx->options->parse & CL_SCAN_PARSE_PE) + options |= CL_SCAN_PE; + // if (cctx->options->parse & CL_SCAN_MAIL_URL) + // options |= CL_SCAN_MAILURL; /* deprecated circa 2009 */ + + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN) + options |= CL_SCAN_BLOCKBROKEN; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX) + options |= CL_SCAN_BLOCKMAX; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH) + options |= CL_SCAN_PHISHING_BLOCKSSL; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK) + options |= CL_SCAN_PHISHING_BLOCKCLOAK; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS) + options |= CL_SCAN_BLOCKMACROS; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED) + options |= CL_SCAN_BLOCKENCRYPTED; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN) + options |= CL_SCAN_PARTITION_INTXN; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED) + options |= CL_SCAN_STRUCTURED; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL) + options |= CL_SCAN_STRUCTURED_SSN_NORMAL; + if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED) + options |= CL_SCAN_STRUCTURED_SSN_STRIPPED; + + if (cctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE) + options |= CL_SCAN_PARTIAL_MESSAGE; + + if (cctx->options->dev & CL_SCAN_DEV_COLLECT_SHA) + options |= CL_SCAN_INTERNAL_COLLECT_SHA; + if (cctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO) + options |= CL_SCAN_PERFORMANCE_INFO; + + return options; +} + +uint32_t cli_bcapi_engine_scan_options_ex(struct cli_bc_ctx *ctx, const uint8_t *option_name, uint32_t name_len) +{ + uint32_t i = 0; + char *option_name_l = NULL; + + if (ctx == NULL || option_name == NULL || name_len == 0) { + cli_warnmsg("engine_scan_options_ex: Invalid arguments!"); + return 0; + } + + cli_ctx *cctx = (cli_ctx*)ctx->ctx; + if (cctx == NULL || cctx->options == NULL) { + cli_warnmsg("engine_scan_options_ex: Invalid arguments!"); + return 0; + } + + option_name_l = malloc(name_len + 1); + for (i = 0; i < name_len; i++) { + option_name_l[0] = tolower(option_name[i]); + } + option_name_l[name_len] = '\0'; + + if (strncmp(option_name_l, "general", MIN(name_len, sizeof("general")))) { + if (cli_memstr(option_name_l, name_len, "allmatch", sizeof("allmatch"))) { + return (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "collect metadata", sizeof("collect metadata"))) { + return (cctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "heuristics", sizeof("heuristics"))) { + return (cctx->options->general & CL_SCAN_GENERAL_HEURISTICS) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "precedence", sizeof("precedence"))) { + return (cctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE) ? 1 : 0; + } + /* else unknown option */ + return 0; + } + else if (strncmp(option_name_l, "parse", MIN(name_len, sizeof("parse")))) { + if (cli_memstr(option_name_l, name_len, "archive", sizeof("archive"))) { + return (cctx->options->parse & CL_SCAN_PARSE_ARCHIVE) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "elf", sizeof("elf"))) { + return (cctx->options->parse & CL_SCAN_PARSE_ELF) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "pdf", sizeof("pdf"))) { + return (cctx->options->parse & CL_SCAN_PARSE_PDF) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "swf", sizeof("swf"))) { + return (cctx->options->parse & CL_SCAN_PARSE_SWF) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "hwp3", sizeof("hwp3"))) { + return (cctx->options->parse & CL_SCAN_PARSE_HWP3) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "xmldocs", sizeof("xmldocs"))) { + return (cctx->options->parse & CL_SCAN_PARSE_XMLDOCS) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "mail", sizeof("mail"))) { + return (cctx->options->parse & CL_SCAN_PARSE_MAIL) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "ole2", sizeof("ole2"))) { + return (cctx->options->parse & CL_SCAN_PARSE_OLE2) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "html", sizeof("html"))) { + return (cctx->options->parse & CL_SCAN_PARSE_HTML) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "pe", sizeof("pe"))) { + return (cctx->options->parse & CL_SCAN_PARSE_PE) ? 1 : 0; + } + /* else unknown option */ + return 0; + } + else if (strncmp(option_name_l, "heuristic", MIN(name_len, sizeof("heuristic")))) { + if (cli_memstr(option_name_l, name_len, "broken", sizeof("broken"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "exceeds max", sizeof("exceeds max"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "phishing ssl mismatch", sizeof("phishing ssl mismatch"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "phishing cloak", sizeof("phishing cloak"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "macros", sizeof("macros"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "encrypted", sizeof("encrypted"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "partition intxn", sizeof("partition intxn"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "structured", sizeof("structured"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "structured ssn normal", sizeof("structured ssn normal"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "structured ssn stripped", sizeof("structured ssn stripped"))) { + return (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED) ? 1 : 0; + } + /* else unknown option */ + return 0; + } + else if (strncmp(option_name_l, "mail", MIN(name_len, sizeof("mail")))) { + if (cli_memstr(option_name_l, name_len, "partial message", sizeof("partial message"))) { + return (cctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE) ? 1 : 0; + } + /* else unknown option */ + return 0; + } + else if (strncmp(option_name_l, "dev", MIN(name_len, sizeof("dev")))) { + if (cli_memstr(option_name_l, name_len, "collect sha", sizeof("collect sha"))) { + return (cctx->options->dev & CL_SCAN_DEV_COLLECT_SHA) ? 1 : 0; + } + if (cli_memstr(option_name_l, name_len, "collect performance info", sizeof("collect performance info"))) { + return (cctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO) ? 1 : 0; + } + /* else unknown option */ + return 0; + } else { + /* else unknown option */ + return 0; + } } uint32_t cli_bcapi_engine_db_options(struct cli_bc_ctx *ctx) diff --git a/libclamav/bytecode_api.h b/libclamav/bytecode_api.h index cf5cb43cf..cbfadf0ee 100644 --- a/libclamav/bytecode_api.h +++ b/libclamav/bytecode_api.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * Copyright (C) 2014-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. * Copyright (C) 2009-2013 Sourcefire, Inc. * All rights reserved. * Authors: Török Edvin, Kevin Lin @@ -203,6 +203,45 @@ enum bc_json_type { JSON_TYPE_STRING /* */ }; +/** +\group_engine + * Scan option flag values for engine_scan_options(). *DEPRECATED* + */ +#define CL_SCAN_RAW 0x0 +#define CL_SCAN_ARCHIVE 0x1 +#define CL_SCAN_MAIL 0x2 +#define CL_SCAN_OLE2 0x4 +#define CL_SCAN_BLOCKENCRYPTED 0x8 +#define CL_SCAN_HTML 0x10 +#define CL_SCAN_PE 0x20 +#define CL_SCAN_BLOCKBROKEN 0x40 +#define CL_SCAN_MAILURL 0x80 /* deprecated circa 2009 */ +#define CL_SCAN_BLOCKMAX 0x100 +#define CL_SCAN_ALGORITHMIC 0x200 +//#define UNUSED 0x400 +#define CL_SCAN_PHISHING_BLOCKSSL 0x800 /* ssl mismatches, not ssl by itself*/ +#define CL_SCAN_PHISHING_BLOCKCLOAK 0x1000 +#define CL_SCAN_ELF 0x2000 +#define CL_SCAN_PDF 0x4000 +#define CL_SCAN_STRUCTURED 0x8000 +#define CL_SCAN_STRUCTURED_SSN_NORMAL 0x10000 +#define CL_SCAN_STRUCTURED_SSN_STRIPPED 0x20000 +#define CL_SCAN_PARTIAL_MESSAGE 0x40000 +#define CL_SCAN_HEURISTIC_PRECEDENCE 0x80000 +#define CL_SCAN_BLOCKMACROS 0x100000 +#define CL_SCAN_ALLMATCHES 0x200000 +#define CL_SCAN_SWF 0x400000 +#define CL_SCAN_PARTITION_INTXN 0x800000 +#define CL_SCAN_XMLDOCS 0x1000000 +#define CL_SCAN_HWP3 0x2000000 +//#define UNUSED 0x4000000 +//#define UNUSED 0x8000000 +#define CL_SCAN_FILE_PROPERTIES 0x10000000 +//#define UNUSED 0x20000000 +#define CL_SCAN_PERFORMANCE_INFO 0x40000000 /* Collect performance timings */ +#define CL_SCAN_INTERNAL_COLLECT_SHA 0x80000000 /* Enables hash output in sha-collect builds - for internal use only */ + + #ifdef __CLAMBC__ /* --------------- BEGIN GLOBALS -------------------------------------------- */ @@ -885,7 +924,7 @@ uint32_t engine_dconf_level(void); /** \group_engine - * Returns the current engine's scan options. + * Returns the current engine's scan options. **DEPRECATED** * @return CL_SCAN* flags */ uint32_t engine_scan_options(void); @@ -1222,5 +1261,49 @@ int32_t json_get_int(int32_t objid); //double json_get_double(int32_t objid); /* ----------------- END 0.98.4 APIs ---------------------------------- */ +/* ----------------- BEGIN 0.100.0 APIs ------------------------------- */ +/* ----------------- Scan Options APIs -------------------------------- */ +/** +\group_engine + * Check if any given scan option is enabled. + * Returns non-zero if the following named options are set: + * + * "general allmatch" - all-match mode is enabled + * "general collect metadata" - --gen-json is enabled + * "general heuristics" - --gen-json is enabled + * + * "parse archive" - archive parsing is enabled + * "parse pdf" - pdf parsing is enabled + * "parse swf" - swf parsing is enabled + * "parse hwp3" - hwp3 parsing is enabled + * "parse xmldocs" - xmldocs parsing is enabled + * "parse mail" - mail parsing is enabled + * "parse ole2" - ole2 parsing is enabled + * "parse html" - html parsing is enabled + * "parse pe" - pe parsing is enabled + * + * "heuristic precedence" - heuristic signatures are set to take precedence + * "heuristic broken" - broken pe heuristic is enabled + * "heuristic exceeds max" - heuristic for when max settings are exceeded is enabled + * "heuristic phishing ssl mismatch" - phishing ssl mismatch heuristic is enabled + * "heuristic phishing cloak" - phishing cloak heuristic is enabled + * "heuristic macros" - macros heuristic is enabled + * "heuristic encrypted" - encrypted heuristic is enabled + * "heuristic partition intxn" - macpartition intxnros heuristic is enabled + * "heuristic structured" - structured heuristic is enabled + * "heuristic structured ssn normal" - structured ssn normal heuristic is enabled + * "heuristic structured ssn stripped" - structured ssn stripped heuristic is enabled + * + * "mail partial message" - parsing of partial mail messages is enabled + * + * "dev collect sha" - --dev-collect-hashes is enabled + * "dev collect performance info" - --dev-performance is enabled + * + * @param[in] scan_options enum value for desired scan option category. + * @return CL_SCAN_