mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
Merge pull request #1532 from val-ms/CLAM-1859-sha256-cache
- md5 -> sha2-256 caching - remove reliance on md5 hashes in general - FIPS cryptographic hash limits feature to disable md5 and sha1. - Adds related option for ClamD, ClamScan, Freshclam, Sigtool - ClamBC: fix crashes - signature names that start with "Weak." won't alert anymore. - ClamScan: - add `--hash-hint`, `--log-hash`, `--hash-alg`, `--file-type-hint`, `--log-file-type` - accurate counts for scanned bytes and bytes read - libclamav: - new cl_scan*_ex() APIs - separate temp-directory-recursion feature from keep-temps feature - object id's for each layer scanned - scan hash hints - scan file type hints - fix double-extraction for OOXML documents - new scan callbacks, deprecate old scan callbacks - new APIs to get access to file data and metadata from scan callbacks - metadata.json: - object id's - replace "viruses" to "alerts" and add "indicators" array - replace "FileMD5" with "sha2-256" - json store extra hashes feature - Related options for ClamD and ClamScan - object id's - related improvements
This commit is contained in:
commit
7e245071a0
131 changed files with 10768 additions and 3099 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -395,6 +395,7 @@ dependencies = [
|
|||
"hex",
|
||||
"hex-literal 0.4.1",
|
||||
"image",
|
||||
"indexmap 2.10.0",
|
||||
"inflate",
|
||||
"libc",
|
||||
"log",
|
||||
|
@ -1097,9 +1098,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
|
@ -2122,7 +2123,7 @@ version = "0.22.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"indexmap 2.10.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
|
|
7
NEWS.md
7
NEWS.md
|
@ -47,12 +47,13 @@ ClamAV 1.5.0 includes the following improvements and changes:
|
|||
Added two new APIs to the public clamav.h header:
|
||||
```c
|
||||
extern cl_error_t cl_cvdverify_ex(const char *file,
|
||||
const char *certs_directory);
|
||||
const char *certs_directory,
|
||||
uint32_t dboptions);
|
||||
|
||||
extern cl_error_t cl_cvdunpack_ex(const char *file,
|
||||
const char *dir,
|
||||
bool dont_verify,
|
||||
const char *certs_directory);
|
||||
const char *certs_directory,
|
||||
uint32_t dboptions);
|
||||
```
|
||||
The original `cl_cvdverify` and `cl_cvdunpack` are deprecated.
|
||||
|
||||
|
|
|
@ -367,9 +367,6 @@
|
|||
/* yara sources are compiled in */
|
||||
#define HAVE_YARA 1
|
||||
|
||||
/* For internal use only - DO NOT DEFINE */
|
||||
#cmakedefine HAVE__INTERNAL__SHA_COLLECT 1
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
#cmakedefine ICONV_CONST @ICONV_CONST@
|
||||
|
||||
|
|
|
@ -398,24 +398,16 @@ int main(int argc, char *argv[])
|
|||
fprintf(stderr, "Out of memory\n");
|
||||
exit(3);
|
||||
}
|
||||
ctx->ctx = &cctx;
|
||||
cctx.engine = engine;
|
||||
cctx.evidence = evidence_new();
|
||||
ctx->ctx = &cctx;
|
||||
cctx.engine = engine;
|
||||
|
||||
cctx.recursion_stack_size = cctx.engine->max_recursion_level;
|
||||
cctx.recursion_stack = calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
|
||||
cctx.recursion_stack = calloc(sizeof(cli_scan_layer_t), cctx.recursion_stack_size);
|
||||
if (!cctx.recursion_stack) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
cctx.recursion_stack[cctx.recursion_level].fmap = map;
|
||||
cctx.recursion_stack[cctx.recursion_level].type = CL_TYPE_ANY; /* ANY for the top level, because we don't yet know the type. */
|
||||
cctx.recursion_stack[cctx.recursion_level].size = map->len;
|
||||
|
||||
cctx.fmap = cctx.recursion_stack[cctx.recursion_level].fmap;
|
||||
|
||||
memset(&dbg_state, 0, sizeof(dbg_state));
|
||||
dbg_state.file = "<libclamav>";
|
||||
dbg_state.line = 0;
|
||||
|
@ -453,11 +445,18 @@ int main(int argc, char *argv[])
|
|||
optfree(opts);
|
||||
exit(5);
|
||||
}
|
||||
map = fmap(fd, 0, 0, opt->strarg);
|
||||
|
||||
map = fmap_new(fd, 0, 0, opt->strarg, opt->strarg);
|
||||
if (!map) {
|
||||
fprintf(stderr, "Unable to map input file %s\n", opt->strarg);
|
||||
exit(5);
|
||||
}
|
||||
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
cctx.recursion_stack[cctx.recursion_level].fmap = map;
|
||||
cctx.recursion_stack[cctx.recursion_level].type = CL_TYPE_ANY; /* ANY for the top level, because we don't yet know the type. */
|
||||
cctx.recursion_stack[cctx.recursion_level].size = map->len;
|
||||
|
||||
rc = cli_bytecode_context_setfile(ctx, map);
|
||||
if (rc != CL_SUCCESS) {
|
||||
fprintf(stderr, "Unable to set file %s: %s\n", opt->strarg, cl_strerror(rc));
|
||||
|
@ -465,10 +464,15 @@ int main(int argc, char *argv[])
|
|||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
/* for testing */
|
||||
ctx->hooks.match_counts = deadbeefcounts;
|
||||
ctx->hooks.match_offsets = deadbeefcounts;
|
||||
rc = cli_bytecode_run(&bcs, bc, ctx);
|
||||
|
||||
/*
|
||||
* Run the bytecode.
|
||||
*/
|
||||
rc = cli_bytecode_run(&bcs, bc, ctx);
|
||||
if (rc != CL_SUCCESS) {
|
||||
fprintf(stderr, "Unable to run bytecode: %s\n", cl_strerror(rc));
|
||||
} else {
|
||||
|
@ -479,12 +483,15 @@ int main(int argc, char *argv[])
|
|||
if (debug_flag)
|
||||
printf("[clambc] Bytecode returned: 0x%llx\n", (long long)v);
|
||||
}
|
||||
|
||||
cli_bytecode_context_destroy(ctx);
|
||||
if (map)
|
||||
funmap(map);
|
||||
cl_engine_free(engine);
|
||||
fmap_free(map);
|
||||
if (cctx.recursion_stack[cctx.recursion_level].evidence) {
|
||||
evidence_free(cctx.recursion_stack[cctx.recursion_level].evidence);
|
||||
}
|
||||
free(cctx.recursion_stack);
|
||||
evidence_free(cctx.evidence);
|
||||
cl_engine_free(engine);
|
||||
}
|
||||
cli_bytecode_destroy(bc);
|
||||
cli_bytecode_done(&bcs);
|
||||
|
|
|
@ -616,8 +616,12 @@ int main(int argc, char **argv)
|
|||
|
||||
cl_engine_set_clcb_virus_found(engine, clamd_virus_found_cb);
|
||||
|
||||
if (optget(opts, "LeaveTemporaryFiles")->enabled)
|
||||
if (optget(opts, "LeaveTemporaryFiles")->enabled) {
|
||||
/* Set the engine to keep temporary files */
|
||||
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
|
||||
/* Also set the engine to create temporary directory structure */
|
||||
cl_engine_set_num(engine, CL_ENGINE_TMPDIR_RECURSION, 1);
|
||||
}
|
||||
|
||||
if (optget(opts, "ForceToDisk")->enabled)
|
||||
cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
|
||||
|
@ -705,6 +709,12 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (optget(opts, "FIPSCryptoHashLimits")->enabled) {
|
||||
dboptions |= CL_DB_FIPS_LIMITS;
|
||||
cl_engine_set_num(engine, CL_ENGINE_FIPS_LIMITS, 1);
|
||||
logg(LOGG_INFO_NF, "FIPS crypto hash limits enabled.\n");
|
||||
}
|
||||
|
||||
if ((ret = cl_load(dbdir, engine, &sigs, dboptions))) {
|
||||
logg(LOGG_ERROR, "%s\n", cl_strerror(ret));
|
||||
ret = 1;
|
||||
|
|
|
@ -94,7 +94,7 @@ void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, vo
|
|||
}
|
||||
}
|
||||
|
||||
void hash_callback(int fd, unsigned long long size, const unsigned char *md5, const char *virname, void *ctx)
|
||||
void hash_callback(int fd, unsigned long long size, const char *md5, const char *virname, void *ctx)
|
||||
{
|
||||
struct cb_context *c = ctx;
|
||||
UNUSEDPARAM(fd);
|
||||
|
@ -103,8 +103,8 @@ void hash_callback(int fd, unsigned long long size, const unsigned char *md5, co
|
|||
if (!c)
|
||||
return;
|
||||
c->virsize = size;
|
||||
strncpy(c->virhash, (const char *)md5, 32);
|
||||
c->virhash[32] = '\0';
|
||||
strncpy(c->virhash, md5, MD5_HASH_SIZE * 2);
|
||||
c->virhash[MD5_HASH_SIZE * 2] = '\0';
|
||||
}
|
||||
|
||||
void clamd_virus_found_cb(int fd, const char *virname, void *ctx)
|
||||
|
|
|
@ -69,7 +69,7 @@ cl_error_t scanfd(const client_conn_t *conn, unsigned long int *scanned, const s
|
|||
int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term);
|
||||
cl_error_t 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);
|
||||
void hash_callback(int fd, unsigned long long size, const char *md5, const char *virname, void *ctx);
|
||||
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx);
|
||||
void clamd_virus_found_cb(int fd, const char *virname, void *context);
|
||||
|
||||
|
|
|
@ -1379,11 +1379,6 @@ int recvloop(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigne
|
|||
options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED;
|
||||
}
|
||||
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
if (optget(opts, "DevCollectHashes")->enabled)
|
||||
options.dev |= CL_SCAN_DEV_COLLECT_SHA;
|
||||
#endif
|
||||
|
||||
if (optget(opts, "GenerateMetadataJson")->enabled) {
|
||||
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
|
||||
}
|
||||
|
@ -1396,6 +1391,10 @@ int recvloop(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigne
|
|||
options.general |= CL_SCAN_GENERAL_STORE_PDF_URIS;
|
||||
}
|
||||
|
||||
if (optget(opts, "JsonStoreExtraHashes")->enabled) {
|
||||
options.general |= CL_SCAN_GENERAL_STORE_EXTRA_HASHES;
|
||||
}
|
||||
|
||||
selfchk = optget(opts, "SelfCheck")->numarg;
|
||||
if (!selfchk) {
|
||||
logg(LOGG_INFO, "Self checking disabled.\n");
|
||||
|
|
|
@ -60,10 +60,22 @@ struct s_info info;
|
|||
short recursion = 0, bell = 0;
|
||||
short printinfected = 0, printclean = 1;
|
||||
|
||||
static void loggBytes(uint64_t bytes)
|
||||
{
|
||||
if (bytes >= (1024 * 1024 * 1024)) {
|
||||
logg(LOGG_INFO, "%.02f GiB", bytes / (double)(1024 * 1024 * 1024));
|
||||
} else if (bytes >= (1024 * 1024)) {
|
||||
logg(LOGG_INFO, "%.02f MiB", bytes / (double)(1024 * 1024));
|
||||
} else if (bytes >= 1024) {
|
||||
logg(LOGG_INFO, "%.02f KiB", bytes / (double)(1024));
|
||||
} else {
|
||||
logg(LOGG_INFO, "%" PRIu64 " B", bytes);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ds, dms, ret;
|
||||
double mb, rmb;
|
||||
struct timeval t1, t2;
|
||||
time_t date_start, date_end;
|
||||
|
||||
|
@ -195,10 +207,15 @@ int main(int argc, char **argv)
|
|||
if (notmoved) {
|
||||
logg(LOGG_INFO, "Not %s: %u\n", optget(opts, "copy")->enabled ? "moved" : "copied", notmoved);
|
||||
}
|
||||
mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
|
||||
logg(LOGG_INFO, "Data scanned: %2.2lf MB\n", mb);
|
||||
rmb = info.rblocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
|
||||
logg(LOGG_INFO, "Data read: %2.2lf MB (ratio %.2f:1)\n", rmb, info.rblocks ? (double)info.blocks / (double)info.rblocks : 0);
|
||||
|
||||
logg(LOGG_INFO, "Data scanned: ");
|
||||
loggBytes(info.bytes_scanned);
|
||||
logg(LOGG_INFO, "\n");
|
||||
|
||||
logg(LOGG_INFO, "Data read: ");
|
||||
loggBytes(info.bytes_read);
|
||||
logg(LOGG_INFO, " (ratio %.2f:1)\n", info.bytes_read ? (double)info.bytes_scanned / (double)info.bytes_read : 0);
|
||||
|
||||
logg(LOGG_INFO, "Time: %u.%3.3u sec (%u m %u s)\n", ds, dms / 1000, ds / 60, ds % 60);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -238,117 +255,135 @@ void help(void)
|
|||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " clamscan [options] [file/directory/-]\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --help -h Show this help\n");
|
||||
mprintf(LOGG_INFO, " --version -V Print version number\n");
|
||||
mprintf(LOGG_INFO, " --verbose -v Be verbose\n");
|
||||
mprintf(LOGG_INFO, " --archive-verbose -a Show filenames inside scanned archives\n");
|
||||
mprintf(LOGG_INFO, " --debug Enable libclamav's debug messages\n");
|
||||
mprintf(LOGG_INFO, " --quiet Only output error messages\n");
|
||||
mprintf(LOGG_INFO, " --help -h Show this help.\n");
|
||||
mprintf(LOGG_INFO, " --version -V Print version number.\n");
|
||||
mprintf(LOGG_INFO, " --verbose -v Be verbose.\n");
|
||||
mprintf(LOGG_INFO, " --archive-verbose -a Show filenames inside scanned archives.\n");
|
||||
mprintf(LOGG_INFO, " --debug Enable libclamav's debug messages.\n");
|
||||
mprintf(LOGG_INFO, " --quiet Only output error messages.\n");
|
||||
mprintf(LOGG_INFO, " --stdout Write to stdout instead of stderr. Does not affect 'debug' messages.\n");
|
||||
mprintf(LOGG_INFO, " --no-summary Disable summary at end of scanning\n");
|
||||
mprintf(LOGG_INFO, " --infected -i Only print infected files\n");
|
||||
mprintf(LOGG_INFO, " --suppress-ok-results -o Skip printing OK files\n");
|
||||
mprintf(LOGG_INFO, " --bell Sound bell on virus detection\n");
|
||||
mprintf(LOGG_INFO, " --no-summary Disable summary at end of scanning.\n");
|
||||
mprintf(LOGG_INFO, " --infected -i Only print infected files.\n");
|
||||
mprintf(LOGG_INFO, " --suppress-ok-results -o Skip printing OK files.\n");
|
||||
mprintf(LOGG_INFO, " --bell Sound bell on virus detection.\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY\n");
|
||||
mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files\n");
|
||||
mprintf(LOGG_INFO, " --force-to-disk[=yes/no(*)] Create temporary files for nested file scans that would otherwise be in-memory only\n");
|
||||
mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY.\n");
|
||||
mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files.\n");
|
||||
mprintf(LOGG_INFO, " --force-to-disk[=yes/no(*)] Create temporary files for nested file scans that would otherwise be in-memory only.\n");
|
||||
mprintf(LOGG_INFO, " --gen-json[=yes/no(*)] Generate JSON metadata for the scanned file(s). For testing & development use ONLY.\n");
|
||||
mprintf(LOGG_INFO, " JSON will be printed if --debug is enabled.\n");
|
||||
mprintf(LOGG_INFO, " A JSON file will dropped to the temp directory if --leave-temps is enabled.\n");
|
||||
mprintf(LOGG_INFO, " --json-store-html-uris[=yes(*)/no] Store html URIs in metadata.\n");
|
||||
mprintf(LOGG_INFO, " URLs will be written to the metadata.json file in an array called 'URIs'\n");
|
||||
mprintf(LOGG_INFO, " --json-store-pdf-uris[=yes(*)/no] Store pdf URIs in metadata.\n");
|
||||
mprintf(LOGG_INFO, " URLs will be written to the metadata.json file in an array called 'URIs'\n");
|
||||
mprintf(LOGG_INFO, " --database=FILE/DIR -d FILE/DIR Load virus database from FILE or load all supported db files from DIR\n");
|
||||
mprintf(LOGG_INFO, " --official-db-only[=yes/no(*)] Only load official signatures\n");
|
||||
mprintf(LOGG_INFO, " URIs will be written to the metadata.json file in an array called 'URIs'.\n");
|
||||
mprintf(LOGG_INFO, " --json-store-pdf-uris[=yes(*)/no] Store pdf URIs in metadata.\n");
|
||||
mprintf(LOGG_INFO, " URIs will be written to the metadata.json file in an array called 'URIs'.\n");
|
||||
mprintf(LOGG_INFO, " --json-store-extra-hashes[=yes(*)/no] Store md5 and sha1 in addition to sha2-256 in metadata.\n");
|
||||
mprintf(LOGG_INFO, " --database=FILE/DIR -d FILE/DIR Load virus database from FILE or load all supported db files from DIR.\n");
|
||||
mprintf(LOGG_INFO, " --official-db-only[=yes/no(*)] Only load official signatures.\n");
|
||||
mprintf(LOGG_INFO, " --fail-if-cvd-older-than=days Return with a nonzero error code if virus database outdated.\n");
|
||||
mprintf(LOGG_INFO, " --log=FILE -l FILE Save scan report to FILE\n");
|
||||
mprintf(LOGG_INFO, " --recursive[=yes/no(*)] -r Scan subdirectories recursively\n");
|
||||
mprintf(LOGG_INFO, " --allmatch[=yes/no(*)] -z Continue scanning within file after finding a match\n");
|
||||
mprintf(LOGG_INFO, " --cross-fs[=yes(*)/no] Scan files and directories on other filesystems\n");
|
||||
mprintf(LOGG_INFO, " --follow-dir-symlinks[=0/1(*)/2] Follow directory symlinks (0 = never, 1 = direct, 2 = always)\n");
|
||||
mprintf(LOGG_INFO, " --follow-file-symlinks[=0/1(*)/2] Follow file symlinks (0 = never, 1 = direct, 2 = always)\n");
|
||||
mprintf(LOGG_INFO, " --file-list=FILE -f FILE Scan files from FILE\n");
|
||||
mprintf(LOGG_INFO, " --log=FILE -l FILE Save scan report to FILE.\n");
|
||||
mprintf(LOGG_INFO, " --recursive[=yes/no(*)] -r Scan subdirectories recursively.\n");
|
||||
mprintf(LOGG_INFO, " --allmatch[=yes/no(*)] -z Continue scanning within file after finding a match.\n");
|
||||
mprintf(LOGG_INFO, " --cross-fs[=yes(*)/no] Scan files and directories on other filesystems.\n");
|
||||
mprintf(LOGG_INFO, " --follow-dir-symlinks[=0/1(*)/2] Follow directory symlinks (0 = never, 1 = direct, 2 = always).\n");
|
||||
mprintf(LOGG_INFO, " --follow-file-symlinks[=0/1(*)/2] Follow file symlinks (0 = never, 1 = direct, 2 = always).\n");
|
||||
mprintf(LOGG_INFO, " --file-list=FILE -f FILE Scan files from FILE.\n");
|
||||
mprintf(LOGG_INFO, " --remove[=yes/no(*)] Remove infected files. Be careful!\n");
|
||||
mprintf(LOGG_INFO, " --move=DIRECTORY Move infected files into DIRECTORY\n");
|
||||
mprintf(LOGG_INFO, " --copy=DIRECTORY Copy infected files into DIRECTORY\n");
|
||||
mprintf(LOGG_INFO, " --exclude=REGEX Don't scan file names matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --exclude-dir=REGEX Don't scan directories matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --include=REGEX Only scan file names matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --include-dir=REGEX Only scan directories matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --move=DIRECTORY Move infected files into DIRECTORY.\n");
|
||||
mprintf(LOGG_INFO, " --copy=DIRECTORY Copy infected files into DIRECTORY.\n");
|
||||
mprintf(LOGG_INFO, " --exclude=REGEX Don't scan file names matching REGEX.\n");
|
||||
mprintf(LOGG_INFO, " --exclude-dir=REGEX Don't scan directories matching REGEX.\n");
|
||||
mprintf(LOGG_INFO, " --include=REGEX Only scan file names matching REGEX.\n");
|
||||
mprintf(LOGG_INFO, " --include-dir=REGEX Only scan directories matching REGEX.\n");
|
||||
#ifdef _WIN32
|
||||
mprintf(LOGG_INFO, " --memory Scan loaded executable modules\n");
|
||||
mprintf(LOGG_INFO, " --kill Kill/Unload infected loaded modules\n");
|
||||
mprintf(LOGG_INFO, " --unload Unload infected modules from processes\n");
|
||||
mprintf(LOGG_INFO, " --memory Scan loaded executable modules.\n");
|
||||
mprintf(LOGG_INFO, " --kill Kill/Unload infected loaded modules.\n");
|
||||
mprintf(LOGG_INFO, " --unload Unload infected modules from processes.\n");
|
||||
#endif
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --bytecode[=yes(*)/no] Load bytecode from the database\n");
|
||||
mprintf(LOGG_INFO, " --bytecode-unsigned[=yes/no(*)] Load unsigned bytecode\n");
|
||||
mprintf(LOGG_INFO, " --bytecode[=yes(*)/no] Load bytecode from the database.\n");
|
||||
mprintf(LOGG_INFO, " --bytecode-unsigned[=yes/no(*)] Load unsigned bytecode.\n");
|
||||
mprintf(LOGG_INFO, " **Caution**: You should NEVER run bytecode signatures from untrusted sources.\n");
|
||||
mprintf(LOGG_INFO, " Doing so may result in arbitrary code execution.\n");
|
||||
mprintf(LOGG_INFO, " --bytecode-timeout=N Set bytecode timeout (in milliseconds)\n");
|
||||
mprintf(LOGG_INFO, " --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics\n");
|
||||
mprintf(LOGG_INFO, " --detect-pua[=yes/no(*)] Detect Possibly Unwanted Applications\n");
|
||||
mprintf(LOGG_INFO, " --exclude-pua=CAT Skip PUA sigs of category CAT\n");
|
||||
mprintf(LOGG_INFO, " --include-pua=CAT Load PUA sigs of category CAT\n");
|
||||
mprintf(LOGG_INFO, " --detect-structured[=yes/no(*)] Detect structured data (SSN, Credit Card)\n");
|
||||
mprintf(LOGG_INFO, " --structured-ssn-format=X SSN format (0=normal,1=stripped,2=both)\n");
|
||||
mprintf(LOGG_INFO, " --structured-ssn-count=N Min SSN count to generate a detect\n");
|
||||
mprintf(LOGG_INFO, " --structured-cc-count=N Min CC count to generate a detect\n");
|
||||
mprintf(LOGG_INFO, " --structured-cc-mode=X CC mode (0=credit debit and private label, 1=credit cards only\n");
|
||||
mprintf(LOGG_INFO, " --scan-mail[=yes(*)/no] Scan mail files\n");
|
||||
mprintf(LOGG_INFO, " --phishing-sigs[=yes(*)/no] Enable email signature-based phishing detection\n");
|
||||
mprintf(LOGG_INFO, " --phishing-scan-urls[=yes(*)/no] Enable URL signature-based phishing detection\n");
|
||||
mprintf(LOGG_INFO, " --heuristic-alerts[=yes(*)/no] Heuristic alerts\n");
|
||||
mprintf(LOGG_INFO, " --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found\n");
|
||||
mprintf(LOGG_INFO, " --normalize[=yes(*)/no] Normalize html, script, and text files. Use normalize=no for yara compatibility\n");
|
||||
mprintf(LOGG_INFO, " --scan-pe[=yes(*)/no] Scan PE files\n");
|
||||
mprintf(LOGG_INFO, " --scan-elf[=yes(*)/no] Scan ELF files\n");
|
||||
mprintf(LOGG_INFO, " --scan-ole2[=yes(*)/no] Scan OLE2 containers\n");
|
||||
mprintf(LOGG_INFO, " --scan-pdf[=yes(*)/no] Scan PDF files\n");
|
||||
mprintf(LOGG_INFO, " --scan-swf[=yes(*)/no] Scan SWF files\n");
|
||||
mprintf(LOGG_INFO, " --scan-html[=yes(*)/no] Scan HTML files\n");
|
||||
mprintf(LOGG_INFO, " --scan-xmldocs[=yes(*)/no] Scan xml-based document files\n");
|
||||
mprintf(LOGG_INFO, " --scan-hwp3[=yes(*)/no] Scan HWP3 files\n");
|
||||
mprintf(LOGG_INFO, " --scan-onenote[=yes(*)/no] Scan OneNote files\n");
|
||||
mprintf(LOGG_INFO, " --scan-archive[=yes(*)/no] Scan archive files (supported by libclamav)\n");
|
||||
mprintf(LOGG_INFO, " --scan-image[=yes(*)/no] Scan image (graphics) files\n");
|
||||
mprintf(LOGG_INFO, " --scan-image-fuzzy-hash[=yes(*)/no] Detect files by calculating image (graphics) fuzzy hashes\n");
|
||||
mprintf(LOGG_INFO, " --alert-broken[=yes/no(*)] Alert on broken executable files (PE & ELF)\n");
|
||||
mprintf(LOGG_INFO, " --alert-broken-media[=yes/no(*)] Alert on broken graphics files (JPEG, TIFF, PNG, GIF)\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted[=yes/no(*)] Alert on encrypted archives and documents\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted-doc[=yes/no(*)] Alert on encrypted documents\n");
|
||||
mprintf(LOGG_INFO, " --alert-macros[=yes/no(*)] Alert on OLE2 files containing VBA macros\n");
|
||||
mprintf(LOGG_INFO, " --alert-exceeds-max[=yes/no(*)] Alert on files that exceed max file size, max scan size, or max recursion limit\n");
|
||||
mprintf(LOGG_INFO, " --alert-phishing-ssl[=yes/no(*)] Alert on emails containing SSL mismatches in URLs\n");
|
||||
mprintf(LOGG_INFO, " --alert-phishing-cloak[=yes/no(*)] Alert on emails containing cloaked URLs\n");
|
||||
mprintf(LOGG_INFO, " --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections\n");
|
||||
mprintf(LOGG_INFO, " --nocerts Disable authenticode certificate chain verification in PE files\n");
|
||||
mprintf(LOGG_INFO, " --dumpcerts Dump authenticode certificate chain in PE files\n");
|
||||
mprintf(LOGG_INFO, " --bytecode-timeout=N Set bytecode timeout (in milliseconds).\n");
|
||||
mprintf(LOGG_INFO, " --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics.\n");
|
||||
mprintf(LOGG_INFO, " --detect-pua[=yes/no(*)] Detect Possibly Unwanted Applications.\n");
|
||||
mprintf(LOGG_INFO, " --exclude-pua=CAT Skip PUA sigs of category CAT.\n");
|
||||
mprintf(LOGG_INFO, " --include-pua=CAT Load PUA sigs of category CAT.\n");
|
||||
mprintf(LOGG_INFO, " --detect-structured[=yes/no(*)] Detect structured data (SSN, Credit Card).\n");
|
||||
mprintf(LOGG_INFO, " --structured-ssn-format=X SSN format (0=normal,1=stripped,2=both).\n");
|
||||
mprintf(LOGG_INFO, " --structured-ssn-count=N Min SSN count to generate a detect.\n");
|
||||
mprintf(LOGG_INFO, " --structured-cc-count=N Min CC count to generate a detect.\n");
|
||||
mprintf(LOGG_INFO, " --structured-cc-mode=X CC mode (0=credit debit and private label, 1=credit cards only.\n");
|
||||
mprintf(LOGG_INFO, " --scan-mail[=yes(*)/no] Scan mail files.\n");
|
||||
mprintf(LOGG_INFO, " --phishing-sigs[=yes(*)/no] Enable email signature-based phishing detection.\n");
|
||||
mprintf(LOGG_INFO, " --phishing-scan-urls[=yes(*)/no] Enable URL signature-based phishing detection.\n");
|
||||
mprintf(LOGG_INFO, " --heuristic-alerts[=yes(*)/no] Heuristic alerts.\n");
|
||||
mprintf(LOGG_INFO, " --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found.\n");
|
||||
mprintf(LOGG_INFO, " --normalize[=yes(*)/no] Normalize html, script, and text files. Use normalize=no for yara compatibility.\n");
|
||||
mprintf(LOGG_INFO, " --scan-pe[=yes(*)/no] Scan PE files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-elf[=yes(*)/no] Scan ELF files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-ole2[=yes(*)/no] Scan OLE2 containers.\n");
|
||||
mprintf(LOGG_INFO, " --scan-pdf[=yes(*)/no] Scan PDF files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-swf[=yes(*)/no] Scan SWF files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-html[=yes(*)/no] Scan HTML files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-xmldocs[=yes(*)/no] Scan xml-based document files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-hwp3[=yes(*)/no] Scan HWP3 files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-onenote[=yes(*)/no] Scan OneNote files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-archive[=yes(*)/no] Scan archive files (supported by libclamav).\n");
|
||||
mprintf(LOGG_INFO, " --scan-image[=yes(*)/no] Scan image (graphics) files.\n");
|
||||
mprintf(LOGG_INFO, " --scan-image-fuzzy-hash[=yes(*)/no] Detect files by calculating image (graphics) fuzzy hashes.\n");
|
||||
mprintf(LOGG_INFO, " --alert-broken[=yes/no(*)] Alert on broken executable files (PE & ELF).\n");
|
||||
mprintf(LOGG_INFO, " --alert-broken-media[=yes/no(*)] Alert on broken graphics files (JPEG, TIFF, PNG, GIF).\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted[=yes/no(*)] Alert on encrypted archives and documents.\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives.\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted-doc[=yes/no(*)] Alert on encrypted documents.\n");
|
||||
mprintf(LOGG_INFO, " --alert-macros[=yes/no(*)] Alert on OLE2 files containing VBA macros.\n");
|
||||
mprintf(LOGG_INFO, " --alert-exceeds-max[=yes/no(*)] Alert on files that exceed max file size, max scan size, or max recursion limit.\n");
|
||||
mprintf(LOGG_INFO, " --alert-phishing-ssl[=yes/no(*)] Alert on emails containing SSL mismatches in URLs.\n");
|
||||
mprintf(LOGG_INFO, " --alert-phishing-cloak[=yes/no(*)] Alert on emails containing cloaked URLs.\n");
|
||||
mprintf(LOGG_INFO, " --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections.\n");
|
||||
mprintf(LOGG_INFO, " --nocerts Disable authenticode certificate chain verification in PE files.\n");
|
||||
mprintf(LOGG_INFO, " --dumpcerts Dump authenticode certificate chain in PE files.\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --max-scantime=#n Scan time longer than this will be skipped and assumed clean (milliseconds)\n");
|
||||
mprintf(LOGG_INFO, " --max-filesize=#n Files larger than this will be skipped and assumed clean\n");
|
||||
mprintf(LOGG_INFO, " --max-scansize=#n The maximum amount of data to scan for each container file (**)\n");
|
||||
mprintf(LOGG_INFO, " --max-files=#n The maximum number of files to scan for each container file (**)\n");
|
||||
mprintf(LOGG_INFO, " --max-recursion=#n Maximum archive recursion level for container file (**)\n");
|
||||
mprintf(LOGG_INFO, " --max-dir-recursion=#n Maximum directory recursion level\n");
|
||||
mprintf(LOGG_INFO, " --max-embeddedpe=#n Maximum size file to check for embedded PE\n");
|
||||
mprintf(LOGG_INFO, " --max-htmlnormalize=#n Maximum size of HTML file to normalize\n");
|
||||
mprintf(LOGG_INFO, " --max-htmlnotags=#n Maximum size of normalized HTML file to scan\n");
|
||||
mprintf(LOGG_INFO, " --max-scriptnormalize=#n Maximum size of script file to normalize\n");
|
||||
mprintf(LOGG_INFO, " --max-ziptypercg=#n Maximum size zip to type reanalyze\n");
|
||||
mprintf(LOGG_INFO, " --max-partitions=#n Maximum number of partitions in disk image to be scanned\n");
|
||||
mprintf(LOGG_INFO, " --max-iconspe=#n Maximum number of icons in PE file to be scanned\n");
|
||||
mprintf(LOGG_INFO, " --max-rechwp3=#n Maximum recursive calls to HWP3 parsing function\n");
|
||||
mprintf(LOGG_INFO, " --max-scantime=#n Scan time longer than this will be skipped and assumed clean (milliseconds).\n");
|
||||
mprintf(LOGG_INFO, " --max-filesize=#n Files larger than this will be skipped and assumed clean.\n");
|
||||
mprintf(LOGG_INFO, " --max-scansize=#n The maximum amount of data to scan for each container file (**).\n");
|
||||
mprintf(LOGG_INFO, " --max-files=#n The maximum number of files to scan for each container file (**).\n");
|
||||
mprintf(LOGG_INFO, " --max-recursion=#n Maximum archive recursion level for container file (**).\n");
|
||||
mprintf(LOGG_INFO, " --max-dir-recursion=#n Maximum directory recursion level.\n");
|
||||
mprintf(LOGG_INFO, " --max-embeddedpe=#n Maximum size file to check for embedded PE.\n");
|
||||
mprintf(LOGG_INFO, " --max-htmlnormalize=#n Maximum size of HTML file to normalize.\n");
|
||||
mprintf(LOGG_INFO, " --max-htmlnotags=#n Maximum size of normalized HTML file to scan.\n");
|
||||
mprintf(LOGG_INFO, " --max-scriptnormalize=#n Maximum size of script file to normalize.\n");
|
||||
mprintf(LOGG_INFO, " --max-ziptypercg=#n Maximum size zip to type reanalyze.\n");
|
||||
mprintf(LOGG_INFO, " --max-partitions=#n Maximum number of partitions in disk image to be scanned.\n");
|
||||
mprintf(LOGG_INFO, " --max-iconspe=#n Maximum number of icons in PE file to be scanned.\n");
|
||||
mprintf(LOGG_INFO, " --max-rechwp3=#n Maximum recursive calls to HWP3 parsing function.\n");
|
||||
mprintf(LOGG_INFO, " --pcre-match-limit=#n Maximum calls to the PCRE match function.\n");
|
||||
mprintf(LOGG_INFO, " --pcre-recmatch-limit=#n Maximum recursive calls to the PCRE match function.\n");
|
||||
mprintf(LOGG_INFO, " --pcre-max-filesize=#n Maximum size file to perform PCRE subsig matching.\n");
|
||||
mprintf(LOGG_INFO, " --disable-cache Disable caching and cache checks for hash sums of scanned files.\n");
|
||||
mprintf(LOGG_INFO, " --hash-hint The file hash so that libclamav does not need to calculate it.\n");
|
||||
mprintf(LOGG_INFO, " The type of hash must match the '--hash-alg'.\n");
|
||||
mprintf(LOGG_INFO, " --log-hash Print the file hash after each file scanned.\n");
|
||||
mprintf(LOGG_INFO, " The type of hash printed will match the '--hash-alg'.\n");
|
||||
mprintf(LOGG_INFO, " --hash-alg The hashing algorithm used for either '--hash-hint' or '--log-hash'.\n");
|
||||
mprintf(LOGG_INFO, " Supported algorithms are 'md5', 'sha1', 'sha2-256'.\n");
|
||||
mprintf(LOGG_INFO, " If not specified, the default is 'sha2-256'.\n");
|
||||
mprintf(LOGG_INFO, " --file-type-hint The file type hint so that libclamav can optimize scanning.\n");
|
||||
mprintf(LOGG_INFO, " E.g. 'pe', 'elf', 'zip', etc.\n");
|
||||
mprintf(LOGG_INFO, " You may also use ClamAV type names such as 'CL_TYPE_PE'.\n");
|
||||
mprintf(LOGG_INFO, " ClamAV will ignore the hint if it is not familiar with the specified type.\n");
|
||||
mprintf(LOGG_INFO, " See also: https://docs.clamav.net/appendix/FileTypes.html#file-types\n");
|
||||
mprintf(LOGG_INFO, " --log-file-type Print the file type after each file scanned.\n");
|
||||
mprintf(LOGG_INFO, " --cvdcertsdir=DIRECTORY Specify a directory containing the root\n");
|
||||
mprintf(LOGG_INFO, " CA cert needed to verify detached CVD digital signatures.\n");
|
||||
mprintf(LOGG_INFO, " If not provided, then clamscan will look in the default directory.\n");
|
||||
mprintf(LOGG_INFO, " --fips-limits Enforce FIPS-like limits on using hash algorithms for\n");
|
||||
mprintf(LOGG_INFO, " cryptographic purposes. Will disable MD5 & SHA1.\n");
|
||||
mprintf(LOGG_INFO, " FP sigs and will require '.sign' files to verify CVD\n");
|
||||
mprintf(LOGG_INFO, " authenticity.\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, "Environment Variables:\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
#define __GLOBAL_H
|
||||
|
||||
struct s_info {
|
||||
unsigned int sigs; /* number of signatures */
|
||||
unsigned int dirs; /* number of scanned directories */
|
||||
unsigned int files; /* number of scanned files */
|
||||
unsigned int ifiles; /* number of infected files */
|
||||
unsigned int errors; /* number of errors */
|
||||
unsigned long int blocks; /* number of *scanned* 16kb blocks */
|
||||
unsigned long int rblocks; /* number of *read* 16kb blocks */
|
||||
unsigned int sigs; /* number of signatures */
|
||||
unsigned int dirs; /* number of scanned directories */
|
||||
unsigned int files; /* number of scanned files */
|
||||
unsigned int ifiles; /* number of infected files */
|
||||
unsigned int errors; /* number of errors */
|
||||
uint64_t bytes_scanned; /* number of *scanned* bytes */
|
||||
uint64_t bytes_read; /* number of *read* bytes */
|
||||
};
|
||||
|
||||
extern struct s_info info;
|
||||
|
|
|
@ -181,7 +181,7 @@ static int print_chain(struct metachain *c, char *str, size_t len)
|
|||
return i == c->nchains - 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
static cl_error_t post(int fd, int result, const char *virname, void *context)
|
||||
static cl_error_t post(int fd, int result, const char *alert_name, void *context)
|
||||
{
|
||||
struct clamscan_cb_data *d = context;
|
||||
struct metachain *c = NULL;
|
||||
|
@ -196,10 +196,10 @@ static cl_error_t post(int fd, int result, const char *virname, void *context)
|
|||
if (c && c->nchains) {
|
||||
print_chain(c, str, sizeof(str));
|
||||
|
||||
if (c->level == c->lastadd && !virname)
|
||||
if (c->level == c->lastadd && !alert_name)
|
||||
free(c->chains[--c->nchains]);
|
||||
|
||||
if (virname && !c->lastvir)
|
||||
if (alert_name && !c->lastvir)
|
||||
c->lastvir = c->level;
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ static cl_error_t meta(const char *container_type, unsigned long fsize_container
|
|||
return CL_CLEAN;
|
||||
}
|
||||
|
||||
static void clamscan_virus_found_cb(int fd, const char *virname, void *context)
|
||||
static void clamscan_virus_found_cb(int fd, const char *alert_name, void *context)
|
||||
{
|
||||
struct clamscan_cb_data *data = (struct clamscan_cb_data *)context;
|
||||
const char *filename;
|
||||
|
@ -288,20 +288,29 @@ static void clamscan_virus_found_cb(int fd, const char *virname, void *context)
|
|||
filename = data->filename;
|
||||
else
|
||||
filename = "(filename not set)";
|
||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, virname);
|
||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, alert_name);
|
||||
return;
|
||||
}
|
||||
|
||||
static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
|
||||
{
|
||||
cl_error_t ret = CL_SUCCESS;
|
||||
int fd, included;
|
||||
int fd = -1;
|
||||
int included = 0;
|
||||
unsigned i;
|
||||
const struct optstruct *opt;
|
||||
const char *virname = NULL;
|
||||
cl_verdict_t verdict = CL_VERDICT_NOTHING_FOUND;
|
||||
const char *alert_name = NULL;
|
||||
STATBUF sb;
|
||||
struct metachain chain;
|
||||
struct clamscan_cb_data data;
|
||||
struct metachain chain = {0};
|
||||
struct clamscan_cb_data data = {0};
|
||||
const char *hash_hint = NULL;
|
||||
char **hash_out = NULL;
|
||||
char *hash = NULL;
|
||||
const char *hash_alg = NULL;
|
||||
const char *file_type_hint = NULL;
|
||||
char **file_type_out = NULL;
|
||||
char *file_type = NULL;
|
||||
|
||||
char *real_filename = NULL;
|
||||
|
||||
|
@ -369,7 +378,7 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
|
|||
goto done;
|
||||
}
|
||||
|
||||
info.rblocks += sb.st_size / CL_COUNT_PRECISION;
|
||||
info.bytes_read += sb.st_size;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -399,6 +408,22 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
|
|||
}
|
||||
}
|
||||
|
||||
if ((opt = optget(opts, "hash-alg"))->enabled) {
|
||||
hash_alg = opt->strarg;
|
||||
}
|
||||
if ((opt = optget(opts, "hash-hint"))->enabled) {
|
||||
hash_hint = opt->strarg;
|
||||
}
|
||||
if ((opt = optget(opts, "log-hash"))->enabled) {
|
||||
hash_out = &hash;
|
||||
}
|
||||
if ((opt = optget(opts, "file-type-hint"))->enabled) {
|
||||
file_type_hint = opt->strarg;
|
||||
}
|
||||
if ((opt = optget(opts, "log-file-type"))->enabled) {
|
||||
file_type_out = &file_type;
|
||||
}
|
||||
|
||||
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||
|
||||
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) {
|
||||
|
@ -409,47 +434,104 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
|
|||
|
||||
data.chain = &chain;
|
||||
data.filename = filename;
|
||||
if ((ret = cl_scandesc_callback(fd, filename, &virname, &info.blocks, engine, options, &data)) == CL_VIRUS) {
|
||||
if (optget(opts, "archive-verbose")->enabled) {
|
||||
if (chain.nchains > 1) {
|
||||
char str[128];
|
||||
int toolong = print_chain(&chain, str, sizeof(str));
|
||||
|
||||
logg(LOGG_INFO, "%s%s!(%llu)%s: %s FOUND\n", str, toolong ? "..." : "", (long long unsigned)(chain.lastvir - 1), chain.chains[chain.nchains - 1], virname);
|
||||
} else if (chain.lastvir) {
|
||||
logg(LOGG_INFO, "%s!(%llu): %s FOUND\n", filename, (long long unsigned)(chain.lastvir - 1), virname);
|
||||
ret = cl_scandesc_ex(
|
||||
fd,
|
||||
filename,
|
||||
&verdict,
|
||||
&alert_name,
|
||||
&info.bytes_scanned,
|
||||
engine, options,
|
||||
&data,
|
||||
hash_hint,
|
||||
hash_out,
|
||||
hash_alg,
|
||||
file_type_hint,
|
||||
file_type_out);
|
||||
|
||||
switch (verdict) {
|
||||
case CL_VERDICT_NOTHING_FOUND: {
|
||||
if (CL_SUCCESS == ret) {
|
||||
if (!printinfected && printclean) {
|
||||
mprintf(LOGG_INFO, "%s: OK\n", filename);
|
||||
}
|
||||
info.files++;
|
||||
} else {
|
||||
if (!printinfected)
|
||||
logg(LOGG_INFO, "%s: %s ERROR\n", filename, cl_strerror(ret));
|
||||
|
||||
info.errors++;
|
||||
}
|
||||
}
|
||||
info.files++;
|
||||
info.ifiles++;
|
||||
} break;
|
||||
|
||||
if (bell)
|
||||
fprintf(stderr, "\007");
|
||||
} else if (ret == CL_CLEAN) {
|
||||
if (!printinfected && printclean)
|
||||
mprintf(LOGG_INFO, "%s: OK\n", filename);
|
||||
case CL_VERDICT_TRUSTED: {
|
||||
// TODO: Option to print "TRUSTED" verdict instead of "OK"?
|
||||
if (!printinfected && printclean) {
|
||||
mprintf(LOGG_INFO, "%s: OK\n", filename);
|
||||
}
|
||||
info.files++;
|
||||
} break;
|
||||
|
||||
info.files++;
|
||||
} else {
|
||||
if (!printinfected)
|
||||
logg(LOGG_INFO, "%s: %s ERROR\n", filename, cl_strerror(ret));
|
||||
case CL_VERDICT_STRONG_INDICATOR:
|
||||
case CL_VERDICT_POTENTIALLY_UNWANTED: {
|
||||
if (optget(opts, "archive-verbose")->enabled) {
|
||||
if (chain.nchains > 1) {
|
||||
char str[128];
|
||||
int toolong = print_chain(&chain, str, sizeof(str));
|
||||
|
||||
info.errors++;
|
||||
logg(LOGG_INFO, "%s%s!(%llu)%s: %s FOUND\n", str, toolong ? "..." : "", (long long unsigned)(chain.lastvir - 1), chain.chains[chain.nchains - 1], alert_name);
|
||||
} else if (chain.lastvir) {
|
||||
logg(LOGG_INFO, "%s!(%llu): %s FOUND\n", filename, (long long unsigned)(chain.lastvir - 1), alert_name);
|
||||
}
|
||||
}
|
||||
info.files++;
|
||||
info.ifiles++;
|
||||
|
||||
if (bell) {
|
||||
fprintf(stderr, "\007");
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
for (i = 0; i < chain.nchains; i++)
|
||||
free(chain.chains[i]);
|
||||
if (NULL != hash) {
|
||||
if (hash_alg == NULL) {
|
||||
// libclamav defaults to sha2-256
|
||||
hash_alg = "sha2-256";
|
||||
}
|
||||
logg(LOGG_INFO, "%s FileHash: %s (%s)\n", filename, hash, hash_alg);
|
||||
}
|
||||
|
||||
free(chain.chains);
|
||||
close(fd);
|
||||
|
||||
if (ret == CL_VIRUS && action)
|
||||
action(filename);
|
||||
if (NULL != file_type) {
|
||||
logg(LOGG_INFO, "%s FileType: %s\n", filename, file_type);
|
||||
}
|
||||
|
||||
done:
|
||||
/*
|
||||
* Run the action callback if the file was infected.
|
||||
*/
|
||||
if (((verdict == CL_VERDICT_STRONG_INDICATOR) || (verdict == CL_VERDICT_POTENTIALLY_UNWANTED)) && action) {
|
||||
action(filename);
|
||||
}
|
||||
|
||||
if (NULL != hash) {
|
||||
free(hash);
|
||||
}
|
||||
if (NULL != file_type) {
|
||||
free(file_type);
|
||||
}
|
||||
if (NULL != chain.chains) {
|
||||
for (i = 0; i < chain.nchains; i++) {
|
||||
free(chain.chains[i]);
|
||||
}
|
||||
free(chain.chains);
|
||||
}
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
if (NULL != real_filename) {
|
||||
free(real_filename);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -565,16 +647,26 @@ static void scandirs(const char *dirname, struct cl_engine *engine, const struct
|
|||
}
|
||||
}
|
||||
|
||||
static int scanstdin(const struct cl_engine *engine, struct cl_scan_options *options)
|
||||
static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
|
||||
{
|
||||
int ret;
|
||||
unsigned int fsize = 0;
|
||||
const char *virname = NULL;
|
||||
const char *tmpdir = NULL;
|
||||
char *file, buff[FILEBUFF];
|
||||
cl_error_t ret;
|
||||
|
||||
size_t fsize = 0;
|
||||
cl_verdict_t verdict = CL_VERDICT_NOTHING_FOUND;
|
||||
const char *alert_name = NULL;
|
||||
const char *tmpdir = NULL;
|
||||
char *filename, buff[FILEBUFF];
|
||||
size_t bread;
|
||||
FILE *fs;
|
||||
struct clamscan_cb_data data;
|
||||
const struct optstruct *opt;
|
||||
const char *hash_hint = NULL;
|
||||
char **hash_out = NULL;
|
||||
char *hash = NULL;
|
||||
const char *hash_alg = NULL;
|
||||
const char *file_type_hint = NULL;
|
||||
char **file_type_out = NULL;
|
||||
char *file_type = NULL;
|
||||
|
||||
tmpdir = cl_engine_get_str(engine, CL_ENGINE_TMPDIR, NULL);
|
||||
if (NULL == tmpdir) {
|
||||
|
@ -586,22 +678,22 @@ static int scanstdin(const struct cl_engine *engine, struct cl_scan_options *opt
|
|||
return 2;
|
||||
}
|
||||
|
||||
if (!(file = cli_gentemp(tmpdir))) {
|
||||
if (!(filename = cli_gentemp(tmpdir))) {
|
||||
logg(LOGG_ERROR, "Can't generate tempfile name\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!(fs = fopen(file, "wb"))) {
|
||||
logg(LOGG_ERROR, "Can't open %s for writing\n", file);
|
||||
free(file);
|
||||
if (!(fs = fopen(filename, "wb"))) {
|
||||
logg(LOGG_ERROR, "Can't open %s for writing\n", filename);
|
||||
free(filename);
|
||||
return 2;
|
||||
}
|
||||
|
||||
while ((bread = fread(buff, 1, FILEBUFF, stdin))) {
|
||||
fsize += bread;
|
||||
if (fwrite(buff, 1, bread, fs) < bread) {
|
||||
logg(LOGG_ERROR, "Can't write to %s\n", file);
|
||||
free(file);
|
||||
logg(LOGG_ERROR, "Can't write to %s\n", filename);
|
||||
free(filename);
|
||||
fclose(fs);
|
||||
return 2;
|
||||
}
|
||||
|
@ -609,30 +701,98 @@ static int scanstdin(const struct cl_engine *engine, struct cl_scan_options *opt
|
|||
|
||||
fclose(fs);
|
||||
|
||||
logg(LOGG_DEBUG, "Checking %s\n", file);
|
||||
if ((opt = optget(opts, "hash-alg"))->enabled) {
|
||||
hash_alg = opt->strarg;
|
||||
}
|
||||
if ((opt = optget(opts, "hash-hint"))->enabled) {
|
||||
hash_hint = opt->strarg;
|
||||
}
|
||||
if ((opt = optget(opts, "log-hash"))->enabled) {
|
||||
hash_out = &hash;
|
||||
}
|
||||
if ((opt = optget(opts, "file-type-hint"))->enabled) {
|
||||
file_type_hint = opt->strarg;
|
||||
}
|
||||
if ((opt = optget(opts, "log-file-type"))->enabled) {
|
||||
file_type_out = &file_type;
|
||||
}
|
||||
|
||||
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||
|
||||
info.files++;
|
||||
info.rblocks += fsize / CL_COUNT_PRECISION;
|
||||
info.bytes_read += fsize;
|
||||
|
||||
data.filename = "stdin";
|
||||
data.chain = NULL;
|
||||
if ((ret = cl_scanfile_callback(file, &virname, &info.blocks, engine, options, &data)) == CL_VIRUS) {
|
||||
info.ifiles++;
|
||||
|
||||
if (bell)
|
||||
fprintf(stderr, "\007");
|
||||
} else if (ret == CL_CLEAN) {
|
||||
if (!printinfected)
|
||||
mprintf(LOGG_INFO, "stdin: OK\n");
|
||||
} else {
|
||||
if (!printinfected)
|
||||
logg(LOGG_INFO, "stdin: %s ERROR\n", cl_strerror(ret));
|
||||
ret = cl_scanfile_ex(
|
||||
filename,
|
||||
&verdict,
|
||||
&alert_name,
|
||||
&info.bytes_scanned,
|
||||
engine,
|
||||
options,
|
||||
&data,
|
||||
hash_hint,
|
||||
hash_out,
|
||||
hash_alg,
|
||||
file_type_hint,
|
||||
file_type_out);
|
||||
|
||||
info.errors++;
|
||||
switch (verdict) {
|
||||
case CL_VERDICT_NOTHING_FOUND: {
|
||||
if (CL_SUCCESS == ret) {
|
||||
if (!printinfected) {
|
||||
mprintf(LOGG_INFO, "stdin: OK\n");
|
||||
}
|
||||
info.files++;
|
||||
} else {
|
||||
if (!printinfected) {
|
||||
logg(LOGG_INFO, "stdin: %s ERROR\n", cl_strerror(ret));
|
||||
}
|
||||
info.errors++;
|
||||
}
|
||||
} break;
|
||||
|
||||
case CL_VERDICT_TRUSTED: {
|
||||
// TODO: Option to print "TRUSTED" verdict instead of "OK"?
|
||||
if (!printinfected) {
|
||||
mprintf(LOGG_INFO, "stdin: OK\n");
|
||||
}
|
||||
} break;
|
||||
|
||||
case CL_VERDICT_STRONG_INDICATOR:
|
||||
case CL_VERDICT_POTENTIALLY_UNWANTED: {
|
||||
info.ifiles++;
|
||||
|
||||
if (bell) {
|
||||
fprintf(stderr, "\007");
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
unlink(file);
|
||||
free(file);
|
||||
if (NULL != hash) {
|
||||
if (hash_alg == NULL) {
|
||||
// libclamav defaults to sha2-256
|
||||
hash_alg = "sha2-256";
|
||||
}
|
||||
logg(LOGG_INFO, "%s FileHash: %s (%s)\n", filename, hash, hash_alg);
|
||||
}
|
||||
|
||||
if (NULL != file_type) {
|
||||
logg(LOGG_INFO, "%s FileType: %s\n", filename, file_type);
|
||||
}
|
||||
|
||||
if (NULL != hash) {
|
||||
free(hash);
|
||||
}
|
||||
|
||||
if (NULL != file_type) {
|
||||
free(file_type);
|
||||
}
|
||||
|
||||
unlink(filename);
|
||||
free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -927,18 +1087,18 @@ static int scan_memory(struct cl_engine *engine, const struct optstruct *opts, s
|
|||
int ret = 0;
|
||||
struct mem_info minfo;
|
||||
|
||||
minfo.d = 0;
|
||||
minfo.files = info.files;
|
||||
minfo.ifiles = info.ifiles;
|
||||
minfo.blocks = info.blocks;
|
||||
minfo.engine = engine;
|
||||
minfo.opts = opts;
|
||||
minfo.options = options;
|
||||
ret = scanmem(&minfo);
|
||||
minfo.d = 0;
|
||||
minfo.files = info.files;
|
||||
minfo.ifiles = info.ifiles;
|
||||
minfo.bytes_scanned = info.bytes_scanned;
|
||||
minfo.engine = engine;
|
||||
minfo.opts = opts;
|
||||
minfo.options = options;
|
||||
ret = scanmem(&minfo);
|
||||
|
||||
info.files = minfo.files;
|
||||
info.ifiles = minfo.ifiles;
|
||||
info.blocks = minfo.blocks;
|
||||
info.files = minfo.files;
|
||||
info.ifiles = minfo.ifiles;
|
||||
info.bytes_scanned = minfo.bytes_scanned;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -976,7 +1136,7 @@ static int scan_files(struct cl_engine *engine, const struct optstruct *opts, st
|
|||
while ((filename = filelist(opts, &ret)) && (file = strdup(filename))) {
|
||||
if (!strcmp(file, "-")) {
|
||||
/* scan data from stdin */
|
||||
ret = scanstdin(engine, options);
|
||||
ret = scanstdin(engine, opts, options);
|
||||
} else if (LSTAT(file, &sb) == -1) {
|
||||
/* Can't access the file */
|
||||
perror(file);
|
||||
|
@ -1196,8 +1356,12 @@ int scanmanager(const struct optstruct *opts)
|
|||
if (optget(opts, "dev-ac-depth")->enabled)
|
||||
cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, optget(opts, "dev-ac-depth")->numarg);
|
||||
|
||||
if (optget(opts, "leave-temps")->enabled)
|
||||
if (optget(opts, "leave-temps")->enabled) {
|
||||
/* Set the engine to keep temporary files */
|
||||
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
|
||||
/* Also set the engine to create temporary directory structure */
|
||||
cl_engine_set_num(engine, CL_ENGINE_TMPDIR_RECURSION, 1);
|
||||
}
|
||||
|
||||
if (optget(opts, "force-to-disk")->enabled)
|
||||
cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
|
||||
|
@ -1240,6 +1404,11 @@ int scanmanager(const struct optstruct *opts)
|
|||
}
|
||||
}
|
||||
|
||||
if (optget(opts, "fips-limits")->enabled) {
|
||||
dboptions |= CL_DB_FIPS_LIMITS;
|
||||
cl_engine_set_num(engine, CL_ENGINE_FIPS_LIMITS, 1);
|
||||
}
|
||||
|
||||
if (optget(opts, "gen-json")->enabled) {
|
||||
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
|
||||
}
|
||||
|
@ -1252,6 +1421,10 @@ int scanmanager(const struct optstruct *opts)
|
|||
options.general |= CL_SCAN_GENERAL_STORE_PDF_URIS;
|
||||
}
|
||||
|
||||
if (optget(opts, "json-store-extra-hashes")->enabled) {
|
||||
options.general |= CL_SCAN_GENERAL_STORE_EXTRA_HASHES;
|
||||
}
|
||||
|
||||
if ((opt = optget(opts, "tempdir"))->enabled) {
|
||||
if ((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
|
||||
logg(LOGG_ERROR, "cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
|
||||
|
@ -1612,11 +1785,6 @@ int scanmanager(const struct optstruct *opts)
|
|||
options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX;
|
||||
}
|
||||
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
if (optget(opts, "dev-collect-hashes")->enabled)
|
||||
options.dev |= CL_SCAN_DEV_COLLECT_SHA;
|
||||
#endif
|
||||
|
||||
if (optget(opts, "dev-performance")->enabled)
|
||||
options.dev |= CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
#define CLAMKEY "Software\\ClamAV"
|
||||
#endif
|
||||
|
||||
#define MAXCMDOPTS 150
|
||||
#define MAXCMDOPTS 200
|
||||
#define MAX_OPTION_LINE_LENGTH 1024
|
||||
|
||||
#define MATCH_NUMBER "^[0-9]+((( +)?#(.*))?)$"
|
||||
|
@ -161,10 +161,15 @@ const struct clam_option __clam_options[] = {
|
|||
{NULL, "include", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "include-dir", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "structured-ssn-format", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "hash-hint", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "hash-alg", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "file-type-hint", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "log-hash", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "log-file-type", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||
{NULL, "hex-dump", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "md5", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "sha1", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "sha256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "sha2-256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "mdb", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "imp", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
{NULL, "fuzzy-img", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||
|
@ -252,6 +257,7 @@ const struct clam_option __clam_options[] = {
|
|||
{NULL, "tar", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
||||
{NULL, "tgz", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
||||
{NULL, "deb", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
||||
{NULL, "sha256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""}, // OPT_DEPRECATED not used so that it will still function for now.
|
||||
|
||||
#ifdef _WIN32
|
||||
{NULL, "memory", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", ""},
|
||||
|
@ -379,8 +385,12 @@ const struct clam_option __clam_options[] = {
|
|||
|
||||
{"JsonStorePDFURIs", "json-store-pdf-uris", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "When GenerateMetadataJson enabled: store uris found in pdf /URI tags.", "yes"},
|
||||
|
||||
{"JsonStoreExtraHashes", "json-store-extra-hashes", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "When GenerateMetadataJson enabled: calculate and store each type of supported file hash.", "yes"},
|
||||
|
||||
{"User", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Run the daemon as a specified user (the process must be started by root).", "clamav"},
|
||||
|
||||
{"FIPSCryptoHashLimits", "fips-limits", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMD | OPT_SIGTOOL | OPT_CLAMONACC, "Apply FIPS-like limitations on which hash algorithms may be used for cryptographic purposes. This essentially disables the legacy CVD digital signature verfication method, and also disables support for MD5 and SHA1 false positive signatures ('.fp' and '.sfp' signatures using MD5 or SHA1).", "yes"},
|
||||
|
||||
/* Scan options */
|
||||
{"Bytecode", "bytecode", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "With this option enabled ClamAV will load bytecode from the database. It is highly recommended you keep this option on, otherwise you'll miss detections for many new viruses.", "yes"},
|
||||
|
||||
|
@ -544,9 +554,6 @@ const struct clam_option __clam_options[] = {
|
|||
|
||||
{"DevACDepth", "dev-ac-depth", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
||||
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
{"DevCollectHashes", "dev-collect-hashes", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
||||
#endif
|
||||
{"DevPerformance", "dev-performance", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
||||
{"DevLiblog", "dev-liblog", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD, "", ""},
|
||||
|
||||
|
|
|
@ -533,8 +533,10 @@ int scanfile(const char *filename, scanmem_data *scan_data, struct mem_info *inf
|
|||
{
|
||||
int fd;
|
||||
int scantype;
|
||||
int ret = CL_CLEAN;
|
||||
const char *virname = NULL;
|
||||
int ret = CL_CLEAN;
|
||||
|
||||
cl_verdict_t verdict = CL_VERDICT_NOTHING_FOUND;
|
||||
const char *alert_name = NULL;
|
||||
|
||||
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||
|
||||
|
@ -562,12 +564,38 @@ int scanfile(const char *filename, scanmem_data *scan_data, struct mem_info *inf
|
|||
ret = CL_VIRUS;
|
||||
}
|
||||
} else { // clamscan
|
||||
ret = cl_scandesc(fd, filename, &virname, &info->blocks, info->engine, info->options);
|
||||
if (ret == CL_VIRUS) {
|
||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, virname);
|
||||
info->ifiles++;
|
||||
} else if (scan_data->printclean) {
|
||||
logg(LOGG_INFO, "%s: OK \n", filename);
|
||||
ret = cl_scandesc_ex(
|
||||
fd,
|
||||
filename,
|
||||
&verdict,
|
||||
&alert_name,
|
||||
&info->bytes_scanned,
|
||||
info->engine,
|
||||
info->options,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
switch (verdict) {
|
||||
case CL_VERDICT_NOTHING_FOUND: {
|
||||
logg(LOGG_INFO, "%s: OK \n", filename);
|
||||
ret = CL_CLEAN;
|
||||
} break;
|
||||
case CL_VERDICT_TRUSTED: {
|
||||
// TODO: Option to print "TRUSTED" verdict instead of "OK"?
|
||||
logg(LOGG_INFO, "%s: OK \n", filename);
|
||||
ret = CL_CLEAN;
|
||||
} break;
|
||||
case CL_VERDICT_STRONG_INDICATOR:
|
||||
case CL_VERDICT_POTENTIALLY_UNWANTED: {
|
||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, alert_name);
|
||||
info->ifiles++;
|
||||
ret = CL_VIRUS;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#ifndef __SCANMEM_H
|
||||
#define __SCANMEM_H
|
||||
|
||||
#include <clamav-types.h>
|
||||
|
||||
#ifndef TH32CS_SNAPMODULE32
|
||||
#define TH32CS_SNAPMODULE32 0x00000010
|
||||
#endif
|
||||
|
@ -54,10 +56,10 @@ typedef struct _scanmem_data_t {
|
|||
} scanmem_data;
|
||||
|
||||
struct mem_info {
|
||||
unsigned int d; /*1 = clamdscan, 0 = clamscan */
|
||||
unsigned int files; /* number of scanned files */
|
||||
unsigned int ifiles; /* number of infected files */
|
||||
unsigned long int blocks; /* number of *scanned* 16kb blocks */
|
||||
unsigned int d; /*1 = clamdscan, 0 = clamscan */
|
||||
unsigned int files; /* number of scanned files */
|
||||
unsigned int ifiles; /* number of infected files */
|
||||
uint64_t bytes_scanned; /* number of *scanned* bytes */
|
||||
unsigned int errors;
|
||||
|
||||
struct cl_engine *engine;
|
||||
|
|
|
@ -102,6 +102,11 @@ Path to a directory containing ClamAV CA certificate files used to verify signed
|
|||
.br
|
||||
Default: @CERTSDIR@
|
||||
.TP
|
||||
\fBFIPSCryptoHashLimits BOOL\fR
|
||||
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||
.br
|
||||
Default: no
|
||||
.TP
|
||||
\fBOfficialDatabaseOnly BOOL\fR
|
||||
Only load the official signatures published by the ClamAV project.
|
||||
.br
|
||||
|
@ -325,6 +330,26 @@ A metadata.json file will be written to the scan temp directory if LeaveTemporar
|
|||
.br
|
||||
Default: no
|
||||
.TP
|
||||
\fBJsonStoreHTMLURIs BOOL\fR
|
||||
Store URIs found in html files to the json metadata.
|
||||
URIs will be stored in an array with the tag 'URIs'.
|
||||
GenerateMetadataJson is required for this feature.
|
||||
.br
|
||||
Default: yes (if GenerateMetadataJson is used)
|
||||
.TP
|
||||
\fBJsonStorePDFURIs BOOL\fR
|
||||
Store URIs found in pdf files to the json metadata.
|
||||
URIs will be stored in an array with the tag 'URIs'.
|
||||
GenerateMetadataJson is required for this feature.
|
||||
.br
|
||||
Default: yes (if GenerateMetadataJson is used)
|
||||
.TP
|
||||
\fBJsonStoreExtraHashes BOOL\fR
|
||||
Calculate MD5 and SHA1 hashes (in addition to SHA2-256) and store to the json metadata.
|
||||
GenerateMetadataJson is required for this feature.
|
||||
.br
|
||||
Default: no
|
||||
.TP
|
||||
\fBUser STRING\fR
|
||||
Run the daemon as a specified user (the process must be started by root).
|
||||
.br
|
||||
|
|
|
@ -57,6 +57,15 @@ This option causes memory or nested map scans to dump the content to disk. If yo
|
|||
\fB\-\-gen\-json\fR
|
||||
Generate JSON description of scanned file(s). JSON will be printed and also dropped to the temp directory if --leave-temps is enabled.
|
||||
.TP
|
||||
\fB\-\-json\-store\-html\-uris\fR
|
||||
Store html URIs in metadata. URIs will be written to the metadata.json file in an array called 'URIs'.
|
||||
.TP
|
||||
\fB\-\-json\-store\-pdf\-uris\fR
|
||||
Store pdf URIs in metadata. URIs will be written to the metadata.json file in an array called 'URIs'.
|
||||
.TP
|
||||
\fB\-\-json\-store\-extra\-hashes\fR
|
||||
Store md5 and sha1 in addition to sha2-256 in metadata.
|
||||
.TP
|
||||
\fB\-d FILE/DIR, \-\-database=FILE/DIR\fR
|
||||
Load virus database from FILE or load all virus database files from DIR.
|
||||
.TP
|
||||
|
@ -274,8 +283,26 @@ Maximum size file to perform PCRE subsig matching (default: 100 MB).
|
|||
\fB\-\-disable\-cache\fR
|
||||
Disable caching and cache checks for hash sums of scanned files.
|
||||
.TP
|
||||
\fB\-\-hash\-hint\fR
|
||||
The file hash so that libclamav does not need to calculate it. The type of hash must match the '\-\-hash-alg'.
|
||||
.TP
|
||||
\fB\-\-log\-hash\fR
|
||||
Print the file hash after each file scanned. The type of hash printed will match the '\-\-hash-alg'.
|
||||
.TP
|
||||
\fB\-\-hash\-alg\fR
|
||||
The hashing algorithm used for either '\-\-hash\-hint' or '\-\-log\-hash'. Supported algorithms are "md5", "sha1", "sha2\-256". If not specified, the default is "sha2\-256".
|
||||
.TP
|
||||
\fB\-\-file\-type\-hint\fR
|
||||
The file type hint so that libclamav can optimize scanning. E.g. "pe", "elf", "zip", etc. You may also use ClamAV type names such as "CL_TYPE_PE". ClamAV will ignore the hint if it is not familiar with the specified type. See also: https://docs.clamav.net/appendix/FileTypes.html#file-types
|
||||
.TP
|
||||
\fB\-\-log\-file\-type\fR
|
||||
Print the file type after each file scanned.
|
||||
.TP
|
||||
\fB\-\-cvdcertsdir=DIR\fR
|
||||
Specify a directory containing the root CA cert needed to verify detached CVD digital signatures. If not provided, then clamscan will look in the default directory.
|
||||
.TP
|
||||
\fB\-\-fips\-limits\fR
|
||||
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||
|
||||
.SH "ENVIRONMENT VARIABLES"
|
||||
.LP
|
||||
|
|
|
@ -71,6 +71,11 @@ Path to a directory containing ClamAV CA certificate files used to verify signed
|
|||
.br
|
||||
Default: @CERTSDIR@
|
||||
.TP
|
||||
\fBFIPSCryptoHashLimits BOOL\fR
|
||||
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||
.br
|
||||
Default: no
|
||||
.TP
|
||||
\fBForeground BOOL\fR
|
||||
Don't fork into background.
|
||||
.br
|
||||
|
|
|
@ -63,8 +63,9 @@ Generate MD5 checksum from stdin or MD5 sigs for FILES.
|
|||
\fB\-\-sha1 [FILES]\fR
|
||||
Generate SHA1 checksum from stdin or SHA1 sigs for FILES.
|
||||
.TP
|
||||
\fB\-\-sha256 [FILES]\fR
|
||||
Generate SHA256 checksum from stdin or SHA256 sigs for FILES.
|
||||
\fB\-\-sha2-256 [FILES]\fR
|
||||
Generate SHA2-256 checksum from stdin or SHA2-256 sigs for FILES.
|
||||
The previous option \-\-sha256 is deprecated and may be removed in a future version.
|
||||
.TP
|
||||
\fB\-\-mdb [FILES]\fR
|
||||
Generate .mdb (PE section hash) signatures for FILES.
|
||||
|
@ -144,6 +145,9 @@ Unpack FILE (CVD) to a current directory.
|
|||
.TP
|
||||
\fB\-\-unpack\-current\fR
|
||||
Unpack a local CVD file (main or daily) to current directory.
|
||||
.TP
|
||||
\fB\-\-fips\-limits\fR
|
||||
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||
|
||||
.SH "COMMANDS FOR WORKING WITH CDIFF PATCH FILES"
|
||||
.LP
|
||||
|
|
|
@ -89,6 +89,12 @@ Example
|
|||
# Default: hardcoded (depends on installation options)
|
||||
#CVDCertsDirectory /etc/clamav/certs
|
||||
|
||||
# Enforce FIPS-like limits on using hash algorithms for cryptographic purposes.
|
||||
# Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify
|
||||
# CVD authenticity.
|
||||
# Default: no
|
||||
#FIPSCryptoHashLimits yes
|
||||
|
||||
# Only load the official signatures published by the ClamAV project.
|
||||
# Default: no
|
||||
#OfficialDatabaseOnly no
|
||||
|
@ -296,6 +302,11 @@ Example
|
|||
# Default: yes (if GenerateMetadataJson is used)
|
||||
#JsonStorePDFURIs no
|
||||
|
||||
# Calculate MD5 and SHA1 hashes (in addition to SHA2-256) and store to the json metadata.
|
||||
# GenerateMetadataJson is required for this feature.
|
||||
# Default: no
|
||||
#JsonStoreExtraHashes yes
|
||||
|
||||
# Permit use of the ALLMATCHSCAN command. If set to no, clamd will reject
|
||||
# any ALLMATCHSCAN command as invalid.
|
||||
# Default: yes
|
||||
|
|
|
@ -22,6 +22,12 @@ Example
|
|||
# Default: hardcoded (depends on installation options)
|
||||
#CVDCertsDirectory /etc/clamav/certs
|
||||
|
||||
# Enforce FIPS-like limits on using hash algorithms for cryptographic purposes.
|
||||
# Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify
|
||||
# CVD authenticity.
|
||||
# Default: no
|
||||
#FIPSCryptoHashLimits yes
|
||||
|
||||
# Path to the log file (make sure it has proper permissions)
|
||||
# Default: disabled
|
||||
#UpdateLogFile /var/log/freshclam.log
|
||||
|
|
|
@ -73,6 +73,23 @@ else()
|
|||
install(TARGETS ex_file_inspection_callback DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
add_executable(ex_scan_callbacks)
|
||||
target_sources(ex_scan_callbacks
|
||||
PRIVATE ex_scan_callbacks.c)
|
||||
set_target_properties(ex_scan_callbacks PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}")
|
||||
target_link_libraries(ex_scan_callbacks
|
||||
PRIVATE
|
||||
ClamAV::libclamav)
|
||||
if(LLVM_FOUND)
|
||||
target_link_directories( ex_scan_callbacks PUBLIC ${LLVM_LIBRARY_DIRS} )
|
||||
target_link_libraries( ex_scan_callbacks PUBLIC ${LLVM_LIBRARIES} )
|
||||
endif()
|
||||
if(WIN32)
|
||||
install(TARGETS ex_scan_callbacks DESTINATION .)
|
||||
else()
|
||||
install(TARGETS ex_scan_callbacks DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
add_executable(ex_cl_cvdunpack)
|
||||
target_sources(ex_cl_cvdunpack
|
||||
PRIVATE ex_cl_cvdunpack.c)
|
||||
|
|
|
@ -45,7 +45,7 @@ int main(int argc, char **argv)
|
|||
|
||||
const char *filename;
|
||||
const char *destination_directory;
|
||||
bool dont_verify = false;
|
||||
uint32_t dboptions = 0;
|
||||
|
||||
switch (argc) {
|
||||
case 2:
|
||||
|
@ -60,7 +60,7 @@ int main(int argc, char **argv)
|
|||
if (strcmp(argv[1], "--no-verify") == 0) {
|
||||
filename = argv[2];
|
||||
destination_directory = argv[3];
|
||||
dont_verify = true;
|
||||
dboptions = CL_DB_UNSIGNED;
|
||||
} else {
|
||||
printf("Usage: %s [--no-verify] file [destination_directory]\n", argv[0]);
|
||||
return CL_EARG;
|
||||
|
@ -73,7 +73,7 @@ int main(int argc, char **argv)
|
|||
|
||||
// Note: using NULL for certs_directory will disable external digital signature verification.
|
||||
|
||||
ret = cl_cvdunpack_ex(filename, destination_directory, dont_verify, NULL);
|
||||
ret = cl_cvdunpack_ex(filename, destination_directory, NULL, dboptions);
|
||||
if (ret != CL_SUCCESS) {
|
||||
printf("ERROR: %s\n", cl_strerror(ret));
|
||||
}
|
||||
|
|
1498
examples/ex_scan_callbacks.c
Normal file
1498
examples/ex_scan_callbacks.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1003,6 +1003,8 @@ static fc_error_t initialize(struct optstruct *opts)
|
|||
|
||||
fcConfig.bCompressLocalDatabase = optget(opts, "CompressLocalDatabase")->enabled;
|
||||
|
||||
fcConfig.bFipsLimits = optget(opts, "FIPSCryptoHashLimits")->enabled;
|
||||
|
||||
/*
|
||||
* Initialize libfreshclam.
|
||||
*/
|
||||
|
|
|
@ -55,7 +55,7 @@ void XzCheck_Init(CXzCheck *p, int mode)
|
|||
case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
|
||||
case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
|
||||
case XZ_CHECK_SHA256:
|
||||
p->sha = cl_hash_init("sha256");
|
||||
p->sha = cl_hash_init("sha2-256");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -701,7 +701,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
|||
{
|
||||
RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
|
||||
p->state = XZ_STATE_BLOCK_HEADER;
|
||||
p->sha = cl_hash_init("sha256");
|
||||
p->sha = cl_hash_init("sha2-256");
|
||||
p->indexSize = 0;
|
||||
p->numBlocks = 0;
|
||||
p->pos = 0;
|
||||
|
@ -722,7 +722,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
|||
p->indexSize += p->indexPreSize;
|
||||
if ((p->sha)) {
|
||||
cl_finish_hash(p->sha, p->shaDigest);
|
||||
p->sha = cl_hash_init("sha256");
|
||||
p->sha = cl_hash_init("sha2-256");
|
||||
}
|
||||
p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
|
||||
p->state = XZ_STATE_STREAM_INDEX;
|
||||
|
|
|
@ -180,7 +180,7 @@ int cli_7unz(cli_ctx *ctx, size_t offset)
|
|||
else if ((outBuffer == NULL) || (outSizeProcessed == 0)) {
|
||||
cli_dbgmsg("cli_unz: extracted empty file\n");
|
||||
} else {
|
||||
if ((found = cli_gentempfd(ctx->sub_tmpdir, &tmp_name, &fd)))
|
||||
if ((found = cli_gentempfd(ctx->this_layer_tmpdir, &tmp_name, &fd)))
|
||||
break;
|
||||
|
||||
cli_dbgmsg("cli_7unz: Saving to %s\n", tmp_name);
|
||||
|
|
|
@ -233,6 +233,7 @@ set(LIBCLAMAV_SOURCES
|
|||
mpool.c mpool.h
|
||||
others.c
|
||||
perflogging.c perflogging.h
|
||||
scan_layer.c scan_layer.h
|
||||
scanners.c scanners.h
|
||||
textdet.c textdet.h
|
||||
version.c
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
#define OID_1_3_6_1_4_1_311_12_1_2 "\x2b\x06\x01\x04\x01\x82\x37\x0c\x01\x02"
|
||||
#define OID_szOID_CATALOG_LIST_MEMBER OID_1_3_6_1_4_1_311_12_1_2
|
||||
|
||||
/* CATALOG_LIST_MEMBER2 seems to be what's used by the SHA256-based CAT files */
|
||||
/* CATALOG_LIST_MEMBER2 seems to be what's used by the SHA2-256-based CAT files */
|
||||
#define OID_1_3_6_1_4_1_311_12_1_3 "\x2b\x06\x01\x04\x01\x82\x37\x0c\x01\x03"
|
||||
#define OID_szOID_CATALOG_LIST_MEMBER2 OID_1_3_6_1_4_1_311_12_1_3
|
||||
|
||||
|
@ -154,31 +154,31 @@ static int map_raw(fmap_t *map, const void *data, unsigned int len, uint8_t raw[
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int map_sha512(fmap_t *map, const void *data, unsigned int len, uint8_t sha512[SHA512_HASH_SIZE])
|
||||
static int map_sha2_512(fmap_t *map, const void *data, unsigned int len, uint8_t sha2_512[SHA512_HASH_SIZE])
|
||||
{
|
||||
if (!fmap_need_ptr_once(map, data, len)) {
|
||||
cli_dbgmsg("map_sha512: failed to read hash data\n");
|
||||
cli_dbgmsg("map_sha2_512: failed to read hash data\n");
|
||||
return 1;
|
||||
}
|
||||
return (cl_sha512(data, len, sha512, NULL) == NULL);
|
||||
return (cl_sha512(data, len, sha2_512, NULL) == NULL);
|
||||
}
|
||||
|
||||
static int map_sha384(fmap_t *map, const void *data, unsigned int len, uint8_t sha384[SHA384_HASH_SIZE])
|
||||
static int map_sha2_384(fmap_t *map, const void *data, unsigned int len, uint8_t sha2_384[SHA384_HASH_SIZE])
|
||||
{
|
||||
if (!fmap_need_ptr_once(map, data, len)) {
|
||||
cli_dbgmsg("map_sha384: failed to read hash data\n");
|
||||
cli_dbgmsg("map_sha2_384: failed to read hash data\n");
|
||||
return 1;
|
||||
}
|
||||
return (cl_sha384(data, len, sha384, NULL) == NULL);
|
||||
return (cl_sha384(data, len, sha2_384, NULL) == NULL);
|
||||
}
|
||||
|
||||
static int map_sha256(fmap_t *map, const void *data, unsigned int len, uint8_t sha256[SHA256_HASH_SIZE])
|
||||
static int map_sha2_256(fmap_t *map, const void *data, unsigned int len, uint8_t sha2_256[SHA256_HASH_SIZE])
|
||||
{
|
||||
if (!fmap_need_ptr_once(map, data, len)) {
|
||||
cli_dbgmsg("map_sha256: failed to read hash data\n");
|
||||
cli_dbgmsg("map_sha2_256: failed to read hash data\n");
|
||||
return 1;
|
||||
}
|
||||
return (cl_sha256(data, len, sha256, NULL) == NULL);
|
||||
return (cl_sha256(data, len, sha2_256, NULL) == NULL);
|
||||
}
|
||||
|
||||
static int map_sha1(fmap_t *map, const void *data, unsigned int len, uint8_t sha1[SHA1_HASH_SIZE])
|
||||
|
@ -211,15 +211,15 @@ static int map_hash(fmap_t *map, const void *data, unsigned int len, uint8_t *ou
|
|||
return 1;
|
||||
}
|
||||
} else if (hashtype == CLI_SHA256RSA) {
|
||||
if (map_sha256(map, data, len, out_hash)) {
|
||||
if (map_sha2_256(map, data, len, out_hash)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (hashtype == CLI_SHA384RSA) {
|
||||
if (map_sha384(map, data, len, out_hash)) {
|
||||
if (map_sha2_384(map, data, len, out_hash)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (hashtype == CLI_SHA512RSA) {
|
||||
if (map_sha512(map, data, len, out_hash)) {
|
||||
if (map_sha2_512(map, data, len, out_hash)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
|
@ -237,11 +237,11 @@ static void *get_hash_ctx(cli_crt_hashtype hashtype)
|
|||
} else if (hashtype == CLI_MD5RSA) {
|
||||
ctx = cl_hash_init("md5");
|
||||
} else if (hashtype == CLI_SHA256RSA) {
|
||||
ctx = cl_hash_init("sha256");
|
||||
ctx = cl_hash_init("sha2-256");
|
||||
} else if (hashtype == CLI_SHA384RSA) {
|
||||
ctx = cl_hash_init("sha384");
|
||||
ctx = cl_hash_init("sha2-384");
|
||||
} else if (hashtype == CLI_SHA512RSA) {
|
||||
ctx = cl_hash_init("sha512");
|
||||
ctx = cl_hash_init("sha2-512");
|
||||
} else {
|
||||
cli_dbgmsg("asn1_get_hash_ctx: unsupported hashtype\n");
|
||||
}
|
||||
|
@ -526,7 +526,7 @@ static int asn1_getnum(const char *s)
|
|||
return (s[0] - '0') * 10 + (s[1] - '0');
|
||||
}
|
||||
|
||||
static int asn1_get_time(fmap_t *map, const void **asn1data, unsigned int *size, time_t *tm)
|
||||
static int asn1_get_time(fmap_t *map, const void **asn1data, unsigned int *size, int64_t *tm)
|
||||
{
|
||||
struct cli_asn1 obj;
|
||||
int ret = asn1_get_obj(map, *asn1data, size, &obj);
|
||||
|
@ -1134,7 +1134,7 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int asn1_parse_countersignature(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *cmgr, const uint8_t *message, const unsigned int message_size, time_t not_before, time_t not_after)
|
||||
static int asn1_parse_countersignature(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *cmgr, const uint8_t *message, const unsigned int message_size, int64_t not_before, int64_t not_after)
|
||||
{
|
||||
|
||||
struct cli_asn1 asn1, deep, deeper;
|
||||
|
@ -1311,7 +1311,7 @@ static int asn1_parse_countersignature(fmap_t *map, const void **asn1data, unsig
|
|||
break;
|
||||
case 2: /* signingTime */
|
||||
{
|
||||
time_t sigdate; /* FIXME shall i use it?! */
|
||||
int64_t sigdate; /* FIXME shall i use it?! */
|
||||
if (asn1_get_time(map, &deeper.content, &deep.size, &sigdate)) {
|
||||
cli_dbgmsg("asn1_parse_countersignature: an error occurred when getting the time\n");
|
||||
deep.size = 1;
|
||||
|
@ -2293,9 +2293,9 @@ int asn1_load_mscat(fmap_t *map, struct cl_engine *engine)
|
|||
if (CLI_SHA1RSA == hashtype) {
|
||||
hm_hashtype = CLI_HASH_SHA1;
|
||||
} else if (CLI_SHA256RSA == hashtype) {
|
||||
hm_hashtype = CLI_HASH_SHA256;
|
||||
hm_hashtype = CLI_HASH_SHA2_256;
|
||||
} else {
|
||||
cli_dbgmsg("asn1_load_mscat: only SHA1 and SHA256 hashes are supported for .cat file sigs\n");
|
||||
cli_dbgmsg("asn1_load_mscat: only SHA1 and SHA2-256 hashes are supported for .cat file sigs\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2333,7 +2333,7 @@ int asn1_load_mscat(fmap_t *map, struct cl_engine *engine)
|
|||
/* Load the trusted hashes into hm_fp, using the size values
|
||||
* 1 and 2 as sentinel values corresponding to CAB and PE hashes
|
||||
* from .cat files respectively. */
|
||||
if (hm_addhash_bin(engine->hm_fp, tagval3.content, hm_hashtype, hashed_obj_type, NULL)) {
|
||||
if (CL_SUCCESS != hm_addhash_bin(engine, HASH_PURPOSE_WHOLE_FILE_FP_CHECK, tagval3.content, hm_hashtype, hashed_obj_type, NULL)) {
|
||||
cli_warnmsg("asn1_load_mscat: failed to add hash\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -2440,5 +2440,9 @@ cl_error_t asn1_check_mscat(struct cl_engine *engine, fmap_t *map, size_t offset
|
|||
}
|
||||
|
||||
cli_dbgmsg("asn1_check_mscat: file with valid authenticode signature, trusted\n");
|
||||
|
||||
// Remove any evidence for this layer and set the verdict to trusted.
|
||||
(void)cli_trust_this_layer(ctx, "authenticode digital signature verification");
|
||||
|
||||
return CL_VERIFIED;
|
||||
}
|
||||
|
|
|
@ -1638,7 +1638,7 @@ cl_error_t cli_scanautoit(cli_ctx *ctx, off_t offset)
|
|||
if (!(version = fmap_need_off_once(map, offset, sizeof(*version))))
|
||||
return CL_EREAD;
|
||||
|
||||
if (!(tmpd = cli_gentemp_with_prefix(ctx->sub_tmpdir, "autoit-tmp")))
|
||||
if (!(tmpd = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "autoit-tmp")))
|
||||
return CL_ETMPDIR;
|
||||
if (mkdir(tmpd, 0700)) {
|
||||
cli_dbgmsg("autoit: Can't create temporary directory %s\n", tmpd);
|
||||
|
|
|
@ -68,10 +68,10 @@ int cli_binhex(cli_ctx *ctx)
|
|||
cli_dbgmsg("in cli_binhex\n");
|
||||
if (!map->len) return CL_CLEAN;
|
||||
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &dname, &datafd)) != CL_SUCCESS)
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &dname, &datafd)) != CL_SUCCESS)
|
||||
return ret;
|
||||
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &rname, &resfd)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &rname, &resfd)) != CL_SUCCESS) {
|
||||
close(datafd);
|
||||
if (cli_unlink(dname)) ret = CL_EUNLINK;
|
||||
free(dname);
|
||||
|
|
|
@ -518,7 +518,7 @@ void fileblobPartialSet(fileblob *fb, const char *fullname, const char *arg)
|
|||
close(fb->fd);
|
||||
return;
|
||||
}
|
||||
blobSetFilename(&fb->b, fb->ctx ? fb->ctx->sub_tmpdir : NULL, fullname);
|
||||
blobSetFilename(&fb->b, fb->ctx ? fb->ctx->this_layer_tmpdir : NULL, fullname);
|
||||
if (fb->b.data)
|
||||
if (fileblobAddData(fb, fb->b.data, fb->b.len) == 0) {
|
||||
free(fb->b.data);
|
||||
|
@ -594,8 +594,8 @@ int fileblobAddData(fileblob *fb, const unsigned char *data, size_t len)
|
|||
do_scan = 0;
|
||||
if (do_scan) {
|
||||
if (ctx->scanned)
|
||||
*ctx->scanned += (unsigned long)len / CL_COUNT_PRECISION;
|
||||
fb->bytes_scanned += (unsigned long)len;
|
||||
*ctx->scanned += len;
|
||||
fb->bytes_scanned += len;
|
||||
|
||||
if ((len > 5) && cli_updatelimits(ctx, len) == CL_CLEAN && (cli_scan_buff(data, (unsigned int)len, 0, ctx->virname, ctx->engine, CL_TYPE_BINARY_DATA, NULL) == CL_VIRUS)) {
|
||||
fb->isInfected = 1;
|
||||
|
|
|
@ -62,7 +62,7 @@ typedef struct fileblob {
|
|||
*/
|
||||
char *fullname; /* full pathname of the file */
|
||||
cli_ctx *ctx; /* When set we can scan the blob, otherwise NULL */
|
||||
unsigned long bytes_scanned;
|
||||
uint64_t bytes_scanned;
|
||||
unsigned int isNotEmpty : 1;
|
||||
unsigned int isInfected : 1;
|
||||
} fileblob;
|
||||
|
|
|
@ -142,13 +142,13 @@ static void bytecode_context_reset(struct cli_bc_ctx *ctx)
|
|||
fd = open(fullname, O_RDONLY | O_BINARY);
|
||||
if (fd >= 0) {
|
||||
ret = cli_scan_desc(fd, cctx, CL_TYPE_HTML, false, NULL, AC_SCAN_VIR,
|
||||
NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED);
|
||||
NULL, "javascript-as-html", fullname, LAYER_ATTRIBUTES_NORMALIZED);
|
||||
if (ret == CL_CLEAN) {
|
||||
if (lseek(fd, 0, SEEK_SET) == -1)
|
||||
cli_dbgmsg("cli_bytecode: call to lseek() has failed\n");
|
||||
else {
|
||||
ret = cli_scan_desc(fd, cctx, CL_TYPE_TEXT_ASCII, false, NULL, AC_SCAN_VIR,
|
||||
NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED);
|
||||
NULL, "javascript-as-text-ascii", fullname, LAYER_ATTRIBUTES_NORMALIZED);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
|
|
@ -215,7 +215,7 @@ int32_t cli_bcapi_write(struct cli_bc_ctx *ctx, uint8_t *data, int32_t len)
|
|||
return -1;
|
||||
}
|
||||
if (-1 == ctx->outfd) {
|
||||
ctx->tempfile = cli_gentemp_with_prefix(cctx ? cctx->sub_tmpdir : NULL, "bcapi_write");
|
||||
ctx->tempfile = cli_gentemp_with_prefix(cctx ? cctx->this_layer_tmpdir : NULL, "bcapi_write");
|
||||
if (!ctx->tempfile) {
|
||||
cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
|
||||
cli_event_error_oom(EV, 0);
|
||||
|
@ -1737,7 +1737,7 @@ int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx, int32_t extracted_file)
|
|||
}
|
||||
|
||||
/* Free the fmap used for the extracted file */
|
||||
funmap(ctx->fmap);
|
||||
fmap_free(ctx->fmap);
|
||||
|
||||
/* Restore pointer to original fmap */
|
||||
cli_bytecode_context_setfile(ctx, ctx->save_map);
|
||||
|
@ -1761,7 +1761,7 @@ int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx, int32_t extracted_file)
|
|||
}
|
||||
|
||||
/* Create fmap for the extracted file */
|
||||
map = fmap(ctx->outfd, 0, 0, NULL);
|
||||
map = fmap_new(ctx->outfd, 0, 0, NULL, ctx->tempfile);
|
||||
if (!map) {
|
||||
cli_warnmsg("can't mmap() extracted temporary file %s\n", ctx->tempfile);
|
||||
return -1;
|
||||
|
@ -2006,7 +2006,7 @@ int32_t cli_bcapi_get_file_reliability(struct cli_bc_ctx *ctx)
|
|||
int32_t cli_bcapi_json_is_active(struct cli_bc_ctx *ctx)
|
||||
{
|
||||
cli_ctx *cctx = (cli_ctx *)ctx->ctx;
|
||||
if (cctx->properties != NULL) {
|
||||
if (cctx->metadata_json != NULL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -2025,7 +2025,7 @@ static int32_t cli_bcapi_json_objs_init(struct cli_bc_ctx *ctx)
|
|||
}
|
||||
ctx->jsonobjs = (void **)j;
|
||||
ctx->njsonobjs = n;
|
||||
j[n - 1] = cctx->properties;
|
||||
j[n - 1] = cctx->metadata_json;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ static inline unsigned int getkey(uint8_t *hash, size_t trees)
|
|||
|
||||
/* SPLAY --------------------------------------------------------------------- */
|
||||
struct node { /* a node */
|
||||
int64_t digest[2];
|
||||
int64_t digest[4];
|
||||
struct node *left;
|
||||
struct node *right;
|
||||
struct node *up;
|
||||
|
@ -201,7 +201,7 @@ static void printnode(const char *prefix, struct cache_set *cs, struct node *n)
|
|||
return;
|
||||
}
|
||||
printf("%s node [%02u]:", prefix, n - cs->data);
|
||||
printf(" size=%lu digest=%llx,%llx\n", (unsigned long)(n->size), n->digest[0], n->digest[1]);
|
||||
printf(" size=%lu digest=%llx,%llx,%llx,%llx\n", (unsigned long)(n->size), n->digest[0], n->digest[1], n->digest[2], n->digest[3]);
|
||||
printf("\tleft=");
|
||||
if (n->left)
|
||||
printf("%02u ", n->left - cs->data);
|
||||
|
@ -265,7 +265,7 @@ static inline void printchain(const char *prefix, struct cache_set *cs)
|
|||
#endif
|
||||
|
||||
/* Looks up a node and splays it up to the root of the tree */
|
||||
static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
||||
static int splay(int64_t *sha2_256, size_t len, struct cache_set *cs)
|
||||
{
|
||||
struct node next = {{0, 0}, NULL, NULL, NULL, NULL, NULL, 0, 0}, *right = &next, *left = &next, *temp, *root = cs->root;
|
||||
int comp, found = 0;
|
||||
|
@ -274,10 +274,10 @@ static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
|||
return 0;
|
||||
|
||||
while (1) {
|
||||
comp = cmp(md5, len, root->digest, root->size);
|
||||
comp = cmp(sha2_256, len, root->digest, root->size);
|
||||
if (comp < 0) {
|
||||
if (!root->left) break;
|
||||
if (cmp(md5, len, root->left->digest, root->left->size) < 0) {
|
||||
if (cmp(sha2_256, len, root->left->digest, root->left->size) < 0) {
|
||||
temp = root->left;
|
||||
root->left = temp->right;
|
||||
if (temp->right) temp->right->up = root;
|
||||
|
@ -292,7 +292,7 @@ static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
|||
root = root->left;
|
||||
} else if (comp > 0) {
|
||||
if (!root->right) break;
|
||||
if (cmp(md5, len, root->right->digest, root->right->size) > 0) {
|
||||
if (cmp(sha2_256, len, root->right->digest, root->right->size) > 0) {
|
||||
temp = root->right;
|
||||
root->right = temp->left;
|
||||
if (temp->left) temp->left->up = root;
|
||||
|
@ -325,11 +325,11 @@ static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
|||
}
|
||||
|
||||
/* Looks up an hash in the tree and maintains the replacement chain */
|
||||
static inline int cacheset_lookup(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t recursion_level)
|
||||
static inline int cacheset_lookup(struct cache_set *cs, uint8_t *sha2_256, size_t size, uint32_t recursion_level)
|
||||
{
|
||||
int64_t hash[2];
|
||||
int64_t hash[4];
|
||||
|
||||
memcpy(hash, md5, 16);
|
||||
memcpy(hash, sha2_256, 32);
|
||||
if (splay(hash, size, cs)) {
|
||||
struct node *o = cs->root->prev, *p = cs->root, *q = cs->root->next;
|
||||
#ifdef PRINT_CHAINS
|
||||
|
@ -367,12 +367,12 @@ static inline int cacheset_lookup(struct cache_set *cs, unsigned char *md5, size
|
|||
/* If the hash is present nothing happens.
|
||||
Otherwise a new node is created for the hash picking one from the begin of the chain.
|
||||
Used nodes are moved to the end of the chain */
|
||||
static inline const char *cacheset_add(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t recursion_level)
|
||||
static inline const char *cacheset_add(struct cache_set *cs, uint8_t *sha2_256, size_t size, uint32_t recursion_level)
|
||||
{
|
||||
struct node *newnode;
|
||||
int64_t hash[2];
|
||||
int64_t hash[4];
|
||||
|
||||
memcpy(hash, md5, 16);
|
||||
memcpy(hash, sha2_256, 32);
|
||||
if (splay(hash, size, cs)) {
|
||||
if (cs->root->minrec > recursion_level)
|
||||
cs->root->minrec = recursion_level;
|
||||
|
@ -457,13 +457,13 @@ static inline const char *cacheset_add(struct cache_set *cs, unsigned char *md5,
|
|||
/* If the hash is not present nothing happens other than splaying the tree.
|
||||
Otherwise the identified node is removed from the tree and then placed back at
|
||||
the front of the chain. */
|
||||
static inline void cacheset_remove(struct cache_set *cs, unsigned char *md5, size_t size)
|
||||
static inline void cacheset_remove(struct cache_set *cs, uint8_t *sha2_256, size_t size)
|
||||
{
|
||||
struct node *targetnode;
|
||||
struct node *reattachnode;
|
||||
int64_t hash[2];
|
||||
int64_t hash[4];
|
||||
|
||||
memcpy(hash, md5, 16);
|
||||
memcpy(hash, sha2_256, 32);
|
||||
if (splay(hash, size, cs) != 1) {
|
||||
cli_dbgmsg("cacheset_remove: node not found in tree\n");
|
||||
return; /* No op */
|
||||
|
@ -498,6 +498,8 @@ static inline void cacheset_remove(struct cache_set *cs, unsigned char *md5, siz
|
|||
targetnode->size = (size_t)0;
|
||||
targetnode->digest[0] = 0;
|
||||
targetnode->digest[1] = 0;
|
||||
targetnode->digest[2] = 0;
|
||||
targetnode->digest[3] = 0;
|
||||
targetnode->up = NULL;
|
||||
targetnode->left = NULL;
|
||||
targetnode->right = NULL;
|
||||
|
@ -527,50 +529,56 @@ static inline void cacheset_remove(struct cache_set *cs, unsigned char *md5, siz
|
|||
}
|
||||
|
||||
/* Looks up an hash in the proper tree */
|
||||
static int cache_lookup_hash(unsigned char *md5, size_t len, struct CACHE *cache, uint32_t recursion_level)
|
||||
static cl_error_t cache_lookup_hash(uint8_t *sha2_256, size_t len, struct CACHE *cache, uint32_t recursion_level)
|
||||
{
|
||||
cl_error_t ret = CL_ERROR;
|
||||
unsigned int key = 0;
|
||||
int ret = CL_VIRUS;
|
||||
struct CACHE *c;
|
||||
|
||||
if (!md5) {
|
||||
if (!sha2_256) {
|
||||
cli_dbgmsg("cache_lookup: No hash available. Nothing to look up.\n");
|
||||
return ret;
|
||||
ret = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
key = getkey(md5, cache->trees);
|
||||
key = getkey(sha2_256, cache->trees);
|
||||
|
||||
c = &cache[key];
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
if (pthread_mutex_lock(&c->mutex)) {
|
||||
cli_errmsg("cache_lookup_hash: cache_lookup_hash: mutex lock fail\n");
|
||||
return ret;
|
||||
ret = CL_ELOCK;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = (cacheset_lookup(&c->cacheset, md5, len, recursion_level)) ? CL_CLEAN : CL_VIRUS;
|
||||
ret = (cacheset_lookup(&c->cacheset, sha2_256, len, recursion_level)) ? CL_CLEAN : CL_VIRUS;
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
#endif
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int clean_cache_init(struct cl_engine *engine)
|
||||
cl_error_t clean_cache_init(struct cl_engine *engine)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
struct CACHE *cache;
|
||||
unsigned int i, j;
|
||||
uint32_t i;
|
||||
|
||||
if (!engine) {
|
||||
cli_errmsg("clean_cache_init: mpool malloc fail\n");
|
||||
return 1;
|
||||
cli_errmsg("clean_cache_init: Engine is NULL.\n");
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||
cli_dbgmsg("clean_cache_init: Caching disabled.\n");
|
||||
return 0;
|
||||
status = CL_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// The user requested the cache size to be engine->cache_size
|
||||
|
@ -583,8 +591,9 @@ int clean_cache_init(struct cl_engine *engine)
|
|||
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);
|
||||
|
||||
if (!(cache = MPOOL_MALLOC(engine->mempool, sizeof(struct CACHE) * trees))) {
|
||||
cli_errmsg("clean_cache_init: mpool malloc fail\n");
|
||||
return 1;
|
||||
cli_errmsg("clean_cache_init: Failed to allocate memory for cache.\n");
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cache->trees = trees;
|
||||
|
@ -593,24 +602,30 @@ int clean_cache_init(struct cl_engine *engine)
|
|||
for (i = 0; i < trees; i++) {
|
||||
#ifdef CL_THREAD_SAFE
|
||||
if (pthread_mutex_init(&cache[i].mutex, NULL)) {
|
||||
cli_errmsg("clean_cache_init: mutex init fail\n");
|
||||
for (j = 0; j < i; j++) cacheset_destroy(&cache[j].cacheset, engine->mempool);
|
||||
for (j = 0; j < i; j++) pthread_mutex_destroy(&cache[j].mutex);
|
||||
MPOOL_FREE(engine->mempool, cache);
|
||||
return 1;
|
||||
cli_errmsg("clean_cache_init: Mutex init failed.\n");
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
if (cacheset_init(&cache[i].cacheset, engine->mempool, cache->nodes_per_tree)) {
|
||||
for (j = 0; j < i; j++) cacheset_destroy(&cache[j].cacheset, engine->mempool);
|
||||
#ifdef CL_THREAD_SAFE
|
||||
for (j = 0; j <= i; j++) pthread_mutex_destroy(&cache[j].mutex);
|
||||
#endif
|
||||
MPOOL_FREE(engine->mempool, cache);
|
||||
return 1;
|
||||
cli_errmsg("clean_cache_init: Failed to initialize cache set.\n");
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
engine->cache = cache;
|
||||
return 0;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("clean_cache_init: Failed to initialize cache.\n");
|
||||
clean_cache_destroy(engine);
|
||||
} else {
|
||||
cli_dbgmsg("clean_cache_init: Cache initialized successfully.\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void clean_cache_destroy(struct cl_engine *engine)
|
||||
|
@ -634,60 +649,71 @@ void clean_cache_destroy(struct cl_engine *engine)
|
|||
MPOOL_FREE(engine->mempool, cache);
|
||||
}
|
||||
|
||||
void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx)
|
||||
void clean_cache_add(cli_ctx *ctx)
|
||||
{
|
||||
cl_error_t ret;
|
||||
|
||||
const char *errmsg = NULL;
|
||||
|
||||
unsigned int key = 0;
|
||||
uint32_t level;
|
||||
struct CACHE *c;
|
||||
|
||||
if (!ctx || !ctx->engine || !ctx->engine->cache)
|
||||
return;
|
||||
uint8_t *sha2_256 = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (!ctx || !ctx->engine || !ctx->engine->cache) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||
cli_dbgmsg("clean_cache_add: Caching disabled. Not adding sample to cache.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!md5) {
|
||||
cli_dbgmsg("clean_cache_add: No hash available. Nothing to add to cache.\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (SCAN_COLLECT_METADATA) {
|
||||
// Don't cache when using the "collect metadata" feature.
|
||||
// We don't cache the JSON, so we can't reproduce it when the cache is positive.
|
||||
cli_dbgmsg("clean_cache_add: collect metadata feature enabled, skipping cache\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ctx->fmap && ctx->fmap->dont_cache_flag == true) {
|
||||
cli_dbgmsg("clean_cache_add: caching disabled for this layer, skipping cache\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 < evidence_num_alerts(ctx->evidence)) {
|
||||
if (0 < evidence_num_alerts(ctx->this_layer_evidence)) {
|
||||
// TODO: The dont cache flag should take care of preventing caching of files with embedded files that alert.
|
||||
// Consider removing this check to allow caching of other actually clean files found within archives.
|
||||
// It would be a (very) minor optimization.
|
||||
cli_dbgmsg("clean_cache_add: alert found within same topfile, skipping cache\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the hash */
|
||||
ret = fmap_get_hash(ctx->fmap, &sha2_256, CLI_HASH_SHA2_256);
|
||||
if (CL_SUCCESS != ret || NULL == sha2_256) {
|
||||
cli_dbgmsg("clean_cache_add: Failed to get SHA2-256 hash.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the file size */
|
||||
size = ctx->fmap->len;
|
||||
|
||||
level = (ctx->fmap && ctx->fmap->dont_cache_flag) ? ctx->recursion_level : 0;
|
||||
|
||||
key = getkey(md5, ctx->engine->cache->trees);
|
||||
key = getkey(sha2_256, ctx->engine->cache->trees);
|
||||
c = &ctx->engine->cache[key];
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
if (pthread_mutex_lock(&c->mutex)) {
|
||||
cli_errmsg("cli_add: mutex lock fail\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
errmsg = cacheset_add(&c->cacheset, md5, size, level);
|
||||
errmsg = cacheset_add(&c->cacheset, sha2_256, size, level);
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
|
@ -696,63 +722,110 @@ void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx)
|
|||
cli_errmsg("%s\n", errmsg);
|
||||
}
|
||||
|
||||
cli_dbgmsg("clean_cache_add: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x (level %u)\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15], level);
|
||||
cli_dbgmsg("clean_cache_add: "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x (level %u)\n",
|
||||
sha2_256[0], sha2_256[1], sha2_256[2], sha2_256[3], sha2_256[4], sha2_256[5], sha2_256[6], sha2_256[7],
|
||||
sha2_256[8], sha2_256[9], sha2_256[10], sha2_256[11], sha2_256[12], sha2_256[13], sha2_256[14], sha2_256[15],
|
||||
sha2_256[16], sha2_256[17], sha2_256[18], sha2_256[19], sha2_256[20], sha2_256[21], sha2_256[22], sha2_256[23],
|
||||
sha2_256[24], sha2_256[25], sha2_256[26], sha2_256[27], sha2_256[28], sha2_256[29], sha2_256[30], sha2_256[31],
|
||||
level);
|
||||
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine *engine)
|
||||
void clean_cache_remove(uint8_t *sha2_256, size_t size, const struct cl_engine *engine)
|
||||
{
|
||||
unsigned int key = 0;
|
||||
struct CACHE *c;
|
||||
|
||||
if (!engine || !engine->cache)
|
||||
return;
|
||||
goto done;
|
||||
|
||||
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||
cli_dbgmsg("clean_cache_remove: Caching disabled.\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!md5) {
|
||||
if (!sha2_256) {
|
||||
cli_dbgmsg("clean_cache_remove: No hash available. Nothing to remove from cache.\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
key = getkey(md5, engine->cache->trees);
|
||||
key = getkey(sha2_256, engine->cache->trees);
|
||||
|
||||
c = &engine->cache[key];
|
||||
#ifdef CL_THREAD_SAFE
|
||||
if (pthread_mutex_lock(&c->mutex)) {
|
||||
cli_errmsg("cli_add: mutex lock fail\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
cacheset_remove(&c->cacheset, md5, size);
|
||||
cacheset_remove(&c->cacheset, sha2_256, size);
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
#endif
|
||||
cli_dbgmsg("clean_cache_remove: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
|
||||
cli_dbgmsg("clean_cache_remove: "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
sha2_256[0], sha2_256[1], sha2_256[2], sha2_256[3], sha2_256[4], sha2_256[5], sha2_256[6], sha2_256[7],
|
||||
sha2_256[8], sha2_256[9], sha2_256[10], sha2_256[11], sha2_256[12], sha2_256[13], sha2_256[14], sha2_256[15],
|
||||
sha2_256[16], sha2_256[17], sha2_256[18], sha2_256[19], sha2_256[20], sha2_256[21], sha2_256[22], sha2_256[23],
|
||||
sha2_256[24], sha2_256[25], sha2_256[26], sha2_256[27], sha2_256[28], sha2_256[29], sha2_256[30], sha2_256[31]);
|
||||
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
cl_error_t clean_cache_check(unsigned char *md5, size_t size, cli_ctx *ctx)
|
||||
cl_error_t clean_cache_check(cli_ctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
cl_error_t status = CL_VIRUS;
|
||||
uint8_t *sha2_256 = NULL;
|
||||
size_t size;
|
||||
|
||||
if (!ctx || !ctx->engine || !ctx->engine->cache)
|
||||
return CL_VIRUS;
|
||||
if (!ctx || !ctx->engine) {
|
||||
cli_errmsg("clean_cache_check: Context or engine is NULL.\n");
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!ctx->engine->cache) {
|
||||
if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||
cli_dbgmsg("clean_cache_check: Caching is disabled.\n");
|
||||
status = CL_VIRUS;
|
||||
} else {
|
||||
cli_dbgmsg("clean_cache_check: Cache is not initialized.\n");
|
||||
status = CL_ENULLARG;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (SCAN_COLLECT_METADATA) {
|
||||
// Don't cache when using the "collect metadata" feature.
|
||||
// We don't cache the JSON, so we can't reproduce it when the cache is positive.
|
||||
cli_dbgmsg("clean_cache_check: collect metadata feature enabled, skipping cache\n");
|
||||
return CL_VIRUS;
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = cache_lookup_hash(md5, size, ctx->engine->cache, ctx->recursion_level);
|
||||
cli_dbgmsg("clean_cache_check: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15], (ret == CL_VIRUS) ? "negative" : "positive");
|
||||
return ret;
|
||||
status = fmap_get_hash(ctx->fmap, &sha2_256, CLI_HASH_SHA2_256);
|
||||
if (status != CL_SUCCESS || !sha2_256) {
|
||||
cli_dbgmsg("clean_cache_check: Failed to get SHA2-256 hash. Cannot check in cache.\n");
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
size = ctx->fmap->len;
|
||||
|
||||
status = cache_lookup_hash(sha2_256, size, ctx->engine->cache, ctx->recursion_level);
|
||||
cli_dbgmsg("clean_cache_check: "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n",
|
||||
sha2_256[0], sha2_256[1], sha2_256[2], sha2_256[3], sha2_256[4], sha2_256[5], sha2_256[6], sha2_256[7],
|
||||
sha2_256[8], sha2_256[9], sha2_256[10], sha2_256[11], sha2_256[12], sha2_256[13], sha2_256[14], sha2_256[15],
|
||||
sha2_256[16], sha2_256[17], sha2_256[18], sha2_256[19], sha2_256[20], sha2_256[21], sha2_256[22], sha2_256[23],
|
||||
sha2_256[24], sha2_256[25], sha2_256[26], sha2_256[27], sha2_256[28], sha2_256[29], sha2_256[30], sha2_256[31],
|
||||
(status == CL_VIRUS) ? "negative" : "positive");
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -26,22 +26,20 @@
|
|||
#include "others.h"
|
||||
|
||||
/**
|
||||
* @brief Add a hash to the cache of clean files.
|
||||
* @brief Add a hash of the current layer to the cache of clean files.
|
||||
*
|
||||
* @param md5 The file to add.
|
||||
* @param size The size of the file.
|
||||
* @param ctx The scanning context.
|
||||
* @param ctx The scanning context.
|
||||
*/
|
||||
void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx);
|
||||
void clean_cache_add(cli_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Removes a hash from the clean cache
|
||||
*
|
||||
* @param md5 The file to remove.
|
||||
* @param size The size of the file.
|
||||
* @param ctx The scanning context.
|
||||
* @param sha2_256 The file to remove.
|
||||
* @param size The size of the file.
|
||||
* @param ctx The scanning context.
|
||||
*/
|
||||
void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine *engine);
|
||||
void clean_cache_remove(uint8_t *sha2_256, size_t size, const struct cl_engine *engine);
|
||||
|
||||
/**
|
||||
* @brief Hashes a file onto the provided buffer and looks it up the clean cache.
|
||||
|
@ -51,7 +49,7 @@ void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine
|
|||
* @return CL_VIRUS if found, CL_CLEAN if not FIXME or a recoverable error.
|
||||
@return CL_EREAD if unrecoverable.
|
||||
*/
|
||||
cl_error_t clean_cache_check(unsigned char *md5, size_t size, cli_ctx *ctx);
|
||||
cl_error_t clean_cache_check(cli_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Allocates the trees for the clean cache.
|
||||
|
@ -59,7 +57,7 @@ cl_error_t clean_cache_check(unsigned char *md5, size_t size, cli_ctx *ctx);
|
|||
* @param engine
|
||||
* @return int
|
||||
*/
|
||||
int clean_cache_init(struct cl_engine *engine);
|
||||
cl_error_t clean_cache_init(struct cl_engine *engine);
|
||||
|
||||
/**
|
||||
* @brief Frees the clean cache
|
||||
|
|
1558
libclamav/clamav.h
1558
libclamav/clamav.h
File diff suppressed because it is too large
Load diff
|
@ -522,21 +522,21 @@ static int crtmgr_rsa_verify(cli_crt *x509, BIGNUM *sig, cli_crt_hashtype hashty
|
|||
if (hashtype == CLI_SHA256RSA) {
|
||||
// Check for OID type indicating a length of 9, OID_sha256, and the NULL type/value
|
||||
if (0 != memcmp(&d[j], "\x06\x09" OID_sha256 "\x05\x00", 13)) {
|
||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA256 hash\n");
|
||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA2-256 hash\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (hashtype == CLI_SHA384RSA) {
|
||||
// Check for OID type indicating a length of 9, OID_sha384, and the NULL type/value
|
||||
if (0 != memcmp(&d[j], "\x06\x09" OID_sha384 "\x05\x00", 13)) {
|
||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA384 hash\n");
|
||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA2-384 hash\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (hashtype == CLI_SHA512RSA) {
|
||||
// Check for OID type indicating a length of 9, OID_sha512, and the NULL type/value
|
||||
if (0 != memcmp(&d[j], "\x06\x09" OID_sha512 "\x05\x00", 13)) {
|
||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA512 hash\n");
|
||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA2-512 hash\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
106
libclamav/cvd.c
106
libclamav/cvd.c
|
@ -41,6 +41,7 @@
|
|||
#include "zlib.h"
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "clamav.h"
|
||||
#include "clamav_rust.h"
|
||||
|
@ -216,7 +217,7 @@ static int cli_tgzload(cvd_t *cvd, struct cl_engine *engine, unsigned int *signo
|
|||
dbio->bufpt = NULL;
|
||||
dbio->readpt = dbio->buf;
|
||||
if (!(dbio->hashctx)) {
|
||||
dbio->hashctx = cl_hash_init("sha256");
|
||||
dbio->hashctx = cl_hash_init("sha2-256");
|
||||
if (!(dbio->hashctx)) {
|
||||
cli_tgzload_cleanup(compr, dbio, fdd);
|
||||
return CL_EMALFDB;
|
||||
|
@ -256,7 +257,7 @@ static int cli_tgzload(cvd_t *cvd, struct cl_engine *engine, unsigned int *signo
|
|||
return CL_EMALFDB;
|
||||
}
|
||||
cl_finish_hash(dbio->hashctx, hash);
|
||||
dbio->hashctx = cl_hash_init("sha256");
|
||||
dbio->hashctx = cl_hash_init("sha2-256");
|
||||
if (!(dbio->hashctx)) {
|
||||
cli_tgzload_cleanup(compr, dbio, fdd);
|
||||
return CL_EMALFDB;
|
||||
|
@ -394,8 +395,9 @@ struct cl_cvd *cl_cvdhead(const char *file)
|
|||
if ((pt = strpbrk(head, "\n\r")))
|
||||
*pt = 0;
|
||||
|
||||
for (i = bread - 1; i > 0 && (head[i] == ' ' || head[i] == '\n' || head[i] == '\r'); head[i] = 0, i--)
|
||||
;
|
||||
for (i = bread - 1; i > 0 && (head[i] == ' ' || head[i] == '\n' || head[i] == '\r'); head[i] = 0, i--) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return cl_cvdparse(head);
|
||||
}
|
||||
|
@ -411,10 +413,10 @@ void cl_cvdfree(struct cl_cvd *cvd)
|
|||
|
||||
cl_error_t cl_cvdverify(const char *file)
|
||||
{
|
||||
return cl_cvdverify_ex(file, NULL);
|
||||
return cl_cvdverify_ex(file, NULL, 0);
|
||||
}
|
||||
|
||||
cl_error_t cl_cvdverify_ex(const char *file, const char *certs_directory)
|
||||
cl_error_t cl_cvdverify_ex(const char *file, const char *certs_directory, uint32_t dboptions)
|
||||
{
|
||||
struct cl_engine *engine = NULL;
|
||||
cl_error_t ret;
|
||||
|
@ -455,7 +457,7 @@ cl_error_t cl_cvdverify_ex(const char *file, const char *certs_directory)
|
|||
}
|
||||
}
|
||||
|
||||
ret = cli_cvdload(engine, NULL, CL_DB_STDOPT | CL_DB_PUA, dbtype, file, verifier, 1);
|
||||
ret = cli_cvdload(engine, NULL, dboptions | CL_DB_STDOPT | CL_DB_PUA, dbtype, file, verifier, true);
|
||||
|
||||
done:
|
||||
if (NULL != engine) {
|
||||
|
@ -471,7 +473,14 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned int options, cvd_type dbtype, const char *filename, void *sign_verifier, unsigned int chkonly)
|
||||
cl_error_t cli_cvdload(
|
||||
struct cl_engine *engine,
|
||||
unsigned int *signo,
|
||||
uint32_t options,
|
||||
cvd_type dbtype,
|
||||
const char *filename,
|
||||
void *sign_verifier,
|
||||
bool chkonly)
|
||||
{
|
||||
cl_error_t status = CL_ECVD;
|
||||
cl_error_t ret;
|
||||
|
@ -484,11 +493,14 @@ cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned i
|
|||
FFIError *cvd_open_error = NULL;
|
||||
FFIError *cvd_verify_error = NULL;
|
||||
char *signer_name = NULL;
|
||||
bool disable_legacy_dsig = false;
|
||||
|
||||
dbio.hashctx = NULL;
|
||||
|
||||
cli_dbgmsg("in cli_cvdload()\n");
|
||||
|
||||
disable_legacy_dsig = (options & CL_DB_FIPS_LIMITS) || (engine->engine_options & ENGINE_OPTIONS_FIPS_LIMITS);
|
||||
|
||||
/* Open the cvd and read the header */
|
||||
cvd = cvd_open(filename, &cvd_open_error);
|
||||
if (!cvd) {
|
||||
|
@ -501,7 +513,7 @@ cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned i
|
|||
if (!cvd_verify(
|
||||
cvd,
|
||||
sign_verifier,
|
||||
false,
|
||||
disable_legacy_dsig,
|
||||
&signer_name,
|
||||
&cvd_verify_error)) {
|
||||
cli_errmsg("cli_cvdload: Can't verify CVD file %s: %s\n", filename, ffierror_fmt(cvd_verify_error));
|
||||
|
@ -641,7 +653,53 @@ done:
|
|||
return status;
|
||||
}
|
||||
|
||||
cl_error_t cli_cvdunpack_and_verify(const char *file, const char *dir, bool dont_verify, void *verifier)
|
||||
cl_error_t cli_cvdverify(
|
||||
const char *file,
|
||||
bool disable_legacy_dsig,
|
||||
void *verifier)
|
||||
{
|
||||
cl_error_t status = CL_SUCCESS;
|
||||
cvd_t *cvd = NULL;
|
||||
FFIError *cvd_open_error = NULL;
|
||||
FFIError *cvd_verify_error = NULL;
|
||||
char *signer_name = NULL;
|
||||
|
||||
cvd = cvd_open(file, &cvd_open_error);
|
||||
if (!cvd) {
|
||||
cli_errmsg("Can't open CVD file %s: %s\n", file, ffierror_fmt(cvd_open_error));
|
||||
return CL_EOPEN;
|
||||
}
|
||||
|
||||
if (!cvd_verify(cvd, verifier, disable_legacy_dsig, &signer_name, &cvd_verify_error)) {
|
||||
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
||||
status = CL_EVERIFY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (NULL != signer_name) {
|
||||
ffi_cstring_free(signer_name);
|
||||
}
|
||||
if (NULL != cvd) {
|
||||
cvd_free(cvd);
|
||||
}
|
||||
if (NULL != cvd_open_error) {
|
||||
ffierror_free(cvd_open_error);
|
||||
}
|
||||
if (NULL != cvd_verify_error) {
|
||||
ffierror_free(cvd_verify_error);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cl_error_t cli_cvdunpack_and_verify(
|
||||
const char *file,
|
||||
const char *dir,
|
||||
bool dont_verify,
|
||||
bool disable_legacy_dsig,
|
||||
void *verifier)
|
||||
{
|
||||
cl_error_t status = CL_SUCCESS;
|
||||
cvd_t *cvd = NULL;
|
||||
|
@ -657,7 +715,7 @@ cl_error_t cli_cvdunpack_and_verify(const char *file, const char *dir, bool dont
|
|||
}
|
||||
|
||||
if (!dont_verify) {
|
||||
if (!cvd_verify(cvd, verifier, false, &signer_name, &cvd_verify_error)) {
|
||||
if (!cvd_verify(cvd, verifier, disable_legacy_dsig, &signer_name, &cvd_verify_error)) {
|
||||
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
||||
status = CL_EVERIFY;
|
||||
goto done;
|
||||
|
@ -691,7 +749,7 @@ done:
|
|||
return status;
|
||||
}
|
||||
|
||||
cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, bool dont_verify, const char *certs_directory)
|
||||
cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, const char *certs_directory, uint32_t dboptions)
|
||||
{
|
||||
cl_error_t status = CL_SUCCESS;
|
||||
cvd_t *cvd = NULL;
|
||||
|
@ -707,15 +765,16 @@ cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, bool dont_verify,
|
|||
return CL_EOPEN;
|
||||
}
|
||||
|
||||
if (dont_verify) {
|
||||
// Just unpack the CVD file.
|
||||
if (dboptions & CL_DB_UNSIGNED) {
|
||||
// Just unpack the CVD file and don´t verify the digital signature.
|
||||
if (!cvd_unpack(cvd, dir, &cvd_unpack_error)) {
|
||||
cli_errmsg("CVD unpacking failed: %s\n", ffierror_fmt(cvd_unpack_error));
|
||||
status = CL_EUNPACK;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
// Verify the CVD file and hten unpack it.
|
||||
// Verify the CVD file and then unpack it.
|
||||
bool disable_legacy_dsig = false;
|
||||
|
||||
// The certs directory is optional.
|
||||
// If not provided, then we can't validate external signatures and will have to rely
|
||||
|
@ -728,7 +787,13 @@ cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, bool dont_verify,
|
|||
}
|
||||
}
|
||||
|
||||
status = cli_cvdunpack_and_verify(file, dir, dont_verify, verifier);
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
disable_legacy_dsig = (dboptions & CL_DB_FIPS_LIMITS) || EVP_default_properties_is_fips_enabled(NULL);
|
||||
#else
|
||||
disable_legacy_dsig = (dboptions & CL_DB_FIPS_LIMITS) || FIPS_mode();
|
||||
#endif
|
||||
|
||||
status = cli_cvdunpack_and_verify(file, dir, false, disable_legacy_dsig, verifier);
|
||||
if (status != CL_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
@ -766,6 +831,7 @@ cl_error_t cl_cvdunpack(const char *file, const char *dir, bool dont_verify)
|
|||
FFIError *cvd_verify_error = NULL;
|
||||
FFIError *cvd_unpack_error = NULL;
|
||||
char *signer_name = NULL;
|
||||
bool disable_legacy_dsig = false;
|
||||
|
||||
cvd = cvd_open(file, &cvd_open_error);
|
||||
if (!cvd) {
|
||||
|
@ -773,8 +839,14 @@ cl_error_t cl_cvdunpack(const char *file, const char *dir, bool dont_verify)
|
|||
return CL_EOPEN;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
disable_legacy_dsig = EVP_default_properties_is_fips_enabled(NULL);
|
||||
#else
|
||||
disable_legacy_dsig = FIPS_mode();
|
||||
#endif
|
||||
|
||||
if (!dont_verify) {
|
||||
if (!cvd_verify(cvd, NULL, false, &signer_name, &cvd_verify_error)) {
|
||||
if (!cvd_verify(cvd, NULL, disable_legacy_dsig, &signer_name, &cvd_verify_error)) {
|
||||
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
||||
status = CL_EVERIFY;
|
||||
goto done;
|
||||
|
|
|
@ -52,7 +52,55 @@ typedef enum cvd_type {
|
|||
CVD_TYPE_CUD,
|
||||
} cvd_type;
|
||||
|
||||
cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned int options, cvd_type dbtype, const char *filename, void *sign_verifier, unsigned int chkonly);
|
||||
cl_error_t cli_cvdunpack_and_verify(const char *file, const char *dir, bool dont_verify, void *verifier);
|
||||
/**
|
||||
* @brief Load a CVD, CLD, or CUD signature database archive
|
||||
*
|
||||
* @param engine The ClamAV engine to load the CVD into
|
||||
* @param signo Pointer to the signature number
|
||||
* @param options CL_DB_* options for loading the CVD
|
||||
* @param dbtype Type of the database
|
||||
* @param filename Name of the CVD file
|
||||
* @param sign_verifier Pointer to the signature verifier
|
||||
* @param chkonly Check only mode
|
||||
* @return cl_error_t CL_SUCCESS on success, or an error code on failure
|
||||
*/
|
||||
cl_error_t cli_cvdload(
|
||||
struct cl_engine *engine,
|
||||
unsigned int *signo,
|
||||
uint32_t options,
|
||||
cvd_type dbtype,
|
||||
const char *filename,
|
||||
void *sign_verifier,
|
||||
bool chkonly);
|
||||
|
||||
/**
|
||||
* @brief Unpack and verify a CVD, CLD, or CUD signature database archive
|
||||
*
|
||||
* @param file Name of the CVD file
|
||||
* @param dir Directory to unpack the CVD into
|
||||
* @param dont_verify Don't verify signatures
|
||||
* @param disable_legacy_dsig Disable legacy MD5-based digital signature verification
|
||||
* @param verifier Pointer to the signature verifier
|
||||
* @return cl_error_t CL_SUCCESS on success, or an error code on failure
|
||||
*/
|
||||
cl_error_t cli_cvdunpack_and_verify(
|
||||
const char *file,
|
||||
const char *dir,
|
||||
bool dont_verify,
|
||||
bool disable_legacy_dsig,
|
||||
void *verifier);
|
||||
|
||||
/**
|
||||
* @brief Verify a CVD, CLD, or CUD signature database archive
|
||||
*
|
||||
* @param file Name of the CVD file
|
||||
* @param disable_legacy_dsig Disable legacy MD5-based digital signature verification
|
||||
* @param verifier Pointer to the signature verifier
|
||||
* @return cl_error_t CL_SUCCESS on success, or an error code on failure
|
||||
*/
|
||||
cl_error_t cli_cvdverify(
|
||||
const char *file,
|
||||
bool disable_legacy_dsig,
|
||||
void *verifier);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -146,7 +146,7 @@ int cli_scandmg(cli_ctx *ctx)
|
|||
}
|
||||
|
||||
/* Create temp folder for contents */
|
||||
if (!(dirname = cli_gentemp_with_prefix(ctx->sub_tmpdir, "dmg-tmp"))) {
|
||||
if (!(dirname = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "dmg-tmp"))) {
|
||||
return CL_ETMPDIR;
|
||||
}
|
||||
if (mkdir(dirname, 0700)) {
|
||||
|
|
|
@ -299,20 +299,20 @@ cl_error_t cli_versig(const char *md5, const char *dsig)
|
|||
if (!BN_dec2bn(&n, CLI_NSTR))
|
||||
goto done;
|
||||
|
||||
if (strlen(md5) != 32 || !isalnum(md5[0])) {
|
||||
if (strlen(md5) != MD5_HASH_SIZE * 2 || !isalnum(md5[0])) {
|
||||
/* someone is trying to fool us with empty/malformed MD5 ? */
|
||||
cli_errmsg("SECURITY WARNING: MD5 basic test failure.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(pt = (char *)cli_decodesig(dsig, 16, e, n)))
|
||||
if (!(pt = (char *)cli_decodesig(dsig, MD5_HASH_SIZE, e, n)))
|
||||
goto done;
|
||||
|
||||
pt2 = cli_str2hex(pt, 16);
|
||||
pt2 = cli_str2hex(pt, MD5_HASH_SIZE);
|
||||
|
||||
cli_dbgmsg("cli_versig: Decoded signature: %s\n", pt2);
|
||||
|
||||
if (strncmp(md5, pt2, 32)) {
|
||||
if (strncmp(md5, pt2, MD5_HASH_SIZE * 2)) {
|
||||
cli_dbgmsg("cli_versig: Signature doesn't match.\n");
|
||||
goto done;
|
||||
}
|
||||
|
@ -328,19 +328,18 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define HASH_LEN 32
|
||||
#define SALT_LEN 32
|
||||
#define PAD_LEN (2048 / 8)
|
||||
#define BLK_LEN (PAD_LEN - HASH_LEN - 1)
|
||||
int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n_str, const char *e_str)
|
||||
#define BLK_LEN (PAD_LEN - SHA256_HASH_SIZE - 1)
|
||||
cl_error_t cli_versig2(const uint8_t *sha2_256, const char *dsig_str, const char *n_str, const char *e_str)
|
||||
{
|
||||
unsigned char *decoded = NULL;
|
||||
unsigned char digest1[HASH_LEN], digest2[HASH_LEN], digest3[HASH_LEN], *salt;
|
||||
unsigned char mask[BLK_LEN], data[BLK_LEN], final[8 + 2 * HASH_LEN], c[4];
|
||||
uint8_t *decoded = NULL;
|
||||
uint8_t digest1[SHA256_HASH_SIZE], digest2[SHA256_HASH_SIZE], digest3[SHA256_HASH_SIZE], *salt;
|
||||
uint8_t mask[BLK_LEN], data[BLK_LEN], final[8 + 2 * SHA256_HASH_SIZE], c[4];
|
||||
unsigned int i, rounds;
|
||||
void *ctx;
|
||||
BIGNUM *n, *e;
|
||||
int ret;
|
||||
cl_error_t ret;
|
||||
|
||||
n = BN_new();
|
||||
e = BN_new();
|
||||
|
@ -374,27 +373,27 @@ int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n
|
|||
e = NULL;
|
||||
|
||||
memcpy(mask, decoded, BLK_LEN);
|
||||
memcpy(digest2, &decoded[BLK_LEN], HASH_LEN);
|
||||
memcpy(digest2, &decoded[BLK_LEN], SHA256_HASH_SIZE);
|
||||
free(decoded);
|
||||
decoded = NULL;
|
||||
|
||||
c[0] = c[1] = 0;
|
||||
rounds = (BLK_LEN + HASH_LEN - 1) / HASH_LEN;
|
||||
rounds = (BLK_LEN + SHA256_HASH_SIZE - 1) / SHA256_HASH_SIZE;
|
||||
for (i = 0; i < rounds; i++) {
|
||||
c[2] = (unsigned char)(i / 256);
|
||||
c[3] = (unsigned char)i;
|
||||
|
||||
ctx = cl_hash_init("sha256");
|
||||
ctx = cl_hash_init("sha2-256");
|
||||
if (!(ctx))
|
||||
return CL_EMEM;
|
||||
|
||||
cl_update_hash(ctx, digest2, HASH_LEN);
|
||||
cl_update_hash(ctx, digest2, SHA256_HASH_SIZE);
|
||||
cl_update_hash(ctx, c, 4);
|
||||
cl_finish_hash(ctx, digest3);
|
||||
if (i + 1 == rounds)
|
||||
memcpy(&data[i * 32], digest3, BLK_LEN - i * HASH_LEN);
|
||||
memcpy(&data[i * 32], digest3, BLK_LEN - i * SHA256_HASH_SIZE);
|
||||
else
|
||||
memcpy(&data[i * 32], digest3, HASH_LEN);
|
||||
memcpy(&data[i * 32], digest3, SHA256_HASH_SIZE);
|
||||
}
|
||||
|
||||
for (i = 0; i < BLK_LEN; i++)
|
||||
|
@ -409,17 +408,17 @@ int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n
|
|||
return CL_EVERIFY;
|
||||
|
||||
memset(final, 0, 8);
|
||||
memcpy(&final[8], sha256, HASH_LEN);
|
||||
memcpy(&final[8 + HASH_LEN], salt, SALT_LEN);
|
||||
memcpy(&final[8], sha2_256, SHA256_HASH_SIZE);
|
||||
memcpy(&final[8 + SHA256_HASH_SIZE], salt, SALT_LEN);
|
||||
|
||||
ctx = cl_hash_init("sha256");
|
||||
ctx = cl_hash_init("sha2-256");
|
||||
if (!(ctx))
|
||||
return CL_EMEM;
|
||||
|
||||
cl_update_hash(ctx, final, sizeof(final));
|
||||
cl_finish_hash(ctx, digest1);
|
||||
|
||||
return memcmp(digest1, digest2, HASH_LEN) ? CL_EVERIFY : CL_SUCCESS;
|
||||
return memcmp(digest1, digest2, SHA256_HASH_SIZE) ? CL_EVERIFY : CL_SUCCESS;
|
||||
|
||||
done:
|
||||
free(decoded);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#endif
|
||||
|
||||
cl_error_t cli_versig(const char *md5, const char *dsig);
|
||||
int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n_str, const char *e_str);
|
||||
cl_error_t cli_versig2(const unsigned char *sha2_256, const char *dsig_str, const char *n_str, const char *e_str);
|
||||
|
||||
/**
|
||||
* @brief Connect to a signing server, send the data to be signed, and return the digital signature.
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
* | Archive Comment Header | 0~N |
|
||||
* |-----------------------------------------------------|------|
|
||||
*
|
||||
* Authors: Micah Snyder
|
||||
* Authors: Valerie Snyder
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* ESTsoft's "unEGG" module was not used in the creation of this capability
|
||||
* in order to avoid to licensing restrictions on the ESTsoft "unEGG" module.
|
||||
*
|
||||
* Authors: Micah Snyder
|
||||
* Authors: Valerie Snyder
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
|
|
@ -147,6 +147,55 @@ static const struct ftmap_s {
|
|||
};
|
||||
// clang-format on
|
||||
|
||||
cli_file_t cli_ftcode_human_friendly(const char *name)
|
||||
{
|
||||
cli_file_t code = CL_TYPE_ERROR;
|
||||
|
||||
unsigned int i;
|
||||
char *reconstructed_name = NULL;
|
||||
const char *ftname;
|
||||
|
||||
if (NULL == name) {
|
||||
cli_dbgmsg("cli_ftcode_human_friendly: NULL name\n");
|
||||
code = CL_TYPE_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 == strncmp(name, "CL_TYPE_", strlen("CL_TYPE_"))) {
|
||||
/* If the name starts with "CL_TYPE_", we can use it directly. */
|
||||
ftname = name;
|
||||
} else {
|
||||
/* If the name does not start with "CL_TYPE_", let's prefix "CL_TYPE_" and convert it to uppercase. */
|
||||
size_t len = strlen(name) + strlen("CL_TYPE_") + 1;
|
||||
|
||||
reconstructed_name = malloc(len);
|
||||
if (NULL == reconstructed_name) {
|
||||
cli_dbgmsg("cli_ftcode_human_friendly: Failed to allocate memory for reconstructed name\n");
|
||||
code = CL_TYPE_ERROR;
|
||||
goto done;
|
||||
}
|
||||
snprintf(reconstructed_name, len, "CL_TYPE_%s", name);
|
||||
|
||||
/* Convert to uppercase */
|
||||
for (i = 0; i < len; i++) {
|
||||
reconstructed_name[i] = toupper((unsigned char)reconstructed_name[i]);
|
||||
}
|
||||
|
||||
ftname = reconstructed_name;
|
||||
}
|
||||
|
||||
code = cli_ftcode(ftname);
|
||||
if (CL_TYPE_ERROR == code) {
|
||||
cli_dbgmsg("cli_ftcode_human_friendly: Unknown file type '%s'\n", name);
|
||||
}
|
||||
|
||||
done:
|
||||
if (NULL != reconstructed_name) {
|
||||
free(reconstructed_name);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
cli_file_t cli_ftcode(const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -278,7 +327,7 @@ const struct ooxml_ftcodes {
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
cli_file_t cli_determine_fmap_type(cli_ctx *ctx, cli_file_t basetype)
|
||||
cli_file_t cli_determine_fmap_type(cli_ctx_t ctx_t, cli_file_t basetype)
|
||||
{
|
||||
unsigned char buffer[MAGIC_BUFFER_SIZE];
|
||||
const unsigned char *buff;
|
||||
|
@ -288,6 +337,7 @@ cli_file_t cli_determine_fmap_type(cli_ctx *ctx, cli_file_t basetype)
|
|||
cli_file_t ret = CL_TYPE_BINARY_DATA;
|
||||
struct cli_matcher *root;
|
||||
struct cli_ac_data mdata;
|
||||
cli_ctx *ctx = (cli_ctx *)ctx_t;
|
||||
|
||||
if (!ctx || !ctx->engine || !ctx->fmap) {
|
||||
cli_errmsg("cli_determine_fmap_type: engine == NULL\n");
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "clamav.h"
|
||||
|
||||
typedef struct cli_ctx_tag cli_ctx;
|
||||
#include "other_types.h"
|
||||
|
||||
#define CL_FILE_MBUFF_SIZE 1024
|
||||
#define CL_PART_MBUFF_SIZE 1028
|
||||
|
@ -149,12 +148,34 @@ struct cli_matched_type {
|
|||
unsigned short cnt;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Convert a file type name to a file type code.
|
||||
*
|
||||
* @param name The name of the file type. E.g. "CL_TYPE_PE", "CL_TYPE_ELF", etc.
|
||||
* @return cli_file_t
|
||||
*/
|
||||
cli_file_t cli_ftcode(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Convert a human-friendly file type name to a file type code.
|
||||
*
|
||||
* @param name The human-friendly name of the file type. E.g. "pe", "ZIP", "CL_TYPE_ELF", etc.
|
||||
* @return cli_file_t
|
||||
*/
|
||||
cli_file_t cli_ftcode_human_friendly(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Convert a file type code to a file type name.
|
||||
*
|
||||
* @param code The file type code. E.g. CL_TYPE_PE, CL_TYPE_ELF, etc.
|
||||
* @return const char* A ame of the file type. E.g. "CL_TYPE_PE", "CL_TYPE_ELF", etc.
|
||||
*/
|
||||
const char *cli_ftname(cli_file_t code);
|
||||
|
||||
void cli_ftfree(const struct cl_engine *engine);
|
||||
cli_file_t cli_compare_ftm_file(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
|
||||
cli_file_t cli_compare_ftm_partition(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
|
||||
cli_file_t cli_determine_fmap_type(cli_ctx *ctx, cli_file_t basetype);
|
||||
cli_file_t cli_determine_fmap_type(cli_ctx_t ctx, cli_file_t basetype);
|
||||
int cli_addtypesigs(struct cl_engine *engine);
|
||||
|
||||
#endif
|
||||
|
|
648
libclamav/fmap.c
648
libclamav/fmap.c
|
@ -108,7 +108,7 @@ static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
|
|||
return pread((int)(ssize_t)handle, buf, count, offset);
|
||||
}
|
||||
|
||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name)
|
||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name, const char *path)
|
||||
{
|
||||
STATBUF st;
|
||||
fmap_t *m = NULL;
|
||||
|
@ -137,7 +137,15 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha
|
|||
if (NULL != name) {
|
||||
m->name = cli_safer_strdup(name);
|
||||
if (NULL == m->name) {
|
||||
funmap(m);
|
||||
fmap_free(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != path) {
|
||||
m->path = cli_safer_strdup(path);
|
||||
if (NULL == m->path) {
|
||||
fmap_free(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -158,11 +166,14 @@ static void unmap_win32(fmap_t *m)
|
|||
if (NULL != m->name) {
|
||||
free(m->name);
|
||||
}
|
||||
if (NULL != m->path) {
|
||||
free(m->path);
|
||||
}
|
||||
free((void *)m);
|
||||
}
|
||||
}
|
||||
|
||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name)
|
||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name, const char *path)
|
||||
{ /* WIN32 */
|
||||
uint64_t pages, mapsz;
|
||||
int pgsz = cli_getpagesize();
|
||||
|
@ -214,7 +225,7 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha
|
|||
return NULL;
|
||||
}
|
||||
m->handle = (void *)(size_t)fd;
|
||||
m->handle_is_fd = true; /* This is probably(?) needed so `fmap_fd()` can return the file descriptor. */
|
||||
m->handle_is_fd = true;
|
||||
m->windows_file_handle = (void *)windows_file_handle;
|
||||
m->windows_map_handle = (void *)windows_map_handle;
|
||||
m->unmap = unmap_win32;
|
||||
|
@ -222,7 +233,15 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha
|
|||
if (NULL != name) {
|
||||
m->name = cli_safer_strdup(name);
|
||||
if (NULL == m->name) {
|
||||
funmap(m);
|
||||
fmap_free(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != path) {
|
||||
m->path = cli_safer_strdup(path);
|
||||
if (NULL == m->path) {
|
||||
fmap_free(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -287,9 +306,8 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char
|
|||
/* This also means the hash will be different.
|
||||
* Clear the have_<hash> flags.
|
||||
* It will be calculated when next it is needed. */
|
||||
duplicate_map->have_md5 = false;
|
||||
duplicate_map->have_sha1 = false;
|
||||
duplicate_map->have_sha256 = false;
|
||||
memset(duplicate_map->will_need_hash, 0, sizeof(duplicate_map->will_need_hash));
|
||||
memset(duplicate_map->have_hash, 0, sizeof(duplicate_map->have_hash));
|
||||
}
|
||||
|
||||
if (NULL != name) {
|
||||
|
@ -302,6 +320,17 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char
|
|||
duplicate_map->name = NULL;
|
||||
}
|
||||
|
||||
/* Duplicate the path if it exists */
|
||||
if (NULL != map->path) {
|
||||
duplicate_map->path = cli_safer_strdup(map->path);
|
||||
if (NULL == duplicate_map->path) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
duplicate_map->path = NULL;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
|
@ -322,6 +351,10 @@ void free_duplicate_fmap(cl_fmap_t *map)
|
|||
free(map->name);
|
||||
map->name = NULL;
|
||||
}
|
||||
if (NULL != map->path) {
|
||||
free(map->path);
|
||||
map->path = NULL;
|
||||
}
|
||||
free(map);
|
||||
}
|
||||
}
|
||||
|
@ -344,12 +377,15 @@ static void unmap_handle(fmap_t *m)
|
|||
if (NULL != m->name) {
|
||||
free(m->name);
|
||||
}
|
||||
if (NULL != m->path) {
|
||||
free(m->path);
|
||||
}
|
||||
free((void *)m);
|
||||
}
|
||||
}
|
||||
|
||||
extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
|
||||
clcb_pread pread_cb, int use_aging)
|
||||
cl_fmap_t *fmap_open_handle(void *handle, size_t offset, size_t len,
|
||||
clcb_pread pread_cb, int use_aging)
|
||||
{
|
||||
cl_error_t status = CL_EMEM;
|
||||
uint64_t pages;
|
||||
|
@ -431,9 +467,9 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
|
|||
m->gets = handle_gets;
|
||||
m->unneed_off = handle_unneed_off;
|
||||
m->handle_is_fd = true;
|
||||
m->have_md5 = false;
|
||||
m->have_sha1 = false;
|
||||
m->have_sha256 = false;
|
||||
|
||||
memset(m->will_need_hash, 0, sizeof(m->will_need_hash));
|
||||
memset(m->have_hash, 0, sizeof(m->have_hash));
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
|
@ -723,7 +759,7 @@ static void unmap_mmap(fmap_t *m)
|
|||
size_t len = m->pages * m->pgsz;
|
||||
fmap_lock;
|
||||
if (munmap((void *)m->data, len) == -1) /* munmap() failed */
|
||||
cli_warnmsg("funmap: unable to unmap memory segment at address: %p with length: %zu\n", (void *)m->data, len);
|
||||
cli_warnmsg("fmap_free: unable to unmap memory segment at address: %p with length: %zu\n", (void *)m->data, len);
|
||||
fmap_unlock;
|
||||
#else
|
||||
UNUSEDPARAM(m);
|
||||
|
@ -736,6 +772,9 @@ static void unmap_malloc(fmap_t *m)
|
|||
if (NULL != m->name) {
|
||||
free(m->name);
|
||||
}
|
||||
if (NULL != m->path) {
|
||||
free(m->path);
|
||||
}
|
||||
free((void *)m);
|
||||
}
|
||||
}
|
||||
|
@ -885,11 +924,6 @@ done:
|
|||
return m;
|
||||
}
|
||||
|
||||
extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len)
|
||||
{
|
||||
return (cl_fmap_t *)fmap_open_memory(start, len, NULL);
|
||||
}
|
||||
|
||||
static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock)
|
||||
{
|
||||
UNUSEDPARAM(lock);
|
||||
|
@ -951,10 +985,10 @@ static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len)
|
|||
return dst;
|
||||
}
|
||||
|
||||
fmap_t *fmap(int fd, off_t offset, size_t len, const char *name)
|
||||
fmap_t *fmap_new(int fd, off_t offset, size_t len, const char *name, const char *path)
|
||||
{
|
||||
int unused;
|
||||
return fmap_check_empty(fd, offset, len, &unused, name);
|
||||
return fmap_check_empty(fd, offset, len, &unused, name, path);
|
||||
}
|
||||
|
||||
static inline uint64_t fmap_align_items(uint64_t sz, uint64_t al)
|
||||
|
@ -1081,14 +1115,9 @@ int fmap_fd(fmap_t *m)
|
|||
return fd;
|
||||
}
|
||||
|
||||
extern void cl_fmap_close(cl_fmap_t *map)
|
||||
cl_error_t fmap_set_hash(fmap_t *map, uint8_t *hash, cli_hash_type_t type)
|
||||
{
|
||||
funmap(map);
|
||||
}
|
||||
|
||||
cl_error_t fmap_set_hash(fmap_t *map, unsigned char *hash, cli_hash_type_t type)
|
||||
{
|
||||
cl_error_t status = CL_SUCCESS;
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (NULL == map) {
|
||||
cli_errmsg("fmap_set_hash: Attempted to set hash for NULL fmap\n");
|
||||
|
@ -1101,25 +1130,55 @@ cl_error_t fmap_set_hash(fmap_t *map, unsigned char *hash, cli_hash_type_t type)
|
|||
goto done;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
memcpy(map->md5, hash, CLI_HASHLEN_MD5);
|
||||
map->have_md5 = true;
|
||||
break;
|
||||
case CLI_HASH_SHA1:
|
||||
memcpy(map->sha1, hash, CLI_HASHLEN_SHA1);
|
||||
map->have_sha1 = true;
|
||||
break;
|
||||
case CLI_HASH_SHA256:
|
||||
memcpy(map->sha256, hash, CLI_HASHLEN_SHA256);
|
||||
map->have_sha256 = true;
|
||||
break;
|
||||
default:
|
||||
cli_errmsg("fmap_set_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("fmap_set_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(map->hash[type], hash, cli_hash_len(type));
|
||||
map->have_hash[type] = true;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
if (cli_debug_flag) {
|
||||
// Convert the hash to a hex string for logging
|
||||
char hash_string[CLI_HASHLEN_MAX * 2 + 1] = {0};
|
||||
size_t hash_len = cli_hash_len(type);
|
||||
|
||||
// Convert hash to string.
|
||||
size_t i;
|
||||
for (i = 0; i < hash_len; i++) {
|
||||
sprintf(hash_string + i * 2, "%02x", map->hash[type][i]);
|
||||
}
|
||||
hash_string[hash_len * 2] = 0;
|
||||
|
||||
cli_dbgmsg("fmap_set_hash: set %s hash: %s\n", cli_hash_name(type), hash_string);
|
||||
}
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
cl_error_t fmap_will_need_hash_later(fmap_t *map, cli_hash_type_t type)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (NULL == map) {
|
||||
cli_errmsg("fmap_will_need_hash_later: Attempted to set hash for NULL fmap\n");
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("fmap_will_need_hash_later: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* set flags */
|
||||
map->will_need_hash[type] = true;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
@ -1128,54 +1187,40 @@ cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type
|
|||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
size_t todo, at = 0;
|
||||
void *hashctx = NULL;
|
||||
void *hashctx[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||
cli_hash_type_t hash_type;
|
||||
|
||||
todo = map->len;
|
||||
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
if (map->have_md5) {
|
||||
goto complete;
|
||||
}
|
||||
break;
|
||||
case CLI_HASH_SHA1:
|
||||
if (map->have_sha1) {
|
||||
goto complete;
|
||||
}
|
||||
break;
|
||||
case CLI_HASH_SHA256:
|
||||
if (map->have_sha256) {
|
||||
goto complete;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If we already have the hash, just return it */
|
||||
if (map->have_hash[type]) {
|
||||
goto complete;
|
||||
}
|
||||
|
||||
map->will_need_hash[type] = true;
|
||||
|
||||
/*
|
||||
* Need to calculate the hash.
|
||||
* Need to calculate the requested hash and maybe others, as well.
|
||||
*/
|
||||
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
hashctx = cl_hash_init("md5");
|
||||
break;
|
||||
case CLI_HASH_SHA1:
|
||||
hashctx = cl_hash_init("sha1");
|
||||
break;
|
||||
case CLI_HASH_SHA256:
|
||||
hashctx = cl_hash_init("sha256");
|
||||
break;
|
||||
default:
|
||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
if (!(hashctx)) {
|
||||
cli_errmsg("fmap_get_hash: error initializing new md5 hash!\n");
|
||||
goto done;
|
||||
/* Initialize hash contexts for all needed hash types */
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (map->will_need_hash[hash_type] && !map->have_hash[hash_type]) {
|
||||
const char *hash_name = cli_hash_name(hash_type);
|
||||
|
||||
hashctx[hash_type] = cl_hash_init(hash_name);
|
||||
if (NULL == hashctx[hash_type]) {
|
||||
cli_errmsg("fmap_get_hash: error initializing %s hash context\n", hash_name);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (todo) {
|
||||
|
@ -1191,58 +1236,415 @@ cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type
|
|||
todo -= readme;
|
||||
at += readme;
|
||||
|
||||
if (cl_update_hash(hashctx, (void *)buf, readme)) {
|
||||
cli_errmsg("fmap_get_hash: error calculating hash!\n");
|
||||
status = CL_EREAD;
|
||||
goto done;
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (map->will_need_hash[hash_type] && !map->have_hash[hash_type]) {
|
||||
if (cl_update_hash(hashctx[hash_type], buf, readme)) {
|
||||
const char *hash_name = cli_hash_name(hash_type);
|
||||
cli_errmsg("fmap_get_hash: error calculating %s hash!\n", hash_name);
|
||||
status = CL_EREAD;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
cl_finish_hash(hashctx, map->md5);
|
||||
map->have_md5 = true;
|
||||
break;
|
||||
case CLI_HASH_SHA1:
|
||||
cl_finish_hash(hashctx, map->sha1);
|
||||
map->have_sha1 = true;
|
||||
break;
|
||||
case CLI_HASH_SHA256:
|
||||
cl_finish_hash(hashctx, map->sha256);
|
||||
map->have_sha256 = true;
|
||||
break;
|
||||
default:
|
||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (map->will_need_hash[hash_type] && !map->have_hash[hash_type]) {
|
||||
cl_finish_hash(hashctx[hash_type], map->hash[hash_type]);
|
||||
map->have_hash[hash_type] = true;
|
||||
|
||||
/* hashctx is finished, don't need to destroy it later */
|
||||
hashctx[hash_type] = NULL;
|
||||
|
||||
if (cli_debug_flag) {
|
||||
// Convert the hash to a hex string for logging
|
||||
char hash_string[CLI_HASHLEN_MAX * 2 + 1] = {0};
|
||||
size_t hash_len = cli_hash_len(hash_type);
|
||||
|
||||
// Convert hash to string.
|
||||
size_t i;
|
||||
for (i = 0; i < hash_len; i++) {
|
||||
sprintf(hash_string + i * 2, "%02x", map->hash[hash_type][i]);
|
||||
}
|
||||
hash_string[hash_len * 2] = 0;
|
||||
|
||||
cli_dbgmsg("fmap_get_hash: calculated %s hash: %s\n", cli_hash_name(hash_type), hash_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
hashctx = NULL;
|
||||
|
||||
complete:
|
||||
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
*hash = map->md5;
|
||||
break;
|
||||
case CLI_HASH_SHA1:
|
||||
*hash = map->sha1;
|
||||
break;
|
||||
case CLI_HASH_SHA256:
|
||||
*hash = map->sha256;
|
||||
break;
|
||||
default:
|
||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
*hash = map->hash[type];
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (NULL != hashctx[hash_type]) {
|
||||
cl_hash_destroy(hashctx[hash_type]);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public API functions.
|
||||
*/
|
||||
|
||||
extern cl_fmap_t *cl_fmap_open_handle(
|
||||
void *handle,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
clcb_pread pread_cb,
|
||||
int use_aging)
|
||||
{
|
||||
return fmap_open_handle(handle, offset, len, pread_cb, use_aging);
|
||||
}
|
||||
|
||||
extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len)
|
||||
{
|
||||
return (cl_fmap_t *)fmap_open_memory(start, len, NULL);
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_set_name(cl_fmap_t *map, const char *name)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (!map || !name) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
free(map->name);
|
||||
|
||||
map->name = cli_safer_strdup(name);
|
||||
if (!map->name) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
if (NULL != hashctx) {
|
||||
cl_hash_destroy(hashctx);
|
||||
extern cl_error_t cl_fmap_get_name(cl_fmap_t *map, const char **name_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (!map || !name_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*name_out = map->name;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_set_path(cl_fmap_t *map, const char *path)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (!map || !path) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
free(map->path);
|
||||
|
||||
map->path = cli_safer_strdup(path);
|
||||
if (!map->path) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_get_path(cl_fmap_t *map, const char **path_out, size_t *offset_out, size_t *len_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (!map || !path_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*path_out = map->path;
|
||||
if (NULL == *path_out) {
|
||||
status = CL_EACCES;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (offset_out) {
|
||||
*offset_out = map->offset;
|
||||
}
|
||||
|
||||
if (len_out) {
|
||||
*len_out = map->len;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_get_fd(const cl_fmap_t *map, int *fd_out, size_t *offset_out, size_t *len_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (!map || !fd_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*fd_out = fmap_fd((fmap_t *)map);
|
||||
if (*fd_out == -1) {
|
||||
status = CL_EACCES;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (offset_out) {
|
||||
*offset_out = map->offset;
|
||||
}
|
||||
|
||||
if (len_out) {
|
||||
*len_out = map->len;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_get_size(const cl_fmap_t *map, size_t *size_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
if (!map || !size_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*size_out = map->len;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_set_hash(const cl_fmap_t *map, const char *hash_alg, char hash)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
cli_hash_type_t type;
|
||||
|
||||
if (!map || !hash_alg) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cli_hash_type_from_name(hash_alg, &type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_set_hash: Unknown hash algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("cl_fmap_set_hash: Unsupported hash algorithm: %s\n", hash_alg);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = fmap_set_hash((fmap_t *)map, (uint8_t *)&hash, type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_set_hash: Failed to set hash for algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_have_hash(const cl_fmap_t *map, const char *hash_alg, bool *have_hash_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
cli_hash_type_t type;
|
||||
|
||||
if (!map || !hash_alg || !have_hash_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cli_hash_type_from_name(hash_alg, &type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_have_hash: Unknown hash algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("cl_fmap_have_hash: Unsupported hash algorithm: %s\n", hash_alg);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*have_hash_out = map->have_hash[type];
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_will_need_hash_later(const cl_fmap_t *map, const char *hash_alg)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
cli_hash_type_t type;
|
||||
|
||||
if (!map || !hash_alg) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cli_hash_type_from_name(hash_alg, &type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_will_need_hash_later: Unknown hash algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("cl_fmap_will_need_hash_later: Unsupported hash algorithm: %s\n", hash_alg);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = fmap_will_need_hash_later((fmap_t *)map, type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_will_need_hash_later: Failed to indicate need for hash algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_get_hash(const cl_fmap_t *map, const char *hash_alg, char **hash_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
cli_hash_type_t type;
|
||||
unsigned char *hash;
|
||||
char *hash_string = NULL;
|
||||
size_t hash_len;
|
||||
size_t i;
|
||||
|
||||
if (!map || !hash_alg || !hash_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cli_hash_type_from_name(hash_alg, &type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_get_hash: Unknown hash algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||
cli_errmsg("cl_fmap_get_hash: Unsupported hash algorithm: %s\n", hash_alg);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = fmap_get_hash((fmap_t *)map, &hash, type);
|
||||
if (status != CL_SUCCESS) {
|
||||
cli_errmsg("cl_fmap_get_hash: Failed to get hash for algorithm: %s\n", hash_alg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
hash_len = cli_hash_len(type);
|
||||
|
||||
/* Convert hash to string */
|
||||
hash_string = malloc(hash_len * 2 + 1);
|
||||
if (!hash_string) {
|
||||
cli_errmsg("cl_fmap_get_hash: Failed to allocate memory for hash string\n");
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < hash_len; i++) {
|
||||
sprintf(hash_string + i * 2, "%02x", hash[i]);
|
||||
}
|
||||
hash_string[hash_len * 2] = 0;
|
||||
|
||||
*hash_out = hash_string;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (status != CL_SUCCESS) {
|
||||
if (NULL != hash_string) {
|
||||
free(hash_string);
|
||||
hash_string = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
extern cl_error_t cl_fmap_get_data(const cl_fmap_t *map, size_t offset, size_t len, const uint8_t **data_out, size_t *data_len_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
const uint8_t *data;
|
||||
|
||||
if (!map || !data_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (offset > map->len) {
|
||||
cli_errmsg("cl_fmap_get_data: Offset %zu is beyond end of file (file length %zu)\n", offset, map->len);
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
// If len is 0, we want to read to the end of the file.
|
||||
len = map->len - offset;
|
||||
}
|
||||
|
||||
if (offset + len > map->len) {
|
||||
// Adjust len to read only to the end of the file if they asked for too much.
|
||||
len = map->len - offset;
|
||||
}
|
||||
|
||||
data = fmap_need_off_once_len((fmap_t *)map, offset, len, &len);
|
||||
if (!data) {
|
||||
cli_errmsg("cl_fmap_get_data: Failed to get data from fmap\n");
|
||||
status = CL_EREAD;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*data_out = data;
|
||||
if (data_len_out) {
|
||||
*data_len_out = len;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
extern void cl_fmap_close(cl_fmap_t *map)
|
||||
{
|
||||
fmap_free(map);
|
||||
}
|
||||
|
|
|
@ -55,18 +55,20 @@ struct cl_fmap {
|
|||
uint64_t pages;
|
||||
uint64_t pgsz;
|
||||
uint64_t paged;
|
||||
bool aging; /** indicates if we should age off memory mapped pages */
|
||||
bool dont_cache_flag; /** indicates if we should not cache scan results for this fmap. Used if limits exceeded */
|
||||
bool handle_is_fd; /** non-zero if map->handle is an fd. */
|
||||
size_t offset; /** file offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0 */
|
||||
size_t nested_offset; /** offset from start of original fmap (data) for nested scan. 0 for orig fmap. */
|
||||
size_t real_len; /** len from start of original fmap (data) to end of current (possibly nested) map. */
|
||||
/* real_len == nested_offset + len.
|
||||
real_len is needed for nested maps because we only reference the original mapping data.
|
||||
We convert caller's fmap offsets & lengths to real data offsets using nested_offset & real_len. */
|
||||
bool aging; /** Indicates if we should age off memory mapped pages */
|
||||
bool dont_cache_flag; /** Indicates if we should not cache scan results for this fmap. Used if limits exceeded */
|
||||
bool handle_is_fd; /** Non-zero if `map->handle` is an fd. This is needed so that `fmap_fd()` knows if it can
|
||||
return a file descriptor. If it's some other kind of handle, then `fmap_fd()` has to return -1. */
|
||||
size_t offset; /** File offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0.
|
||||
`offset` & `len` are critical information for anyone using the file descriptor/handle */
|
||||
size_t nested_offset; /** Offset from start of original fmap (data) for nested scan. 0 for orig fmap. */
|
||||
size_t real_len; /** Length from start of original fmap (data) to end of current (possibly nested) map.
|
||||
`real_len == nested_offset + len`.
|
||||
`real_len` is needed for nested maps because we only reference the original mapping data.
|
||||
We convert caller's fmap offsets & lengths to real data offsets using `nested_offset` & `real_len`. */
|
||||
|
||||
/* external */
|
||||
size_t len; /** length of data from nested_offset, accessible via current fmap */
|
||||
size_t len; /** Length of data from nested_offset, accessible via current fmap */
|
||||
|
||||
/* real_len = nested_offset + len
|
||||
* file_offset = offset + nested_offset + need_offset
|
||||
|
@ -84,14 +86,19 @@ struct cl_fmap {
|
|||
void (*unneed_off)(fmap_t *, size_t at, size_t len);
|
||||
void *windows_file_handle;
|
||||
void *windows_map_handle;
|
||||
bool have_md5;
|
||||
unsigned char md5[CLI_HASHLEN_MD5];
|
||||
bool have_sha1;
|
||||
unsigned char sha1[CLI_HASHLEN_SHA1];
|
||||
bool have_sha256;
|
||||
unsigned char sha256[CLI_HASHLEN_SHA256];
|
||||
|
||||
/* flags to indicate if we should calculate a hash next time we calculate any hashes */
|
||||
bool will_need_hash[CLI_HASH_AVAIL_TYPES];
|
||||
|
||||
/* flags to indicate if we have calculated a hash */
|
||||
bool have_hash[CLI_HASH_AVAIL_TYPES];
|
||||
|
||||
/* hash values */
|
||||
uint8_t hash[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
|
||||
|
||||
uint64_t *bitmap;
|
||||
char *name;
|
||||
char *name; /* name of the file, e.g. as recorded in a zip file entry record */
|
||||
char *path; /* path to the file/tempfile, if fmap was created from a file descriptor */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -101,14 +108,15 @@ struct cl_fmap {
|
|||
* @param offset Offset into file for start of map.
|
||||
* @param len Length from offset for size of map.
|
||||
* @param name (optional) Original name of the file (to set fmap name metadata)
|
||||
* @return fmap_t* The newly created fmap. Free it with `funmap()`
|
||||
* @param path (optional) Original path of the file (to set fmap path metadata)
|
||||
* @return fmap_t* The newly created fmap. Free it with `fmap_free()`
|
||||
*/
|
||||
fmap_t *fmap(int fd, off_t offset, size_t len, const char *name);
|
||||
fmap_t *fmap_new(int fd, off_t offset, size_t len, const char *name, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Create new fmap given a file descriptor.
|
||||
*
|
||||
* This variant of fmap() provides a boolean output variable to indicate on
|
||||
* This variant of fmap_new() provides a boolean output variable to indicate on
|
||||
* failure if the failure was because the file is empty (not really a failure).
|
||||
*
|
||||
* @param fd File descriptor of file to be mapped.
|
||||
|
@ -116,9 +124,10 @@ fmap_t *fmap(int fd, off_t offset, size_t len, const char *name);
|
|||
* @param len Length from offset for size of map.
|
||||
* @param[out] empty Boolean will be non-zero if the file couldn't be mapped because it is empty.
|
||||
* @param name (optional) Original name of the file (to set fmap name metadata)
|
||||
* @return fmap_t* The newly created fmap. Free it with `funmap()`
|
||||
* @param path (optional) Original path of the file (to set fmap path metadata)
|
||||
* @return fmap_t* The newly created fmap. Free it with `fmap_free()`
|
||||
*/
|
||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name);
|
||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Create a new fmap given a buffer.
|
||||
|
@ -155,7 +164,7 @@ void free_duplicate_fmap(cl_fmap_t *map);
|
|||
*
|
||||
* @param m The map to be free'd.
|
||||
*/
|
||||
static inline void funmap(fmap_t *m)
|
||||
static inline void fmap_free(fmap_t *m)
|
||||
{
|
||||
m->unmap(m);
|
||||
}
|
||||
|
@ -429,6 +438,22 @@ cl_error_t fmap_dump_to_file(fmap_t *map, const char *filepath, const char *tmpd
|
|||
*/
|
||||
int fmap_fd(fmap_t *m);
|
||||
|
||||
/**
|
||||
* @brief Indicate that we will want to calculate this hash later.asm
|
||||
*
|
||||
* Set a flag to provide advanced notice that the next time we get a hash and
|
||||
* it has to calculate the hash, it will also calculate this hash.
|
||||
*
|
||||
* This is an optimization so that all hashes may be calculated in one pass
|
||||
* of the file rather than doing multiple passes of the file for each
|
||||
* needed hash.
|
||||
*
|
||||
* @param map The map in question.
|
||||
* @param type The type of hash we'll need.
|
||||
* @return cl_error_t CL_SUCCESS if was able to set the flag, else some error.
|
||||
*/
|
||||
cl_error_t fmap_will_need_hash_later(fmap_t *map, cli_hash_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the fmap hash.
|
||||
*
|
||||
|
@ -439,7 +464,7 @@ int fmap_fd(fmap_t *m);
|
|||
* @param type The type of hash to calculate.
|
||||
* @return cl_error_t CL_SUCCESS if was able to get the hash, else some error.
|
||||
*/
|
||||
cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type);
|
||||
cl_error_t fmap_get_hash(fmap_t *map, uint8_t **hash, cli_hash_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Set the hash for the fmap that was previously calculated.
|
||||
|
@ -449,6 +474,6 @@ cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type
|
|||
* @param type The type of hash to calculate.
|
||||
* @return cl_error_t CL_SUCCESS if was able to set the hash, else some error.
|
||||
*/
|
||||
cl_error_t fmap_set_hash(fmap_t *map, unsigned char *hash, cli_hash_type_t type);
|
||||
cl_error_t fmap_set_hash(fmap_t *map, uint8_t *hash, cli_hash_type_t type);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) 2013-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2011-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm <tkojm@clamav.net>, Aldo Mazzeo, Micah Snyder
|
||||
* Authors: Tomasz Kojm <tkojm@clamav.net>, Aldo Mazzeo, Valerie Snyder
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
|
|
@ -360,7 +360,7 @@ static cl_error_t hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader,
|
|||
ext = 0;
|
||||
/* Dump file, extent by extent */
|
||||
do {
|
||||
uint32_t currBlock, endBlock, outputSize = 0;
|
||||
uint32_t currBlock, endBlock;
|
||||
if (targetSize == 0) {
|
||||
cli_dbgmsg("hfsplus_scanfile: output complete\n");
|
||||
break;
|
||||
|
@ -423,7 +423,6 @@ static cl_error_t hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader,
|
|||
}
|
||||
|
||||
targetSize -= to_write;
|
||||
outputSize += to_write;
|
||||
currBlock++;
|
||||
|
||||
if (targetSize == 0) {
|
||||
|
@ -1539,7 +1538,7 @@ cli_dbgmsg("sizeof(hfsNodeDescriptor) is %lu\n", sizeof(hfsNodeDescriptor));
|
|||
}
|
||||
|
||||
/* Create temp folder for contents */
|
||||
if (!(targetdir = cli_gentemp_with_prefix(ctx->sub_tmpdir, "hfsplus-tmp"))) {
|
||||
if (!(targetdir = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "hfsplus-tmp"))) {
|
||||
cli_errmsg("cli_scanhfsplus: cli_gentemp failed\n");
|
||||
status = CL_ETMPDIR;
|
||||
goto done;
|
||||
|
|
|
@ -87,7 +87,7 @@ static cl_error_t decompress_and_callback(cli_ctx *ctx, fmap_t *input, size_t at
|
|||
remain = len;
|
||||
|
||||
/* reserve tempfile for output and callback */
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
||||
cli_errmsg("%s: Can't generate temporary file\n", parent);
|
||||
return ret;
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ cl_error_t cli_hwp5header(cli_ctx *ctx, hwp5_header_t *hwp5)
|
|||
if (SCAN_COLLECT_METADATA) {
|
||||
json_object *header, *flags;
|
||||
|
||||
header = cli_jsonobj(ctx->wrkproperty, "Hwp5Header");
|
||||
header = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp5Header");
|
||||
if (!header) {
|
||||
cli_errmsg("HWP5.x: No memory for Hwp5Header object\n");
|
||||
return CL_EMEM;
|
||||
|
@ -405,23 +405,23 @@ cl_error_t cli_scanhwp5_stream(cli_ctx *ctx, hwp5_header_t *hwp5, char *name, in
|
|||
return CL_ESTAT;
|
||||
}
|
||||
|
||||
input = fmap(fd, 0, statbuf.st_size, NULL);
|
||||
input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||
if (!input) {
|
||||
cli_errmsg("HWP5.x: Failed to get fmap for input stream\n");
|
||||
return CL_EMAP;
|
||||
}
|
||||
ret = decompress_and_callback(ctx, input, 0, 0, "HWP5.x", hwp5_cb, NULL);
|
||||
funmap(input);
|
||||
fmap_free(input);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* JSON Output Summary Information */
|
||||
if (SCAN_COLLECT_METADATA && ctx->properties != NULL) {
|
||||
if (SCAN_COLLECT_METADATA && ctx->metadata_json != NULL) {
|
||||
if (name && !strncmp(name, "_5_hwpsummaryinformation", 24)) {
|
||||
cli_dbgmsg("HWP5.x: Detected a '_5_hwpsummaryinformation' stream\n");
|
||||
/* JSONOLE2 - what to do if something breaks? */
|
||||
if (cli_ole2_summary_json(ctx, fd, 2) == CL_ETIMEOUT)
|
||||
if (cli_ole2_summary_json(ctx, fd, 2, filepath) == CL_ETIMEOUT)
|
||||
return CL_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +530,7 @@ static inline cl_error_t parsehwp3_docinfo(cli_ctx *ctx, size_t offset, struct h
|
|||
json_object *header, *flags;
|
||||
char *str;
|
||||
|
||||
header = cli_jsonobj(ctx->wrkproperty, "Hwp3Header");
|
||||
header = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp3Header");
|
||||
if (!header) {
|
||||
cli_errmsg("HWP3.x: No memory for Hwp3Header object\n");
|
||||
return CL_EMEM;
|
||||
|
@ -600,7 +600,7 @@ static inline cl_error_t parsehwp3_docsummary(cli_ctx *ctx, size_t offset)
|
|||
return CL_EMAP;
|
||||
}
|
||||
|
||||
summary = cli_jsonobj(ctx->wrkproperty, "Hwp3SummaryInfo");
|
||||
summary = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp3SummaryInfo");
|
||||
if (!summary) {
|
||||
cli_errmsg("HWP3.x: No memory for json object\n");
|
||||
return CL_EMEM;
|
||||
|
@ -1514,7 +1514,7 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t
|
|||
hwp3_debug("HWP3.x: Information Block @ offset %llu\n", infoloc);
|
||||
|
||||
if (SCAN_COLLECT_METADATA) {
|
||||
infoblk_1 = cli_jsonobj(ctx->wrkproperty, "InfoBlk_1");
|
||||
infoblk_1 = cli_jsonobj(ctx->this_layer_metadata_json, "InfoBlk_1");
|
||||
if (!infoblk_1) {
|
||||
cli_errmsg("HWP5.x: No memory for information block object\n");
|
||||
return CL_EMEM;
|
||||
|
@ -1752,7 +1752,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
return CL_ESTAT;
|
||||
}
|
||||
|
||||
map = dmap = fmap(fd, 0, statbuf.st_size, NULL);
|
||||
map = dmap = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||
if (!map) {
|
||||
cli_errmsg("HWP3.x: Failed to get fmap for uncompressed stream\n");
|
||||
return CL_EMAP;
|
||||
|
@ -1767,14 +1767,14 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
|
||||
/* Fonts - 7 entries of 2 + (n x 40) bytes where n is the first 2 bytes of the entry */
|
||||
if (SCAN_COLLECT_METADATA)
|
||||
fonts = cli_jsonarray(ctx->wrkproperty, "FontCounts");
|
||||
fonts = cli_jsonarray(ctx->this_layer_metadata_json, "FontCounts");
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
uint16_t nfonts;
|
||||
|
||||
if (fmap_readn(map, &nfonts, offset, sizeof(nfonts)) != sizeof(nfonts)) {
|
||||
if (dmap)
|
||||
funmap(dmap);
|
||||
fmap_free(dmap);
|
||||
return CL_EREAD;
|
||||
}
|
||||
nfonts = le16_to_host(nfonts);
|
||||
|
@ -1787,7 +1787,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
if ((new_offset <= offset) || (new_offset >= map->len)) {
|
||||
cli_errmsg("HWP3.x: Font Entry: number of fonts is too high, invalid. %u\n", nfonts);
|
||||
if (dmap)
|
||||
funmap(dmap);
|
||||
fmap_free(dmap);
|
||||
return CL_EPARSE;
|
||||
}
|
||||
offset = new_offset;
|
||||
|
@ -1796,20 +1796,20 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
/* Styles - 2 + (n x 238) bytes where n is the first 2 bytes of the section */
|
||||
if (fmap_readn(map, &nstyles, offset, sizeof(nstyles)) != sizeof(nstyles)) {
|
||||
if (dmap)
|
||||
funmap(dmap);
|
||||
fmap_free(dmap);
|
||||
return CL_EREAD;
|
||||
}
|
||||
nstyles = le16_to_host(nstyles);
|
||||
|
||||
if (SCAN_COLLECT_METADATA)
|
||||
cli_jsonint(ctx->wrkproperty, "StyleCount", nstyles);
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "StyleCount", nstyles);
|
||||
|
||||
hwp3_debug("HWP3.x: %u Styles @ offset %zu\n", nstyles, offset);
|
||||
new_offset = offset + (2 + nstyles * 238);
|
||||
if ((new_offset <= offset) || (new_offset >= map->len)) {
|
||||
cli_errmsg("HWP3.x: Font Entry: number of font styles is too high, invalid. %u\n", nstyles);
|
||||
if (dmap)
|
||||
funmap(dmap);
|
||||
fmap_free(dmap);
|
||||
return CL_EPARSE;
|
||||
}
|
||||
offset += (2 + nstyles * 238);
|
||||
|
@ -1821,12 +1821,12 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
/* return is never a virus */
|
||||
if (ret != CL_SUCCESS) {
|
||||
if (dmap)
|
||||
funmap(dmap);
|
||||
fmap_free(dmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (SCAN_COLLECT_METADATA)
|
||||
cli_jsonint(ctx->wrkproperty, "ParagraphCount", p);
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "ParagraphCount", p);
|
||||
|
||||
last = 0;
|
||||
/* 'additional information block #1's - attachments and media */
|
||||
|
@ -1840,7 +1840,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
}
|
||||
|
||||
if (dmap)
|
||||
funmap(dmap);
|
||||
fmap_free(dmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1887,7 +1887,7 @@ cl_error_t cli_scanhwp3(cli_ctx *ctx)
|
|||
if (docinfo.di_compressed)
|
||||
ret = decompress_and_callback(ctx, ctx->fmap, offset, 0, "HWP3.x", hwp3_cb, NULL);
|
||||
else
|
||||
ret = hwp3_cb(&offset, 0, ctx->sub_filepath, ctx);
|
||||
ret = hwp3_cb(&offset, 0, ctx->fmap->path, ctx);
|
||||
|
||||
if (ret != CL_SUCCESS)
|
||||
return ret;
|
||||
|
@ -1993,7 +1993,7 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in
|
|||
return CL_ESTAT;
|
||||
}
|
||||
|
||||
if (!(input = fmap(fd, 0, statbuf.st_size, NULL))) {
|
||||
if (!(input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath))) {
|
||||
cli_errmsg("HWPML: Failed to get fmap for binary data\n");
|
||||
return CL_EMAP;
|
||||
}
|
||||
|
@ -2001,19 +2001,19 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in
|
|||
/* send data for base64 conversion - TODO: what happens with really big files? */
|
||||
if (!(instream = fmap_need_off_once(input, 0, input->len))) {
|
||||
cli_errmsg("HWPML: Failed to get input stream from binary data\n");
|
||||
funmap(input);
|
||||
fmap_free(input);
|
||||
return CL_EMAP;
|
||||
}
|
||||
|
||||
decoded = (char *)cl_base64_decode((char *)instream, input->len, NULL, &decodedlen, 0);
|
||||
funmap(input);
|
||||
fmap_free(input);
|
||||
if (!decoded) {
|
||||
cli_errmsg("HWPML: Failed to get base64 decode binary data\n");
|
||||
return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||
}
|
||||
|
||||
/* open file for writing and scanning */
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tempfile, &df)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tempfile, &df)) != CL_SUCCESS) {
|
||||
cli_warnmsg("HWPML: Failed to create temporary file for decoded stream scanning\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -2045,14 +2045,14 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in
|
|||
goto hwpml_end;
|
||||
}
|
||||
|
||||
input = fmap(fd, 0, statbuf.st_size, NULL);
|
||||
input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||
if (!input) {
|
||||
cli_errmsg("HWPML: Failed to get fmap for binary data\n");
|
||||
ret = CL_EMAP;
|
||||
goto hwpml_end;
|
||||
}
|
||||
ret = decompress_and_callback(ctx, input, 0, 0, "HWPML", hwpml_scan_cb, NULL);
|
||||
funmap(input);
|
||||
fmap_free(input);
|
||||
} else {
|
||||
if (fd == df) { /* fd is a decoded tempfile */
|
||||
ret = hwpml_scan_cb(NULL, fd, tempfile, ctx);
|
||||
|
@ -2092,7 +2092,7 @@ cl_error_t cli_scanhwpml(cli_ctx *ctx)
|
|||
if (!reader) {
|
||||
cli_dbgmsg("cli_scanhwpml: cannot initialize xmlReader\n");
|
||||
|
||||
ret = cli_json_parse_error(ctx->wrkproperty, "HWPML_ERROR_XML_READER_IO");
|
||||
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "HWPML_ERROR_XML_READER_IO");
|
||||
|
||||
return ret; // libxml2 failed!
|
||||
}
|
||||
|
|
|
@ -250,7 +250,7 @@ cl_error_t cli_scanishield_msi(cli_ctx *ctx, off_t off)
|
|||
|
||||
/* FIXMEISHIELD: cleanup the spam below */
|
||||
cli_dbgmsg("ishield-msi: File %s (csize: %llx, unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x unk7:%x unk8:%x unk9:%x unk10:%x unk11:%x)\n", key, (long long)csize, fb.unk1, fb.unk2, fb.unk3, fb.unk4, fb.unk5, fb.unk6, fb.unk7, fb.unk8, fb.unk9, fb.unk10, fb.unk11);
|
||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
||||
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||
if (NULL != filename) {
|
||||
free(filename);
|
||||
}
|
||||
|
@ -491,7 +491,7 @@ static cl_error_t is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize)
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(fname = cli_gentemp(ctx->sub_tmpdir))) {
|
||||
if (!(fname = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||
return CL_EMEM;
|
||||
}
|
||||
|
||||
|
@ -751,7 +751,7 @@ static cl_error_t is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint
|
|||
return CL_EMEM;
|
||||
}
|
||||
|
||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
||||
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||
free(outbuf);
|
||||
return CL_EMEM;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ static cl_error_t iso_scan_file(const iso9660_t *iso, unsigned int block, unsign
|
|||
int fd = -1;
|
||||
cl_error_t ret = CL_SUCCESS;
|
||||
|
||||
if (cli_gentempfd(iso->ctx->sub_tmpdir, &tmpf, &fd) != CL_SUCCESS) {
|
||||
if (cli_gentempfd(iso->ctx->this_layer_tmpdir, &tmpf, &fd) != CL_SUCCESS) {
|
||||
return CL_ETMPFILE;
|
||||
}
|
||||
|
||||
|
|
|
@ -225,6 +225,39 @@ cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i)
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
cl_error_t cli_jsonuint64(json_object *obj, const char *key, uint64_t i)
|
||||
{
|
||||
json_type objty;
|
||||
json_object *fpobj;
|
||||
if (NULL == obj) {
|
||||
cli_dbgmsg("json: no parent object specified to cli_jsonuint64\n");
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
objty = json_object_get_type(obj);
|
||||
|
||||
if (objty == json_type_object) {
|
||||
if (NULL == key) {
|
||||
cli_dbgmsg("json: null string specified as key to cli_jsonuint64\n");
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
} else if (objty != json_type_array) {
|
||||
return CL_EARG;
|
||||
}
|
||||
|
||||
fpobj = json_object_new_uint64(i);
|
||||
if (NULL == fpobj) {
|
||||
cli_errmsg("json: no memory for json int object.\n");
|
||||
return CL_EMEM;
|
||||
}
|
||||
|
||||
if (objty == json_type_object)
|
||||
json_object_object_add(obj, key, fpobj);
|
||||
else if (objty == json_type_array)
|
||||
json_object_array_add(obj, fpobj);
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
cl_error_t cli_jsonbool(json_object *obj, const char *key, int i)
|
||||
{
|
||||
json_type objty;
|
||||
|
|
|
@ -41,6 +41,7 @@ cl_error_t cli_jsonstr(json_object *obj, const char *key, const char *s);
|
|||
cl_error_t cli_jsonstrlen(json_object *obj, const char *key, const char *s, int len);
|
||||
cl_error_t cli_jsonint(json_object *obj, const char *key, int32_t i);
|
||||
cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i);
|
||||
cl_error_t cli_jsonuint64(json_object *obj, const char *key, uint64_t i);
|
||||
cl_error_t cli_jsonbool(json_object *obj, const char *key, int i);
|
||||
cl_error_t cli_jsondouble(json_object *obj, const char *key, double d);
|
||||
|
||||
|
|
|
@ -68,6 +68,28 @@ CLAMAV_PUBLIC {
|
|||
cl_engine_set_clcb_vba;
|
||||
cl_cvdunpack_ex;
|
||||
cl_cvdverify_ex;
|
||||
cl_scandesc_ex;
|
||||
cl_scanmap_ex;
|
||||
cl_scanfile_ex;
|
||||
cl_fmap_set_name;
|
||||
cl_fmap_get_name;
|
||||
cl_fmap_set_path;
|
||||
cl_fmap_get_path;
|
||||
cl_fmap_get_fd;
|
||||
cl_fmap_get_size;
|
||||
cl_fmap_set_hash;
|
||||
cl_fmap_have_hash;
|
||||
cl_fmap_will_need_hash_later;
|
||||
cl_fmap_get_hash;
|
||||
cl_fmap_get_data;
|
||||
cl_scan_layer_get_fmap;
|
||||
cl_scan_layer_get_parent_layer;
|
||||
cl_scan_layer_get_type;
|
||||
cl_scan_layer_get_recursion_level;
|
||||
cl_scan_layer_get_object_id;
|
||||
cl_scan_layer_get_last_alert;
|
||||
cl_scan_layer_get_attributes;
|
||||
cl_engine_set_scan_callback;
|
||||
};
|
||||
CLAMAV_PRIVATE {
|
||||
global:
|
||||
|
@ -224,7 +246,7 @@ CLAMAV_PRIVATE {
|
|||
cli_bytecode_done;
|
||||
cli_bytecode_debug;
|
||||
cli_hex2ui;
|
||||
fmap;
|
||||
fmap_new;
|
||||
cli_bytecode_context_set_trace;
|
||||
cli_bytecode_debug_printsrc;
|
||||
cli_bytecode_printversion;
|
||||
|
@ -296,6 +318,7 @@ CLAMAV_PRIVATE {
|
|||
cli_checklimits;
|
||||
cli_matchmeta;
|
||||
cli_cvdunpack_and_verify;
|
||||
cli_cvdverify;
|
||||
|
||||
__cli_strcasestr;
|
||||
__cli_strndup;
|
||||
|
|
|
@ -417,7 +417,7 @@ cl_error_t cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
|
|||
}
|
||||
}
|
||||
|
||||
tmp_fname = cli_gentemp(ctx->sub_tmpdir);
|
||||
tmp_fname = cli_gentemp(ctx->this_layer_tmpdir);
|
||||
if (!tmp_fname) {
|
||||
ret = CL_EMEM;
|
||||
goto done;
|
||||
|
@ -546,7 +546,7 @@ cl_error_t cli_scanmschm(cli_ctx *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
tmp_fname = cli_gentemp(ctx->sub_tmpdir);
|
||||
tmp_fname = cli_gentemp(ctx->this_layer_tmpdir);
|
||||
if (!tmp_fname) {
|
||||
ret = CL_EMEM;
|
||||
break;
|
||||
|
|
|
@ -25,15 +25,48 @@
|
|||
typedef enum cli_hash_type {
|
||||
CLI_HASH_MD5 = 0,
|
||||
CLI_HASH_SHA1,
|
||||
CLI_HASH_SHA256,
|
||||
|
||||
/* new hash types go above this line */
|
||||
CLI_HASH_AVAIL_TYPES
|
||||
CLI_HASH_SHA2_256,
|
||||
CLI_HASH_SHA2_384,
|
||||
CLI_HASH_SHA2_512,
|
||||
} cli_hash_type_t;
|
||||
|
||||
#define CLI_HASHLEN_MD5 16
|
||||
#define CLI_HASHLEN_SHA1 20
|
||||
#define CLI_HASHLEN_SHA256 32
|
||||
#define CLI_HASHLEN_MAX 32
|
||||
#define CLI_HASH_AVAIL_TYPES (CLI_HASH_SHA2_256 + 1)
|
||||
|
||||
/**
|
||||
* @brief Get the name of the hash type as a string.
|
||||
*
|
||||
* @param type The hash type.
|
||||
* @return char* The name of the hash type.
|
||||
*/
|
||||
const char* cli_hash_name(cli_hash_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Get OpenSSL's name of the hash type as a string.
|
||||
*
|
||||
* Needed because older versions of OpenSSL aren't familiar with "sha2-256",
|
||||
* "sha2-384", and "sha2-512".
|
||||
*
|
||||
* @param alg The name of the hash algorithm.
|
||||
* @return char* The OpenSSL name of the hash algorithm.
|
||||
*/
|
||||
const char *to_openssl_alg(const char *alg);
|
||||
|
||||
/**
|
||||
* @brief Get the size of the hash type.
|
||||
*
|
||||
* @param type The hash type.
|
||||
* @return size_t The size of the hash type.
|
||||
*/
|
||||
size_t cli_hash_len(cli_hash_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Get the hash type from its name.
|
||||
*
|
||||
* @param name The name of the hash type.
|
||||
* @return cli_hash_type_t The hash type.
|
||||
*/
|
||||
cl_error_t cli_hash_type_from_name(const char* name, cli_hash_type_t* type_out);
|
||||
|
||||
#define CLI_HASHLEN_MAX SHA256_HASH_SIZE
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,14 +26,109 @@
|
|||
#include "others.h"
|
||||
#include "str.h"
|
||||
|
||||
int hm_addhash_str(struct cli_matcher *root, const char *strhash, uint32_t size, const char *virusname)
|
||||
const char *cli_hash_name(cli_hash_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
return "md5";
|
||||
case CLI_HASH_SHA1:
|
||||
return "sha1";
|
||||
case CLI_HASH_SHA2_256:
|
||||
return "sha2-256";
|
||||
case CLI_HASH_SHA2_384:
|
||||
return "sha2-384";
|
||||
case CLI_HASH_SHA2_512:
|
||||
return "sha2-512";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char *to_openssl_alg(const char *alg) {
|
||||
cl_error_t ret;
|
||||
cli_hash_type_t type;
|
||||
|
||||
ret = cli_hash_type_from_name(alg, &type);
|
||||
if (CL_SUCCESS != ret) {
|
||||
cli_dbgmsg("to_openssl_alg: unknown hash type %s\n", alg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
return "md5";
|
||||
case CLI_HASH_SHA1:
|
||||
return "sha1";
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
case CLI_HASH_SHA2_256:
|
||||
return "sha2-256";
|
||||
case CLI_HASH_SHA2_384:
|
||||
return "sha2-384";
|
||||
case CLI_HASH_SHA2_512:
|
||||
return "sha2-512";
|
||||
#else
|
||||
case CLI_HASH_SHA2_256:
|
||||
return "sha256";
|
||||
case CLI_HASH_SHA2_384:
|
||||
return "sha384";
|
||||
case CLI_HASH_SHA2_512:
|
||||
return "sha512";
|
||||
#endif
|
||||
default:
|
||||
cli_dbgmsg("to_openssl_alg: unknown hash type %d\n", type);
|
||||
return NULL; // Unsupported hash type
|
||||
}
|
||||
}
|
||||
|
||||
size_t cli_hash_len(cli_hash_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case CLI_HASH_MD5:
|
||||
return MD5_HASH_SIZE;
|
||||
case CLI_HASH_SHA1:
|
||||
return SHA1_HASH_SIZE;
|
||||
case CLI_HASH_SHA2_256:
|
||||
return SHA256_HASH_SIZE;
|
||||
case CLI_HASH_SHA2_384:
|
||||
return SHA384_HASH_SIZE;
|
||||
case CLI_HASH_SHA2_512:
|
||||
return SHA512_HASH_SIZE;
|
||||
default:
|
||||
return 0; // Invalid type
|
||||
}
|
||||
}
|
||||
|
||||
cl_error_t cli_hash_type_from_name(const char *name, cli_hash_type_t *type_out)
|
||||
{
|
||||
if (!name || !type_out) {
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
if (strcasecmp(name, "md5") == 0) {
|
||||
*type_out = CLI_HASH_MD5;
|
||||
} else if (strcasecmp(name, "sha1") == 0) {
|
||||
*type_out = CLI_HASH_SHA1;
|
||||
} else if ((strcasecmp(name, "sha2-256") == 0) || (strcasecmp(name, "sha256") == 0)) {
|
||||
*type_out = CLI_HASH_SHA2_256;
|
||||
} else if ((strcasecmp(name, "sha2-384") == 0) || (strcasecmp(name, "sha384") == 0)) {
|
||||
*type_out = CLI_HASH_SHA2_384;
|
||||
} else if ((strcasecmp(name, "sha2-512") == 0) || (strcasecmp(name, "sha512") == 0)) {
|
||||
*type_out = CLI_HASH_SHA2_512;
|
||||
} else {
|
||||
return CL_EARG; // Unknown hash type name
|
||||
}
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
cl_error_t hm_addhash_str(struct cl_engine *engine, hash_purpose_t purpose, const char *strhash, uint32_t size, const char *virusname)
|
||||
{
|
||||
cli_hash_type_t type;
|
||||
char binhash[CLI_HASHLEN_MAX];
|
||||
int hlen;
|
||||
char binhash[SHA256_HASH_SIZE];
|
||||
size_t hlen;
|
||||
|
||||
if (!root || !strhash) {
|
||||
cli_errmsg("hm_addhash_str: NULL root or hash\n");
|
||||
if (!engine || !strhash) {
|
||||
cli_errmsg("hm_addhash_str: NULL engine or hash\n");
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
|
@ -45,46 +140,78 @@ int hm_addhash_str(struct cli_matcher *root, const char *strhash, uint32_t size,
|
|||
|
||||
hlen = strlen(strhash);
|
||||
switch (hlen) {
|
||||
case 32:
|
||||
case (MD5_HASH_SIZE * 2):
|
||||
type = CLI_HASH_MD5;
|
||||
break;
|
||||
case 40:
|
||||
case (SHA1_HASH_SIZE * 2):
|
||||
type = CLI_HASH_SHA1;
|
||||
break;
|
||||
case 64:
|
||||
type = CLI_HASH_SHA256;
|
||||
case (SHA256_HASH_SIZE * 2):
|
||||
type = CLI_HASH_SHA2_256;
|
||||
break;
|
||||
default:
|
||||
cli_errmsg("hm_addhash_str: invalid hash %s -- FIXME!\n", strhash);
|
||||
return CL_EARG;
|
||||
}
|
||||
|
||||
if (cli_hex2str_to(strhash, (char *)binhash, hlen)) {
|
||||
cli_errmsg("hm_addhash_str: invalid hash %s\n", strhash);
|
||||
return CL_EARG;
|
||||
}
|
||||
|
||||
return hm_addhash_bin(root, binhash, type, size, virusname);
|
||||
return hm_addhash_bin(engine, purpose, binhash, type, size, virusname);
|
||||
}
|
||||
|
||||
const unsigned int hashlen[] = {
|
||||
CLI_HASHLEN_MD5,
|
||||
CLI_HASHLEN_SHA1,
|
||||
CLI_HASHLEN_SHA256};
|
||||
|
||||
int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname)
|
||||
cl_error_t hm_addhash_bin(struct cl_engine *engine, hash_purpose_t purpose, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname)
|
||||
{
|
||||
const unsigned int hlen = hashlen[type];
|
||||
size_t hlen = cli_hash_len(type);
|
||||
const struct cli_htu32_element *item;
|
||||
struct cli_sz_hash *szh;
|
||||
struct cli_htu32 *ht;
|
||||
int i;
|
||||
cl_error_t ret;
|
||||
struct cli_matcher *root = NULL;
|
||||
|
||||
if (purpose == HASH_PURPOSE_PE_SECTION_DETECT) {
|
||||
root = engine->hm_mdb;
|
||||
} else if (purpose == HASH_PURPOSE_WHOLE_FILE_DETECT) {
|
||||
root = engine->hm_hdb;
|
||||
} else if (purpose == HASH_PURPOSE_PE_IMPORT_DETECT) {
|
||||
root = engine->hm_imp;
|
||||
} else if (purpose == HASH_PURPOSE_WHOLE_FILE_FP_CHECK) {
|
||||
if ((type == CLI_HASH_MD5 || type == CLI_HASH_SHA1) &&
|
||||
(engine->engine_options & ENGINE_OPTIONS_FIPS_LIMITS)) {
|
||||
return CL_SUCCESS; // No error, just skip adding MD5/SHA1 FP hashes in FIPS mode
|
||||
}
|
||||
root = engine->hm_fp;
|
||||
}
|
||||
|
||||
if (NULL == root) {
|
||||
if (NULL == (root = MPOOL_CALLOC(engine->mempool, 1, sizeof(*root)))) {
|
||||
return CL_EMEM;
|
||||
}
|
||||
#ifdef USE_MPOOL
|
||||
root->mempool = engine->mempool;
|
||||
#endif
|
||||
if (purpose == HASH_PURPOSE_WHOLE_FILE_DETECT) {
|
||||
engine->hm_hdb = root;
|
||||
} else if (purpose == HASH_PURPOSE_PE_SECTION_DETECT) {
|
||||
engine->hm_mdb = root;
|
||||
} else if (purpose == HASH_PURPOSE_PE_IMPORT_DETECT) {
|
||||
engine->hm_imp = root;
|
||||
} else if (purpose == HASH_PURPOSE_WHOLE_FILE_FP_CHECK) {
|
||||
engine->hm_fp = root;
|
||||
}
|
||||
}
|
||||
|
||||
if (size) {
|
||||
/* size non-zero, find sz_hash element in size-driven hashtable */
|
||||
ht = &root->hm.sizehashes[type];
|
||||
if (!root->hm.sizehashes[type].capacity) {
|
||||
i = CLI_HTU32_INIT(ht, 64, root->mempool);
|
||||
if (i) return i;
|
||||
ret = CLI_HTU32_INIT(ht, 64, root->mempool);
|
||||
if (CL_SUCCESS != ret) {
|
||||
cli_errmsg("hm_addhash_bin: failed to initialize hash table\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
item = cli_htu32_find(ht, size);
|
||||
|
@ -98,14 +225,15 @@ int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_
|
|||
|
||||
htitem.key = size;
|
||||
htitem.data.as_ptr = szh;
|
||||
i = CLI_HTU32_INSERT(ht, &htitem, root->mempool);
|
||||
if (i) {
|
||||
ret = CLI_HTU32_INSERT(ht, &htitem, root->mempool);
|
||||
if (CL_SUCCESS != ret) {
|
||||
cli_errmsg("hm_addhash_bin: failed to add item to hashtab");
|
||||
MPOOL_FREE(root->mempool, szh);
|
||||
return i;
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
szh = (struct cli_sz_hash *)item->data.as_ptr;
|
||||
}
|
||||
} else {
|
||||
/* size 0 = wildcard */
|
||||
szh = &root->hwild.hashes[type];
|
||||
|
@ -133,7 +261,7 @@ int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_
|
|||
memcpy(&szh->hash_array[(szh->items - 1) * hlen], binhash, hlen);
|
||||
szh->virusnames[(szh->items - 1)] = virusname;
|
||||
|
||||
return 0;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int hm_cmp(const uint8_t *itm, const uint8_t *ref, unsigned int keylen)
|
||||
|
@ -209,7 +337,7 @@ void hm_flush(struct cli_matcher *root)
|
|||
|
||||
while ((item = cli_htu32_next(ht, item))) {
|
||||
szh = (struct cli_sz_hash *)item->data.as_ptr;
|
||||
keylen = hashlen[type];
|
||||
keylen = cli_hash_len(type);
|
||||
|
||||
if (szh->items > 1)
|
||||
hm_sort(szh, 0, szh->items, keylen);
|
||||
|
@ -218,29 +346,29 @@ void hm_flush(struct cli_matcher *root)
|
|||
|
||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||
szh = &root->hwild.hashes[type];
|
||||
keylen = hashlen[type];
|
||||
keylen = cli_hash_len(type);
|
||||
|
||||
if (szh->items > 1)
|
||||
hm_sort(szh, 0, szh->items, keylen);
|
||||
}
|
||||
}
|
||||
|
||||
int cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size)
|
||||
bool cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size)
|
||||
{
|
||||
return (size && size != 0xffffffff && root && root->hm.sizehashes[type].capacity && cli_htu32_find(&root->hm.sizehashes[type], size));
|
||||
}
|
||||
|
||||
int cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type)
|
||||
bool cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type)
|
||||
{
|
||||
return (root && root->hwild.hashes[type].items);
|
||||
}
|
||||
|
||||
int cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type)
|
||||
bool cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type)
|
||||
{
|
||||
return (root && (root->hwild.hashes[type].items || root->hm.sizehashes[type].capacity));
|
||||
}
|
||||
|
||||
static int hm_scan(const unsigned char *digest, const char **virname, const struct cli_sz_hash *szh, cli_hash_type_t type)
|
||||
static cl_error_t hm_scan(const uint8_t *digest, const char **virname, const struct cli_sz_hash *szh, cli_hash_type_t type)
|
||||
{
|
||||
unsigned int keylen;
|
||||
size_t l, r;
|
||||
|
@ -248,7 +376,7 @@ static int hm_scan(const unsigned char *digest, const char **virname, const stru
|
|||
if (!digest || !szh || !szh->items)
|
||||
return CL_CLEAN;
|
||||
|
||||
keylen = hashlen[type];
|
||||
keylen = cli_hash_len(type);
|
||||
|
||||
l = 0;
|
||||
r = szh->items - 1;
|
||||
|
@ -272,7 +400,7 @@ static int hm_scan(const unsigned char *digest, const char **virname, const stru
|
|||
}
|
||||
|
||||
/* cli_hm_scan will scan only size-specific hashes, if any */
|
||||
int cli_hm_scan(const unsigned char *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
||||
cl_error_t cli_hm_scan(const uint8_t *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
||||
{
|
||||
const struct cli_htu32_element *item;
|
||||
struct cli_sz_hash *szh;
|
||||
|
@ -290,7 +418,7 @@ int cli_hm_scan(const unsigned char *digest, uint32_t size, const char **virname
|
|||
}
|
||||
|
||||
/* cli_hm_scan_wild will scan only size-agnostic hashes, if any */
|
||||
int cli_hm_scan_wild(const unsigned char *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
||||
cl_error_t cli_hm_scan_wild(const uint8_t *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
||||
{
|
||||
if (!digest || !root || !root->hwild.hashes[type].items)
|
||||
return CL_CLEAN;
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
#include "matcher-hash-types.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
typedef enum {
|
||||
HASH_PURPOSE_PE_SECTION_DETECT = 0, /** PE section hash malware detection (aka .mdb, .mdu, .msb, .msu) */
|
||||
HASH_PURPOSE_WHOLE_FILE_DETECT, /** Whole file hash malware detection (aka .hdb, .hdu, .hsb, .hsu) */
|
||||
HASH_PURPOSE_WHOLE_FILE_FP_CHECK, /** Whole file false positive prevention (aka .fp, .sfp) */
|
||||
HASH_PURPOSE_PE_IMPORT_DETECT /** PE import hash malware detection (aka .imp) */
|
||||
} hash_purpose_t;
|
||||
|
||||
struct cli_sz_hash {
|
||||
uint8_t *hash_array;
|
||||
const char **virusnames;
|
||||
|
@ -44,14 +51,14 @@ struct cli_hash_wild {
|
|||
struct cli_sz_hash hashes[CLI_HASH_AVAIL_TYPES];
|
||||
};
|
||||
|
||||
int hm_addhash_str(struct cli_matcher *root, const char *strhash, uint32_t size, const char *virusname);
|
||||
int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname);
|
||||
cl_error_t hm_addhash_str(struct cl_engine *engine, hash_purpose_t purpose, const char *strhash, uint32_t size, const char *virusname);
|
||||
cl_error_t hm_addhash_bin(struct cl_engine *engine, hash_purpose_t purpose, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname);
|
||||
void hm_flush(struct cli_matcher *root);
|
||||
int cli_hm_scan(const unsigned char *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
||||
int cli_hm_scan_wild(const unsigned char *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
||||
int cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size);
|
||||
int cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type);
|
||||
int cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type);
|
||||
cl_error_t cli_hm_scan(const uint8_t *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
||||
cl_error_t cli_hm_scan_wild(const uint8_t *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
||||
bool cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size);
|
||||
bool cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type);
|
||||
bool cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type);
|
||||
void hm_free(struct cli_matcher *root);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -572,148 +572,174 @@ void cli_targetinfo_destroy(struct cli_target_info *info)
|
|||
cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname)
|
||||
{
|
||||
cl_error_t status = CL_VIRUS;
|
||||
char md5[33];
|
||||
unsigned int i;
|
||||
cl_error_t ret;
|
||||
|
||||
size_t i;
|
||||
const char *virname = NULL;
|
||||
fmap_t *map;
|
||||
int32_t stack_index;
|
||||
const char *ptr;
|
||||
uint8_t shash1[SHA1_HASH_SIZE * 2 + 1];
|
||||
uint8_t shash256[SHA256_HASH_SIZE * 2 + 1];
|
||||
int have_sha1, have_sha256;
|
||||
unsigned char *digest;
|
||||
size_t size;
|
||||
|
||||
uint8_t *hash;
|
||||
cli_hash_type_t hash_type;
|
||||
char hash_string[SHA256_HASH_SIZE * 2 + 1];
|
||||
|
||||
bool need_hash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||
|
||||
stack_index = (int32_t)ctx->recursion_level;
|
||||
|
||||
char *source = NULL;
|
||||
size_t source_len;
|
||||
|
||||
while (stack_index >= 0) {
|
||||
map = ctx->recursion_stack[stack_index].fmap;
|
||||
|
||||
if (CL_SUCCESS != fmap_get_hash(map, &digest, CLI_HASH_MD5)) {
|
||||
cli_dbgmsg("cli_check_fp: Failed to get a hash for the map at stack index # %u\n", stack_index);
|
||||
stack_index--;
|
||||
continue;
|
||||
}
|
||||
size = map->len;
|
||||
need_hash[CLI_HASH_MD5] = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_MD5, map->len) ||
|
||||
cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_MD5);
|
||||
|
||||
/*
|
||||
* First, check the MD5 digest.
|
||||
* MD5 is default, so it always exists.
|
||||
*/
|
||||
if (cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: %d\n", virname, (int)size);
|
||||
return CL_CLEAN;
|
||||
} else if (cli_hm_scan_wild(digest, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: *\n", virname);
|
||||
return CL_CLEAN;
|
||||
}
|
||||
need_hash[CLI_HASH_SHA1] = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, map->len) ||
|
||||
cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA1) ||
|
||||
cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1);
|
||||
|
||||
if (cli_debug_flag || ctx->engine->cb_hash) {
|
||||
const char *name = ctx->recursion_stack[stack_index].fmap->name;
|
||||
const char *type = cli_ftname(ctx->recursion_stack[stack_index].type);
|
||||
need_hash[CLI_HASH_SHA2_256] = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA2_256, map->len) ||
|
||||
cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA2_256) ||
|
||||
cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA2_256, 1);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(md5 + i * 2, "%02x", digest[i]);
|
||||
md5[32] = 0;
|
||||
|
||||
cli_dbgmsg("FP SIGNATURE: %s:%u:%s # Name: %s, Type: %s\n",
|
||||
md5, (unsigned int)size, vname ? vname : "Name", name ? name : "n/a", type);
|
||||
}
|
||||
|
||||
have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA1) || cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1);
|
||||
have_sha256 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA256);
|
||||
if (have_sha1 || have_sha256) {
|
||||
if ((ptr = fmap_need_off_once(map, 0, size))) {
|
||||
if (have_sha1) {
|
||||
cl_sha1(ptr, size, &shash1[SHA1_HASH_SIZE], NULL);
|
||||
|
||||
if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
|
||||
return CL_CLEAN;
|
||||
}
|
||||
if (cli_hm_scan_wild(&shash1[SHA1_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
|
||||
return CL_CLEAN;
|
||||
}
|
||||
/* See whether the hash matches those loaded in from .cat files
|
||||
* (associated with the .CAB file type) */
|
||||
if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(sha1): Found .CAB false positive detection via catalog file\n");
|
||||
return CL_CLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_sha256) {
|
||||
cl_sha256(ptr, size, &shash256[SHA256_HASH_SIZE], NULL);
|
||||
|
||||
if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
|
||||
return CL_CLEAN;
|
||||
}
|
||||
if (cli_hm_scan_wild(&shash256[SHA256_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
|
||||
return CL_CLEAN;
|
||||
}
|
||||
/* See whether the hash matches those loaded in from .cat files
|
||||
* (associated with the .CAB file type) */
|
||||
if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp(sha256): Found .CAB false positive detection via catalog file\n");
|
||||
return CL_CLEAN;
|
||||
}
|
||||
/* Set fmap to need hash later if required.
|
||||
* This is an optimization so we can calculate all needed hashes in one pass. */
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (need_hash[hash_type]) {
|
||||
ret = fmap_will_need_hash_later(map, hash_type);
|
||||
if (CL_SUCCESS != ret) {
|
||||
cli_dbgmsg("cli_check_fp: Failed to set fmap to need MD5 hash later\n");
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
if (SCAN_DEV_COLLECT_SHA && (ctx->sha_collect > 0)) {
|
||||
if ((ptr = fmap_need_off_once(map, 0, size))) {
|
||||
if (!have_sha256)
|
||||
cl_sha256(ptr, size, shash256 + SHA256_HASH_SIZE, NULL);
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (need_hash[hash_type]) {
|
||||
size_t hash_len = cli_hash_len(hash_type);
|
||||
|
||||
for (i = 0; i < SHA256_HASH_SIZE; i++)
|
||||
sprintf((char *)shash256 + i * 2, "%02x", shash256[SHA256_HASH_SIZE + i]);
|
||||
|
||||
if (!have_sha1)
|
||||
cl_sha1(ptr, size, shash1 + SHA1_HASH_SIZE);
|
||||
|
||||
for (i = 0; i < SHA1_HASH_SIZE; i++)
|
||||
sprintf((char *)shash1 + i * 2, "%02x", shash1[SHA1_HASH_SIZE + i]);
|
||||
|
||||
if (NULL == ctx->target_filepath) {
|
||||
cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", "NO_IDEA");
|
||||
} else {
|
||||
cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", ctx->target_filepath);
|
||||
/* If we need a hash, we will calculate it now */
|
||||
ret = fmap_get_hash(map, &hash, hash_type);
|
||||
if (CL_SUCCESS != ret) {
|
||||
cli_dbgmsg("cli_check_fp: Failed to get hash for the map at stack index # %u\n", stack_index);
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
} else
|
||||
cli_errmsg("can't compute sha\n!");
|
||||
|
||||
ctx->sha_collect = -1;
|
||||
}
|
||||
#endif
|
||||
/* Convert hash to string */
|
||||
for (i = 0; i < hash_len; i++) {
|
||||
sprintf(hash_string + i * 2, "%02x", hash[i]);
|
||||
}
|
||||
hash_string[hash_len * 2] = 0;
|
||||
|
||||
if (ctx->engine->cb_hash)
|
||||
ctx->engine->cb_hash(fmap_fd(ctx->fmap), size, (const unsigned char *)md5, vname ? vname : "noname", ctx->cb_ctx);
|
||||
if (cli_debug_flag || ctx->engine->cb_hash) {
|
||||
const char *name = ctx->recursion_stack[stack_index].fmap->name;
|
||||
const char *type = cli_ftname(ctx->recursion_stack[stack_index].type);
|
||||
|
||||
if (ctx->engine->cb_stats_add_sample) {
|
||||
stats_section_t sections;
|
||||
memset(§ions, 0x00, sizeof(stats_section_t));
|
||||
cli_dbgmsg("FP SIGNATURE: %s:%u:%s # Name: %s, Type: %s\n",
|
||||
hash_string, (unsigned int)map->len, vname ? vname : "Name", name ? name : "n/a", type);
|
||||
}
|
||||
|
||||
if (!(ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_STATS) &&
|
||||
!(ctx->engine->dconf->stats & (DCONF_STATS_DISABLED | DCONF_STATS_PE_SECTION_DISABLED)))
|
||||
cli_genhash_pe(ctx, CL_GENHASH_PE_CLASS_SECTION, 1, §ions);
|
||||
if (CLI_HASH_MD5 == hash_type) {
|
||||
/* Run legacy callbacks that include MD5 hash */
|
||||
if (ctx->engine->cb_hash) {
|
||||
ctx->engine->cb_hash(fmap_fd(ctx->fmap), map->len, hash_string, vname ? vname : "noname", ctx->cb_ctx);
|
||||
}
|
||||
|
||||
// TODO We probably only want to call cb_stats_add_sample when
|
||||
// sections.section != NULL... leaving as is for now
|
||||
ctx->engine->cb_stats_add_sample(vname ? vname : "noname", digest, size, §ions, ctx->engine->stats_data);
|
||||
if (ctx->engine->cb_stats_add_sample) {
|
||||
stats_section_t sections;
|
||||
memset(§ions, 0x00, sizeof(stats_section_t));
|
||||
|
||||
if (sections.sections) {
|
||||
free(sections.sections);
|
||||
if (!(ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_STATS) &&
|
||||
!(ctx->engine->dconf->stats & (DCONF_STATS_DISABLED | DCONF_STATS_PE_SECTION_DISABLED))) {
|
||||
|
||||
cli_genhash_pe(ctx, CL_GENHASH_PE_CLASS_SECTION, 1, §ions);
|
||||
}
|
||||
|
||||
// TODO We probably only want to call cb_stats_add_sample when
|
||||
// sections.section != NULL... leaving as is for now
|
||||
ctx->engine->cb_stats_add_sample(vname ? vname : "noname", hash, map->len, §ions, ctx->engine->stats_data);
|
||||
|
||||
if (sections.sections) {
|
||||
free(sections.sections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_hm_scan(hash, map->len, &virname, ctx->engine->hm_fp, hash_type) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp: Found false positive detection for %s (fp sig: %s)\n", cli_hash_name(hash_type), virname);
|
||||
|
||||
source_len = strlen(virname) + strlen("false positive signature match: ") + 1;
|
||||
source = malloc(source_len);
|
||||
if (source) {
|
||||
snprintf(source, source_len, "false positive signature match: %s", virname);
|
||||
}
|
||||
|
||||
// Remove any evidence and set the verdict to trusted for the layer where the FP hash matched, and for all contained layers.
|
||||
(void)cli_trust_layers(ctx, (uint32_t)stack_index, ctx->recursion_level, source);
|
||||
|
||||
free(source);
|
||||
source = NULL;
|
||||
|
||||
status = CL_VERIFIED;
|
||||
goto done;
|
||||
}
|
||||
if (cli_hm_scan_wild(hash, &virname, ctx->engine->hm_fp, hash_type) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp: Found false positive detection for %s (fp sig: %s)\n", cli_hash_name(hash_type), virname);
|
||||
|
||||
source_len = strlen(virname) + strlen("false positive signature match: ") + 1;
|
||||
source = malloc(source_len);
|
||||
if (source) {
|
||||
snprintf(source, source_len, "false positive signature match: %s", virname);
|
||||
}
|
||||
|
||||
// Remove any evidence and set the verdict to trusted for the layer where the FP hash matched, and for all contained layers.
|
||||
(void)cli_trust_layers(ctx, (uint32_t)stack_index, ctx->recursion_level, source);
|
||||
|
||||
free(source);
|
||||
source = NULL;
|
||||
|
||||
status = CL_VERIFIED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (CLI_HASH_MD5 != hash_type) {
|
||||
/* See whether the hash matches those loaded in from .cat files
|
||||
* (associated with the .CAB file type) */
|
||||
if (cli_hm_scan(hash, 1, &virname, ctx->engine->hm_fp, hash_type) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_fp: Found .CAB false positive detection for %s via catalog file\n", cli_hash_name(hash_type));
|
||||
|
||||
source_len = strlen(virname) + strlen("false positive signature match: ") + 1;
|
||||
source = malloc(source_len);
|
||||
if (source) {
|
||||
snprintf(source, source_len, "false positive signature match: %s", virname);
|
||||
}
|
||||
|
||||
// Remove any evidence and set the verdict to trusted for the layer where the FP hash matched, and for all contained layers.
|
||||
(void)cli_trust_layers(ctx, (uint32_t)stack_index, ctx->recursion_level, source);
|
||||
|
||||
free(source);
|
||||
source = NULL;
|
||||
|
||||
status = CL_VERIFIED;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack_index -= 1;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (NULL != source) {
|
||||
free(source);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -778,13 +804,13 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t
|
|||
return (int32_t)ret;
|
||||
}
|
||||
|
||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, uint32_t attributes)
|
||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, const char *path, uint32_t attributes)
|
||||
{
|
||||
cl_error_t status = CL_CLEAN;
|
||||
int empty;
|
||||
fmap_t *new_map = NULL;
|
||||
|
||||
new_map = fmap_check_empty(desc, 0, 0, &empty, name);
|
||||
new_map = fmap_check_empty(desc, 0, 0, &empty, name, path);
|
||||
if (NULL == new_map) {
|
||||
if (!empty) {
|
||||
cli_dbgmsg("cli_scan_desc: Failed to allocate new map for file descriptor scan.\n");
|
||||
|
@ -799,13 +825,13 @@ cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype
|
|||
goto done;
|
||||
}
|
||||
|
||||
status = cli_scan_fmap(ctx, ftype, filetype_only, ftoffset, acmode, acres, NULL);
|
||||
status = cli_scan_fmap(ctx, ftype, filetype_only, ftoffset, acmode, acres);
|
||||
|
||||
(void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
|
||||
|
||||
done:
|
||||
if (NULL != new_map) {
|
||||
funmap(new_map);
|
||||
fmap_free(new_map);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -830,7 +856,7 @@ static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
|
||||
static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, uint32_t lsid)
|
||||
{
|
||||
cl_error_t status = CL_CLEAN;
|
||||
unsigned evalcnt = 0;
|
||||
|
@ -893,7 +919,10 @@ static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
|||
// Instead of alerting, we'll make a duplicate fmap (add recursion depth, to prevent infinite loops) and
|
||||
// scan the file with the handler type.
|
||||
|
||||
if (hash && 0 != memcmp(ctx->handlertype_hash, hash, 16)) {
|
||||
/*
|
||||
* If the current layer was re-typed already, then prevent HandlerType from being applied again.
|
||||
*/
|
||||
if (!(ctx->recursion_stack[ctx->recursion_level].attributes & LAYER_ATTRIBUTES_RETYPED)) {
|
||||
/*
|
||||
* Create an fmap window into our current fmap using the original offset & length, and rescan as the new type
|
||||
*
|
||||
|
@ -910,9 +939,7 @@ static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
|||
goto done;
|
||||
}
|
||||
|
||||
memcpy(ctx->handlertype_hash, hash, 16);
|
||||
|
||||
status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true, LAYER_ATTRIBUTES_NONE); /* Perform scan with child fmap */
|
||||
status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true, LAYER_ATTRIBUTES_RETYPED); /* Perform scan with child fmap */
|
||||
if (CL_SUCCESS != status) {
|
||||
cli_dbgmsg("Failed to re-scan fmap as a new type.\n");
|
||||
goto done;
|
||||
|
@ -970,14 +997,12 @@ done:
|
|||
}
|
||||
|
||||
#ifdef HAVE_YARA
|
||||
static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
|
||||
static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, uint32_t lsid)
|
||||
{
|
||||
struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
|
||||
cl_error_t rc;
|
||||
YR_SCAN_CONTEXT context;
|
||||
|
||||
(void)hash;
|
||||
|
||||
memset(&context, 0, sizeof(YR_SCAN_CONTEXT));
|
||||
context.fmap = ctx->fmap;
|
||||
context.file_size = ctx->fmap->len;
|
||||
|
@ -999,18 +1024,18 @@ static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
|||
}
|
||||
#endif
|
||||
|
||||
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
|
||||
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info)
|
||||
{
|
||||
uint32_t i;
|
||||
cl_error_t status = CL_SUCCESS;
|
||||
|
||||
for (i = 0; i < root->ac_lsigs; i++) {
|
||||
if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL) {
|
||||
status = lsig_eval(ctx, root, acdata, target_info, hash, i);
|
||||
status = lsig_eval(ctx, root, acdata, target_info, i);
|
||||
}
|
||||
#ifdef HAVE_YARA
|
||||
else if (root->ac_lsigtable[i]->type == CLI_YARA_NORMAL || root->ac_lsigtable[i]->type == CLI_YARA_OFFSET) {
|
||||
status = yara_eval(ctx, root, acdata, target_info, hash, i);
|
||||
status = yara_eval(ctx, root, acdata, target_info, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1033,11 +1058,16 @@ cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_da
|
|||
return status;
|
||||
}
|
||||
|
||||
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
|
||||
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres)
|
||||
{
|
||||
const unsigned char *buff;
|
||||
cl_error_t ret = CL_CLEAN, type = CL_CLEAN;
|
||||
bool compute_hash[CLI_HASH_AVAIL_TYPES];
|
||||
|
||||
cli_hash_type_t hash_type;
|
||||
bool need_hash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||
void *hashctx[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||
unsigned char digest[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
|
||||
|
||||
unsigned int i = 0, j = 0;
|
||||
uint32_t maxpatlen, bytes, offset = 0;
|
||||
|
||||
|
@ -1056,8 +1086,6 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
struct cli_pcre_off target_pcre_offsets_table;
|
||||
bool target_pcre_offsets_table_initialized = false;
|
||||
|
||||
unsigned char digest[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
|
||||
|
||||
struct cli_matcher *generic_ac_root = NULL, *target_ac_root = NULL;
|
||||
|
||||
struct cli_target_info info;
|
||||
|
@ -1065,34 +1093,12 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
|
||||
struct cli_matcher *hdb, *fp;
|
||||
|
||||
void *md5ctx = NULL;
|
||||
void *sha1ctx = NULL;
|
||||
void *sha256ctx = NULL;
|
||||
|
||||
if (!ctx->engine) {
|
||||
cli_errmsg("cli_scan_fmap: engine == NULL\n");
|
||||
ret = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
md5ctx = cl_hash_init("md5");
|
||||
if (!(md5ctx)) {
|
||||
ret = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sha1ctx = cl_hash_init("sha1");
|
||||
if (!(sha1ctx)) {
|
||||
ret = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sha256ctx = cl_hash_init("sha256");
|
||||
if (!(sha256ctx)) {
|
||||
ret = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!filetype_only) {
|
||||
generic_ac_root = ctx->engine->root[0]; /* generic signatures */
|
||||
}
|
||||
|
@ -1245,36 +1251,35 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
matching with the AC & BM pattern matchers is an optimization so we
|
||||
we can do both processes while the cache is still hot. */
|
||||
|
||||
if (!refhash) {
|
||||
if (cli_hm_have_size(hdb, CLI_HASH_MD5, ctx->fmap->len) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_MD5, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(hdb, CLI_HASH_MD5) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_MD5)) {
|
||||
compute_hash[CLI_HASH_MD5] = true;
|
||||
} else {
|
||||
compute_hash[CLI_HASH_MD5] = false;
|
||||
need_hash[CLI_HASH_MD5] = cli_hm_have_size(hdb, CLI_HASH_MD5, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(hdb, CLI_HASH_MD5) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_MD5, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_MD5);
|
||||
|
||||
need_hash[CLI_HASH_SHA1] = cli_hm_have_size(hdb, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(hdb, CLI_HASH_SHA1) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_SHA1);
|
||||
|
||||
need_hash[CLI_HASH_SHA2_256] = cli_hm_have_size(hdb, CLI_HASH_SHA2_256, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(hdb, CLI_HASH_SHA2_256) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_SHA2_256, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_SHA2_256);
|
||||
|
||||
/*
|
||||
* Initialize hash contexts for the hashes that we need to compute.
|
||||
*/
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (need_hash[hash_type] && !ctx->fmap->have_hash[hash_type]) {
|
||||
const char *hash_name = cli_hash_name(hash_type);
|
||||
|
||||
hashctx[hash_type] = cl_hash_init(hash_name);
|
||||
if (NULL == hashctx[hash_type]) {
|
||||
cli_errmsg("cli_scan_fmap: Error initializing %s hash context\n", hash_name);
|
||||
ret = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compute_hash[CLI_HASH_MD5] = 0;
|
||||
memcpy(digest[CLI_HASH_MD5], refhash, 16);
|
||||
}
|
||||
|
||||
if (cli_hm_have_size(hdb, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(hdb, CLI_HASH_SHA1) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_SHA1)) {
|
||||
compute_hash[CLI_HASH_SHA1] = true;
|
||||
} else {
|
||||
compute_hash[CLI_HASH_SHA1] = false;
|
||||
}
|
||||
|
||||
if (cli_hm_have_size(hdb, CLI_HASH_SHA256, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(hdb, CLI_HASH_SHA256) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_SHA256, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
|
||||
compute_hash[CLI_HASH_SHA256] = true;
|
||||
} else {
|
||||
compute_hash[CLI_HASH_SHA256] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1289,7 +1294,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
if (!(buff = fmap_need_off_once(ctx->fmap, offset, bytes)))
|
||||
break;
|
||||
if (ctx->scanned)
|
||||
*ctx->scanned += bytes / CL_COUNT_PRECISION;
|
||||
*ctx->scanned += bytes;
|
||||
|
||||
if (target_ac_root) {
|
||||
const char *virname = NULL;
|
||||
|
@ -1323,12 +1328,19 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
const void *data = buff + maxpatlen * (offset != 0);
|
||||
uint32_t data_len = bytes - maxpatlen * (offset != 0);
|
||||
|
||||
if (compute_hash[CLI_HASH_MD5])
|
||||
cl_update_hash(md5ctx, (void *)data, data_len);
|
||||
if (compute_hash[CLI_HASH_SHA1])
|
||||
cl_update_hash(sha1ctx, (void *)data, data_len);
|
||||
if (compute_hash[CLI_HASH_SHA256])
|
||||
cl_update_hash(sha256ctx, (void *)data, data_len);
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
/*
|
||||
* Compute the hash for the current data chunk, if we need to.
|
||||
*/
|
||||
if (need_hash[hash_type] && !ctx->fmap->have_hash[hash_type]) {
|
||||
if (cl_update_hash(hashctx[hash_type], data, data_len)) {
|
||||
const char *hash_name = cli_hash_name(hash_type);
|
||||
cli_errmsg("cli_scan_fmap: Error calculating %s hash!\n", hash_name);
|
||||
ret = CL_EREAD;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1341,47 +1353,40 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
if (!filetype_only && hdb) {
|
||||
/* We're not just doing file typing, we're scanning for malware.
|
||||
So we need to check the hash sigs, if there are any. */
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
/*
|
||||
* Compute the hash for the current data chunk, if we need to.
|
||||
*/
|
||||
if (need_hash[hash_type] && !ctx->fmap->have_hash[hash_type]) {
|
||||
cl_finish_hash(hashctx[hash_type], digest[hash_type]);
|
||||
hashctx[hash_type] = NULL;
|
||||
|
||||
cli_hash_type_t hashtype;
|
||||
|
||||
if (compute_hash[CLI_HASH_MD5]) {
|
||||
cl_finish_hash(md5ctx, digest[CLI_HASH_MD5]);
|
||||
md5ctx = NULL;
|
||||
|
||||
// Save the MD5 hash for later use (e.g. in FP checks).
|
||||
fmap_set_hash(ctx->fmap, digest[CLI_HASH_MD5], CLI_HASH_MD5);
|
||||
}
|
||||
if (refhash) {
|
||||
// Set "compute_hash" to 1 because we'll use this later to know if we have a hash to check.
|
||||
compute_hash[CLI_HASH_MD5] = 1;
|
||||
fmap_set_hash(ctx->fmap, digest[hash_type], hash_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (compute_hash[CLI_HASH_SHA1]) {
|
||||
cl_finish_hash(sha1ctx, digest[CLI_HASH_SHA1]);
|
||||
sha1ctx = NULL;
|
||||
|
||||
// Save the SHA1 hash for later use (e.g. in FP checks).
|
||||
fmap_set_hash(ctx->fmap, digest[CLI_HASH_SHA1], CLI_HASH_SHA1);
|
||||
}
|
||||
if (compute_hash[CLI_HASH_SHA256]) {
|
||||
cl_finish_hash(sha256ctx, digest[CLI_HASH_SHA256]);
|
||||
sha256ctx = NULL;
|
||||
|
||||
// Save the SHA256 hash for later use (e.g. in FP checks).
|
||||
fmap_set_hash(ctx->fmap, digest[CLI_HASH_SHA256], CLI_HASH_SHA256);
|
||||
}
|
||||
|
||||
for (hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
const char *virname = NULL;
|
||||
const char *virname_w = NULL;
|
||||
uint8_t *hash = NULL;
|
||||
|
||||
/* If no hash, skip to next type */
|
||||
if (!compute_hash[hashtype]) {
|
||||
if (!need_hash[hash_type]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do hash scan checking hash sigs with specific size */
|
||||
ret = cli_hm_scan(digest[hashtype], ctx->fmap->len, &virname, hdb, hashtype);
|
||||
/* Get the hash for the current type.
|
||||
* We already calculated all the needed ones, so this is a simple lookup.
|
||||
* Yes, I know there is the digest[] array, but that one may be hashes calculated before this function. */
|
||||
ret = fmap_get_hash(ctx->fmap, &hash, hash_type);
|
||||
if (CL_SUCCESS != ret) {
|
||||
cli_dbgmsg("cli_scan_fmap: Error getting hash for type %d\n", hash_type);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Do hash scan checking hash sigs with specific size.
|
||||
* This part is fast, so we aren't checking if there are any of hash sigs for this type of hash at this file size */
|
||||
ret = cli_hm_scan(hash, ctx->fmap->len, &virname, hdb, hash_type);
|
||||
if (ret == CL_VIRUS) {
|
||||
/* Matched with size-based hash ... */
|
||||
ret = cli_append_virus(ctx, virname);
|
||||
|
@ -1390,8 +1395,9 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
}
|
||||
}
|
||||
|
||||
/* Do hash scan checking hash sigs with wildcard size */
|
||||
ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype);
|
||||
/* Do hash scan checking hash sigs with wildcard size.
|
||||
* This part is fast, so we aren't checking if there are any hash sigs for this type of hash with wildcard size */
|
||||
ret = cli_hm_scan_wild(hash, &virname_w, hdb, hash_type);
|
||||
if (ret == CL_VIRUS) {
|
||||
/* Matched with size-agnostic hash ... */
|
||||
ret = cli_append_virus(ctx, virname_w);
|
||||
|
@ -1408,26 +1414,22 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
// Evaluate for the target-specific signature AC matches.
|
||||
if (NULL != target_ac_root) {
|
||||
if (ret != CL_VIRUS) {
|
||||
ret = cli_exp_eval(ctx, target_ac_root, &target_ac_data, &info, (const char *)refhash);
|
||||
ret = cli_exp_eval(ctx, target_ac_root, &target_ac_data, &info);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate for the generic signature AC matches.
|
||||
if (NULL != generic_ac_root) {
|
||||
if (ret != CL_VIRUS) {
|
||||
ret = cli_exp_eval(ctx, generic_ac_root, &generic_ac_data, &info, (const char *)refhash);
|
||||
ret = cli_exp_eval(ctx, generic_ac_root, &generic_ac_data, &info);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (NULL != md5ctx) {
|
||||
cl_hash_destroy(md5ctx);
|
||||
}
|
||||
if (NULL != sha1ctx) {
|
||||
cl_hash_destroy(sha1ctx);
|
||||
}
|
||||
if (NULL != sha256ctx) {
|
||||
cl_hash_destroy(sha256ctx);
|
||||
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||
if (NULL != hashctx[hash_type]) {
|
||||
cl_hash_destroy(hashctx[hash_type]);
|
||||
}
|
||||
}
|
||||
|
||||
if (gdata_initialized) {
|
||||
|
|
|
@ -322,7 +322,7 @@ cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t
|
|||
* @param attributes Layer attributes for the thing to be scanned.
|
||||
* @return cl_error_t
|
||||
*/
|
||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, uint32_t attributes);
|
||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, const char *path, uint32_t attributes);
|
||||
|
||||
/**
|
||||
* @brief Non-magic scan matching of the current fmap in the scan context. Newer API.
|
||||
|
@ -343,10 +343,9 @@ cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype
|
|||
* @param[out] ftoffset (optional) A list of file type signature matches with their corresponding offsets. If provided, will output the file type signature matches.
|
||||
* @param acmode Use AC_SCAN_VIR and AC_SCAN_FT to set scanning modes.
|
||||
* @param[out] acres A list of cli_ac_result AC pattern matching results.
|
||||
* @param refhash MD5 hash of the current file, used to save time creating hashes and to limit scan recursion for the HandlerType logical signature FTM feature.
|
||||
* @return cl_error_t
|
||||
*/
|
||||
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash);
|
||||
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres);
|
||||
|
||||
/**
|
||||
* @brief Evaluate logical signatures and yara rules given the AC matching results
|
||||
|
@ -359,12 +358,12 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
|||
* @param hash Reference hash of the current file, used to limit recursion for the HandlerType logical signature FTM feature.
|
||||
* @return cl_error_t
|
||||
*/
|
||||
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash);
|
||||
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info);
|
||||
|
||||
cl_error_t cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
|
||||
|
||||
/**
|
||||
* @brief Determine if an alert is a known false positive, using each fmap in the ctx->container stack to check MD5, SHA1, and SHA256 hashes.
|
||||
* @brief Determine if an alert is a known false positive, using each fmap in the ctx->container stack to check MD5, SHA1, and SHA2-256 hashes.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param vname (Optional) The name of the signature alert.
|
||||
|
|
|
@ -381,7 +381,7 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
|
|||
mctx.subtypeTable = subtype;
|
||||
mctx.ctx = ctx;
|
||||
mctx.files = 0;
|
||||
mctx.wrkobj = ctx->wrkproperty;
|
||||
mctx.wrkobj = ctx->this_layer_metadata_json;
|
||||
|
||||
/*
|
||||
* Is it a UNIX style mbox with more than one
|
||||
|
@ -1457,8 +1457,8 @@ static cl_error_t parseMHTMLComment(const char *comment, cli_ctx *ctx, void *wrk
|
|||
if (!reader) {
|
||||
cli_dbgmsg("parseMHTMLComment: cannot initialize xmlReader\n");
|
||||
|
||||
if (ctx->wrkproperty != NULL)
|
||||
ret = cli_json_parse_error(ctx->wrkproperty, "MHTML_ERROR_XML_READER_MEM");
|
||||
if (ctx->this_layer_metadata_json != NULL)
|
||||
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "MHTML_ERROR_XML_READER_MEM");
|
||||
|
||||
return ret; // libxml2 failed!
|
||||
}
|
||||
|
@ -1515,8 +1515,8 @@ parseRootMHTML(mbox_ctx *mctx, message *m, text *t)
|
|||
if (htmlDoc == NULL) {
|
||||
cli_dbgmsg("parseRootMHTML: cannot initialize read html document\n");
|
||||
|
||||
if (ctx->wrkproperty != NULL)
|
||||
ret = cli_json_parse_error(ctx->wrkproperty, "MHTML_ERROR_HTML_READ");
|
||||
if (ctx->this_layer_metadata_json != NULL)
|
||||
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "MHTML_ERROR_HTML_READ");
|
||||
if (ret != CL_SUCCESS)
|
||||
rc = FAIL;
|
||||
|
||||
|
@ -1537,8 +1537,8 @@ parseRootMHTML(mbox_ctx *mctx, message *m, text *t)
|
|||
if (reader == NULL) {
|
||||
cli_dbgmsg("parseRootMHTML: cannot initialize xmlTextReader\n");
|
||||
|
||||
if (ctx->wrkproperty != NULL)
|
||||
ret = cli_json_parse_error(ctx->wrkproperty, "MHTML_ERROR_XML_READER_IO");
|
||||
if (ctx->this_layer_metadata_json != NULL)
|
||||
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "MHTML_ERROR_XML_READER_IO");
|
||||
if (ret != CL_SUCCESS)
|
||||
rc = FAIL;
|
||||
|
||||
|
@ -2262,7 +2262,7 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re
|
|||
cli_dbgmsg("No HTML code found to be scanned\n");
|
||||
} else {
|
||||
/* Send root HTML file for preclassification */
|
||||
if (mctx->ctx->wrkproperty)
|
||||
if (mctx->ctx->this_layer_metadata_json)
|
||||
(void)parseRootMHTML(mctx, messages[htmltextPart], aText);
|
||||
|
||||
rc = parseEmailBody(messages[htmltextPart], aText, mctx, recursion_level + 1);
|
||||
|
@ -3831,7 +3831,7 @@ getHrefs(cli_ctx *ctx, message *m, tag_arguments_t *hrefs)
|
|||
|
||||
/* TODO: make this size customisable */
|
||||
if (len > 100 * 1024) {
|
||||
cli_dbgmsg("Viruses pointed to by URLs not scanned in large message\n");
|
||||
cli_dbgmsg("HTML pointed to by URLs not scanned in large message\n");
|
||||
blobDestroy(b);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4448,7 +4448,7 @@ do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, m
|
|||
|
||||
if (thisobj != NULL) {
|
||||
/* attempt to determine container size - prevents incorrect type reporting */
|
||||
if (json_object_object_get_ex(mctx->ctx->wrkproperty, "ContainedObjects", &arrobj)) {
|
||||
if (json_object_object_get_ex(mctx->ctx->this_layer_metadata_json, "ContainedObjects", &arrobj)) {
|
||||
arrlen = json_object_array_length(arrobj);
|
||||
}
|
||||
}
|
||||
|
@ -4469,7 +4469,7 @@ do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, m
|
|||
const char *dtype = NULL;
|
||||
|
||||
/* attempt to acquire container type */
|
||||
if (json_object_object_get_ex(mctx->ctx->wrkproperty, "ContainedObjects", &arrobj)) {
|
||||
if (json_object_object_get_ex(mctx->ctx->this_layer_metadata_json, "ContainedObjects", &arrobj)) {
|
||||
if (json_object_array_length(arrobj) > arrlen) {
|
||||
entry = json_object_array_get_idx(arrobj, arrlen);
|
||||
}
|
||||
|
|
|
@ -279,7 +279,6 @@ static cl_error_t mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extl
|
|||
/* EBR checks */
|
||||
status = mbr_check_ebr(&ebr);
|
||||
if (status != CL_SUCCESS) {
|
||||
status = status;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -379,7 +378,6 @@ static cl_error_t mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extl
|
|||
|
||||
status = cli_magic_scan_nested_fmap_type(ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL, LAYER_ATTRIBUTES_NONE);
|
||||
if (status != CL_SUCCESS) {
|
||||
status = status;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -813,7 +813,7 @@ static int cli_ole2_summary_json_cleanup(summary_ctx_t *sctx, int retcode)
|
|||
cli_dbgmsg("in cli_ole2_summary_json_cleanup: %d[%x]\n", retcode, sctx->flags);
|
||||
|
||||
if (sctx->sfmap) {
|
||||
funmap(sctx->sfmap);
|
||||
fmap_free(sctx->sfmap);
|
||||
}
|
||||
|
||||
if (sctx->flags) {
|
||||
|
@ -872,7 +872,7 @@ static int cli_ole2_summary_json_cleanup(summary_ctx_t *sctx, int retcode)
|
|||
return retcode;
|
||||
}
|
||||
|
||||
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
||||
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode, const char *filepath)
|
||||
{
|
||||
summary_ctx_t sctx;
|
||||
STATBUF statbuf;
|
||||
|
@ -909,7 +909,7 @@ int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
|||
return CL_ESTAT;
|
||||
}
|
||||
|
||||
sctx.sfmap = fmap(fd, 0, statbuf.st_size, NULL);
|
||||
sctx.sfmap = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||
if (!sctx.sfmap) {
|
||||
cli_dbgmsg("ole2_summary_json: failed to get fmap\n");
|
||||
return CL_EMAP;
|
||||
|
@ -919,14 +919,14 @@ int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
|||
|
||||
switch (mode) {
|
||||
case 1:
|
||||
sctx.summary = cli_jsonobj(ctx->wrkproperty, "DocSummaryInfo");
|
||||
sctx.summary = cli_jsonobj(ctx->this_layer_metadata_json, "DocSummaryInfo");
|
||||
break;
|
||||
case 2:
|
||||
sctx.summary = cli_jsonobj(ctx->wrkproperty, "Hwp5SummaryInfo");
|
||||
sctx.summary = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp5SummaryInfo");
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
sctx.summary = cli_jsonobj(ctx->wrkproperty, "SummaryInfo");
|
||||
sctx.summary = cli_jsonobj(ctx->this_layer_metadata_json, "SummaryInfo");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -991,7 +991,7 @@ int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
|||
|
||||
/* second property set (index=1) is always a custom property set (if present) */
|
||||
if (sumstub.num_propsets == 2) {
|
||||
cli_jsonbool(ctx->wrkproperty, "HasUserDefinedProperties", 1);
|
||||
cli_jsonbool(ctx->this_layer_metadata_json, "HasUserDefinedProperties", 1);
|
||||
}
|
||||
|
||||
return cli_ole2_summary_json_cleanup(&sctx, CL_SUCCESS);
|
||||
|
|
|
@ -166,6 +166,6 @@ typedef struct summary_ctx {
|
|||
} summary_ctx_t;
|
||||
|
||||
/* Summary and Document Information Parsing to JSON */
|
||||
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode);
|
||||
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode, const char *filepath);
|
||||
|
||||
#endif /* __MSDOC_H_ */
|
||||
|
|
|
@ -241,7 +241,7 @@ cl_error_t cli_scanmsxml(cli_ctx *ctx)
|
|||
if (!reader) {
|
||||
cli_dbgmsg("cli_scanmsxml: cannot initialize xmlReader\n");
|
||||
|
||||
ret = cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_IO");
|
||||
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_XML_READER_IO");
|
||||
|
||||
return ret; // libxml2 failed!
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@ static cl_error_t msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr
|
|||
|
||||
cli_msxmlmsg("BINARY CALLBACK DATA!\n");
|
||||
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
||||
cli_warnmsg("msxml_parse_element: failed to create temporary file %s\n", tempfile);
|
||||
return ret;
|
||||
}
|
||||
|
@ -426,7 +426,7 @@ static cl_error_t msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr
|
|||
break;
|
||||
}
|
||||
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
||||
cli_warnmsg("msxml_parse_element: failed to create temporary file %s\n", tempfile);
|
||||
free(decoded);
|
||||
return ret;
|
||||
|
@ -554,7 +554,7 @@ cl_error_t cli_msxml_parse_document(cli_ctx *ctx, xmlTextReaderPtr reader, const
|
|||
ictx.num_keys = num_keys;
|
||||
|
||||
if (flags & MSXML_FLAG_JSON) {
|
||||
ictx.root = ctx->wrkproperty;
|
||||
ictx.root = ctx->this_layer_metadata_json;
|
||||
/* JSON Sanity Check */
|
||||
if (!ictx.root)
|
||||
ictx.flags &= ~MSXML_FLAG_JSON;
|
||||
|
|
|
@ -521,7 +521,7 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset)
|
|||
memset(&nsist, 0, sizeof(struct nsis_st));
|
||||
|
||||
nsist.off = offset;
|
||||
if (!(nsist.dir = cli_gentemp_with_prefix(ctx->sub_tmpdir, "nulsft-tmp")))
|
||||
if (!(nsist.dir = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "nulsft-tmp")))
|
||||
return CL_ETMPDIR;
|
||||
if (mkdir(nsist.dir, 0700)) {
|
||||
cli_dbgmsg("NSIS: Can't create temporary directory %s\n", nsist.dir);
|
||||
|
@ -539,18 +539,31 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset)
|
|||
continue;
|
||||
}
|
||||
if (ret == CL_SUCCESS) {
|
||||
char *name = NULL;
|
||||
cli_dbgmsg("NSIS: Successfully extracted file #%u\n", nsist.fno);
|
||||
if (lseek(nsist.ofd, 0, SEEK_SET) == -1) {
|
||||
cli_dbgmsg("NSIS: call to lseek() failed\n");
|
||||
free(nsist.dir);
|
||||
return CL_ESEEK;
|
||||
}
|
||||
if (nsist.fno == 1) {
|
||||
ret = cli_scan_desc(nsist.ofd, ctx, CL_TYPE_ANY, false, NULL, AC_SCAN_VIR, NULL, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
||||
} else {
|
||||
ret = cli_magic_scan_desc(nsist.ofd, nsist.ofn, ctx, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
||||
|
||||
// Get basename of the file from nsist.ofn
|
||||
ret = cli_basename(nsist.ofn, strlen(nsist.ofn), &name, true /* posix_support_backslash_pathsep */);
|
||||
if (CL_SUCCESS != ret || NULL == name) {
|
||||
cli_dbgmsg("NSIS: Failed to get basename of the file\n");
|
||||
// If it fails, the name will just be NULL. That's okay.
|
||||
}
|
||||
|
||||
if (nsist.fno == 1) {
|
||||
ret = cli_scan_desc(nsist.ofd, ctx, CL_TYPE_ANY, false, NULL, AC_SCAN_VIR, NULL, name, nsist.ofn, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
||||
} else {
|
||||
ret = cli_magic_scan_desc(nsist.ofd, nsist.ofn, ctx, name, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
||||
}
|
||||
|
||||
CLI_FREE_AND_SET_NULL(name);
|
||||
|
||||
close(nsist.ofd);
|
||||
|
||||
if (!ctx->engine->keeptmp) {
|
||||
if (cli_unlink(nsist.ofn)) {
|
||||
ret = CL_EUNLINK;
|
||||
|
|
|
@ -1065,12 +1065,12 @@ static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t
|
|||
case 1: /* Directory */
|
||||
ole2_listmsg("directory node\n");
|
||||
if (dir) {
|
||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
||||
if (!json_object_object_get_ex(ctx->wrkproperty, "DigitalSignatures", NULL)) {
|
||||
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||
if (!json_object_object_get_ex(ctx->this_layer_metadata_json, "DigitalSignatures", NULL)) {
|
||||
name = cli_ole2_get_property_name2(prop_block[idx].name, prop_block[idx].name_size);
|
||||
if (name) {
|
||||
if (!strcmp(name, "_xmlsignatures") || !strcmp(name, "_signatures")) {
|
||||
cli_jsonbool(ctx->wrkproperty, "HasDigitalSignatures", 1);
|
||||
cli_jsonbool(ctx->this_layer_metadata_json, "HasDigitalSignatures", 1);
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
|
@ -1352,8 +1352,8 @@ static cl_error_t scan_biff_for_xlm_macros_and_images(
|
|||
state->tmp = buff[i] & 0x20;
|
||||
} else if ((state->data_offset == 14 || state->data_offset == 15) && state->tmp) {
|
||||
if (buff[i] == 1 || buff[i] == 2) {
|
||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
||||
json_object *indicators = cli_jsonarray(ctx->wrkproperty, "MacroIndicators");
|
||||
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||
json_object *indicators = cli_jsonarray(ctx->this_layer_metadata_json, "MacroIndicators");
|
||||
if (indicators) {
|
||||
cli_jsonstr(indicators, NULL, "autorun");
|
||||
} else {
|
||||
|
@ -1373,16 +1373,16 @@ static cl_error_t scan_biff_for_xlm_macros_and_images(
|
|||
} else if (state->data_offset == 5 && buff[i] == 1) { // Excel 4.0 macro sheet
|
||||
cli_dbgmsg("[scan_biff_for_xlm_macros_and_images] Found XLM macro sheet\n");
|
||||
|
||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
||||
cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
|
||||
json_object *macro_languages = cli_jsonarray(ctx->wrkproperty, "MacroLanguages");
|
||||
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||
cli_jsonbool(ctx->this_layer_metadata_json, "HasMacros", 1);
|
||||
json_object *macro_languages = cli_jsonarray(ctx->this_layer_metadata_json, "MacroLanguages");
|
||||
if (macro_languages) {
|
||||
cli_jsonstr(macro_languages, NULL, "XLM");
|
||||
} else {
|
||||
cli_dbgmsg("[scan_biff_for_xlm_macros_and_images] Failed to add \"XLM\" entry to MacroLanguages JSON array\n");
|
||||
}
|
||||
if (state->tmp == 1 || state->tmp == 2) {
|
||||
json_object *indicators = cli_jsonarray(ctx->wrkproperty, "MacroIndicators");
|
||||
json_object *indicators = cli_jsonarray(ctx->this_layer_metadata_json, "MacroIndicators");
|
||||
if (indicators) {
|
||||
cli_jsonstr(indicators, NULL, "hidden");
|
||||
} else {
|
||||
|
@ -1537,8 +1537,8 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
|||
|
||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||
if (name) {
|
||||
if (SCAN_COLLECT_METADATA && ctx->wrkproperty != NULL) {
|
||||
arrobj = cli_jsonarray(ctx->wrkproperty, "Streams");
|
||||
if (SCAN_COLLECT_METADATA && ctx->this_layer_metadata_json != NULL) {
|
||||
arrobj = cli_jsonarray(ctx->this_layer_metadata_json, "Streams");
|
||||
if (NULL == arrobj) {
|
||||
cli_warnmsg("ole2: no memory for streams list or streams is not an array\n");
|
||||
} else {
|
||||
|
@ -1547,13 +1547,13 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
|||
}
|
||||
|
||||
if (!strcmp(name, "powerpoint document")) {
|
||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_MSPPT");
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_MSPPT");
|
||||
}
|
||||
if (!strcmp(name, "worddocument")) {
|
||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_MSWORD");
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_MSWORD");
|
||||
}
|
||||
if (!strcmp(name, "workbook")) {
|
||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_MSXL");
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_MSXL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1609,7 +1609,7 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
|||
if (!memcmp(hwp_check + offset, "HWP Document File", 17)) {
|
||||
hwp5_header_t *hwp_new;
|
||||
|
||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_HWP5");
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_HWP5");
|
||||
|
||||
CLI_CALLOC_OR_GOTO_DONE(hwp_new, 1, sizeof(hwp5_header_t), status = CL_EMEM);
|
||||
|
||||
|
@ -1680,7 +1680,7 @@ likely_mso_stream(int fd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx)
|
||||
static cl_error_t scan_mso_stream(int fd, const char *filepath, cli_ctx *ctx)
|
||||
{
|
||||
int zret, ofd;
|
||||
cl_error_t ret = CL_SUCCESS;
|
||||
|
@ -1704,7 +1704,7 @@ static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx)
|
|||
return CL_ESTAT;
|
||||
}
|
||||
|
||||
input = fmap(fd, 0, statbuf.st_size, NULL);
|
||||
input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||
if (!input) {
|
||||
cli_dbgmsg("scan_mso_stream: Failed to get fmap for input stream\n");
|
||||
return CL_EMAP;
|
||||
|
@ -1712,9 +1712,9 @@ static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx)
|
|||
}
|
||||
|
||||
/* reserve tempfile for output and scanning */
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
||||
cli_errmsg("scan_mso_stream: Can't generate temporary file\n");
|
||||
funmap(input);
|
||||
fmap_free(input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1815,7 +1815,7 @@ mso_end:
|
|||
if (cli_unlink(tmpname))
|
||||
ret = CL_EUNLINK;
|
||||
free(tmpname);
|
||||
funmap(input);
|
||||
fmap_free(input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1841,7 +1841,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
|||
}
|
||||
print_ole2_property(prop);
|
||||
|
||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
||||
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||
ret = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
@ -1927,7 +1927,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
|||
}
|
||||
|
||||
/* JSON Output Summary Information */
|
||||
if (SCAN_COLLECT_METADATA && (ctx->properties != NULL)) {
|
||||
if (SCAN_COLLECT_METADATA && (ctx->metadata_json != NULL)) {
|
||||
if (!name) {
|
||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||
}
|
||||
|
@ -1935,7 +1935,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
|||
if (!strncmp(name, "_5_summaryinformation", 21)) {
|
||||
cli_dbgmsg("OLE2: detected a '_5_summaryinformation' stream\n");
|
||||
/* JSONOLE2 - what to do if something breaks? */
|
||||
if (cli_ole2_summary_json(ctx, ofd, 0) == CL_ETIMEOUT) {
|
||||
if (cli_ole2_summary_json(ctx, ofd, 0, tempfile) == CL_ETIMEOUT) {
|
||||
ret = CL_ETIMEOUT;
|
||||
goto done;
|
||||
}
|
||||
|
@ -1944,7 +1944,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
|||
if (!strncmp(name, "_5_documentsummaryinformation", 29)) {
|
||||
cli_dbgmsg("OLE2: detected a '_5_documentsummaryinformation' stream\n");
|
||||
/* JSONOLE2 - what to do if something breaks? */
|
||||
if (cli_ole2_summary_json(ctx, ofd, 1) == CL_ETIMEOUT) {
|
||||
if (cli_ole2_summary_json(ctx, ofd, 1, tempfile) == CL_ETIMEOUT) {
|
||||
ret = CL_ETIMEOUT;
|
||||
goto done;
|
||||
}
|
||||
|
@ -1961,7 +1961,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
|||
ret = CL_ESEEK;
|
||||
} else if (is_mso) {
|
||||
/* MSO Stream Scan */
|
||||
ret = scan_mso_stream(ofd, ctx);
|
||||
ret = scan_mso_stream(ofd, tempfile, ctx);
|
||||
} else {
|
||||
/* Normal File Scan */
|
||||
ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||
|
@ -2045,7 +2045,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
|||
|
||||
nrounds = rijndaelSetupDecrypt(rk, key->key, key->key_length_bits);
|
||||
|
||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
||||
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||
ret = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
@ -2167,7 +2167,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
|||
}
|
||||
|
||||
/* JSON Output Summary Information */
|
||||
if (SCAN_COLLECT_METADATA && (ctx->properties != NULL)) {
|
||||
if (SCAN_COLLECT_METADATA && (ctx->metadata_json != NULL)) {
|
||||
if (!name) {
|
||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||
}
|
||||
|
@ -2175,7 +2175,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
|||
if (!strncmp(name, "_5_summaryinformation", 21)) {
|
||||
cli_dbgmsg("OLE2: detected a '_5_summaryinformation' stream\n");
|
||||
/* JSONOLE2 - what to do if something breaks? */
|
||||
if (cli_ole2_summary_json(ctx, ofd, 0) == CL_ETIMEOUT) {
|
||||
if (cli_ole2_summary_json(ctx, ofd, 0, tempfile) == CL_ETIMEOUT) {
|
||||
ret = CL_ETIMEOUT;
|
||||
goto done;
|
||||
}
|
||||
|
@ -2184,7 +2184,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
|||
if (!strncmp(name, "_5_documentsummaryinformation", 29)) {
|
||||
cli_dbgmsg("OLE2: detected a '_5_documentsummaryinformation' stream\n");
|
||||
/* JSONOLE2 - what to do if something breaks? */
|
||||
if (cli_ole2_summary_json(ctx, ofd, 1) == CL_ETIMEOUT) {
|
||||
if (cli_ole2_summary_json(ctx, ofd, 1, tempfile) == CL_ETIMEOUT) {
|
||||
ret = CL_ETIMEOUT;
|
||||
goto done;
|
||||
}
|
||||
|
@ -2201,7 +2201,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
|||
ret = CL_ESEEK;
|
||||
} else if (is_mso) {
|
||||
/* MSO Stream Scan */
|
||||
ret = scan_mso_stream(ofd, ctx);
|
||||
ret = scan_mso_stream(ofd, tempfile, ctx);
|
||||
} else {
|
||||
/* Normal File Scan */
|
||||
ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||
|
@ -2939,12 +2939,12 @@ cl_error_t cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **fil
|
|||
}
|
||||
}
|
||||
|
||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
||||
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||
if (encryption_status.encrypted) {
|
||||
if (encryption_status.encryption_type) {
|
||||
cli_jsonstr(ctx->wrkproperty, ENCRYPTED_JSON_KEY, encryption_status.encryption_type);
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, ENCRYPTED_JSON_KEY, encryption_status.encryption_type);
|
||||
} else {
|
||||
cli_jsonstr(ctx->wrkproperty, ENCRYPTED_JSON_KEY, GENERIC_ENCRYPTED);
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, ENCRYPTED_JSON_KEY, GENERIC_ENCRYPTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,9 +151,9 @@ static cl_error_t ooxml_core_cb(int fd, const char *filepath, cli_ctx *ctx, cons
|
|||
cli_dbgmsg("in ooxml_core_cb\n");
|
||||
ret = ooxml_parse_document(fd, ctx);
|
||||
if (ret == CL_EPARSE)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_CORE_XMLPARSER");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_CORE_XMLPARSER");
|
||||
else if (ret == CL_EFORMAT)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_CORE_MALFORMED");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_CORE_MALFORMED");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -169,9 +169,9 @@ static cl_error_t ooxml_extn_cb(int fd, const char *filepath, cli_ctx *ctx, cons
|
|||
cli_dbgmsg("in ooxml_extn_cb\n");
|
||||
ret = ooxml_parse_document(fd, ctx);
|
||||
if (ret == CL_EPARSE)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_EXTN_XMLPARSER");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_EXTN_XMLPARSER");
|
||||
else if (ret == CL_EFORMAT)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_EXTN_MALFORMED");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_EXTN_MALFORMED");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, c
|
|||
cli_dbgmsg("ooxml_content_cb: xmlReaderForFd error for "
|
||||
"[Content_Types].xml"
|
||||
"\n");
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_FD");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_XML_READER_FD");
|
||||
|
||||
ctx->scansize = sav_scansize;
|
||||
ctx->scannedfiles = sav_scannedfiles;
|
||||
|
@ -303,40 +303,40 @@ static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, c
|
|||
|
||||
ooxml_content_exit:
|
||||
if (core) {
|
||||
cli_jsonint(ctx->wrkproperty, "CorePropertiesFileCount", core);
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "CorePropertiesFileCount", core);
|
||||
if (core > 1)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES");
|
||||
} else if (!mcore)
|
||||
cli_dbgmsg("cli_process_ooxml: file does not contain core properties file\n");
|
||||
if (mcore) {
|
||||
cli_jsonint(ctx->wrkproperty, "CorePropertiesMissingFileCount", mcore);
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CORE_PROPFILES");
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "CorePropertiesMissingFileCount", mcore);
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MISSING_CORE_PROPFILES");
|
||||
}
|
||||
|
||||
if (extn) {
|
||||
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesFileCount", extn);
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "ExtendedPropertiesFileCount", extn);
|
||||
if (extn > 1)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES");
|
||||
} else if (!mextn)
|
||||
cli_dbgmsg("cli_process_ooxml: file does not contain extended properties file\n");
|
||||
if (mextn) {
|
||||
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesMissingFileCount", mextn);
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_EXTN_PROPFILES");
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "ExtendedPropertiesMissingFileCount", mextn);
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MISSING_EXTN_PROPFILES");
|
||||
}
|
||||
|
||||
if (cust) {
|
||||
cli_jsonint(ctx->wrkproperty, "CustomPropertiesFileCount", cust);
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "CustomPropertiesFileCount", cust);
|
||||
if (cust > 1)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES");
|
||||
} else if (!mcust)
|
||||
cli_dbgmsg("cli_process_ooxml: file does not contain custom properties file\n");
|
||||
if (mcust) {
|
||||
cli_jsonint(ctx->wrkproperty, "CustomPropertiesMissingFileCount", mcust);
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CUST_PROPFILES");
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "CustomPropertiesMissingFileCount", mcust);
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MISSING_CUST_PROPFILES");
|
||||
}
|
||||
|
||||
if (dsig) {
|
||||
cli_jsonint(ctx->wrkproperty, "DigitalSignaturesCount", dsig);
|
||||
cli_jsonint(ctx->this_layer_metadata_json, "DigitalSignaturesCount", dsig);
|
||||
}
|
||||
|
||||
/* restore the engine tracking limits; resets session limit tracking */
|
||||
|
@ -437,7 +437,7 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||
"version.xml"
|
||||
"!\n");
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_HWP_VERSION");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_NO_HWP_VERSION");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
ret = unzip_single_internal(ctx, loff, ooxml_hwp_cb);
|
||||
|
@ -450,7 +450,7 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||
"Contents/content.hpf"
|
||||
"!\n");
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_HWP_CONTENT");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_NO_HWP_CONTENT");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
ret = unzip_single_internal(ctx, loff, ooxml_hwp_cb);
|
||||
|
@ -464,7 +464,7 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||
"[Content_Types].xml"
|
||||
"!\n");
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_CONTENT_TYPES");
|
||||
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_NO_CONTENT_TYPES");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
cli_dbgmsg("cli_process_ooxml: found "
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <libxml/xmlreader.h>
|
||||
|
||||
struct openioc_hash {
|
||||
unsigned char *hash;
|
||||
uint8_t *hash;
|
||||
void *next;
|
||||
};
|
||||
|
||||
|
@ -311,7 +311,7 @@ int openioc_parse(const char *fname, int fd, struct cl_engine *engine, unsigned
|
|||
|
||||
free(vp);
|
||||
|
||||
rc = hm_addhash_str(engine->hm_hdb, hash, 0, virusname);
|
||||
rc = hm_addhash_str(engine, HASH_PURPOSE_WHOLE_FILE_DETECT, hash, 0, virusname);
|
||||
if (rc != CL_SUCCESS)
|
||||
cli_dbgmsg("openioc_parse: hm_addhash_str failed with %i hash len %i for %s.\n",
|
||||
rc, hashlen, virusname);
|
||||
|
|
35
libclamav/other_types.h
Normal file
35
libclamav/other_types.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (C) 2021-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Valerie Snyder
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __OTHER_TYPES_H_LC
|
||||
#define __OTHER_TYPES_H_LC
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct image_fuzzy_hash {
|
||||
uint8_t hash[8];
|
||||
} image_fuzzy_hash_t;
|
||||
|
||||
typedef void *evidence_t;
|
||||
typedef void *onedump_t;
|
||||
typedef void *cvd_t;
|
||||
typedef void *cli_ctx_t;
|
||||
|
||||
#endif /* __OTHER_TYPES_H_LC */
|
1207
libclamav/others.c
1207
libclamav/others.c
File diff suppressed because it is too large
Load diff
|
@ -43,6 +43,7 @@
|
|||
#include <json.h>
|
||||
|
||||
#include "clamav.h"
|
||||
#include "other_types.h"
|
||||
#include "dconf.h"
|
||||
#include "filetypes.h"
|
||||
#include "fmap.h"
|
||||
|
@ -51,6 +52,7 @@
|
|||
#include "bytecode_api.h"
|
||||
#include "events.h"
|
||||
#include "crtmgr.h"
|
||||
#include "scan_layer.h"
|
||||
|
||||
#include "unrar_iface.h"
|
||||
|
||||
|
@ -171,52 +173,29 @@ typedef struct bitset_tag {
|
|||
unsigned long length;
|
||||
} bitset_t;
|
||||
|
||||
typedef struct image_fuzzy_hash {
|
||||
uint8_t hash[8];
|
||||
} image_fuzzy_hash_t;
|
||||
|
||||
typedef struct recursion_level_tag {
|
||||
cli_file_t type;
|
||||
size_t size;
|
||||
cl_fmap_t *fmap; /* The fmap for this layer. This used to be in an array in the ctx. */
|
||||
uint32_t recursion_level_buffer; /* Which buffer layer in scan recursion. */
|
||||
uint32_t recursion_level_buffer_fmap; /* Which fmap layer in this buffer. */
|
||||
uint32_t attributes; /* layer attributes. */
|
||||
image_fuzzy_hash_t image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */
|
||||
bool calculated_image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */
|
||||
} recursion_level_t;
|
||||
|
||||
typedef void *evidence_t;
|
||||
typedef void *onedump_t;
|
||||
typedef void *cvd_t;
|
||||
|
||||
/* internal clamav context */
|
||||
typedef struct cli_ctx_tag {
|
||||
char *target_filepath; /* (optional) The filepath of the original scan target. */
|
||||
const char *sub_filepath; /* (optional) The filepath of the current file being parsed. May be a temp file. */
|
||||
char *sub_tmpdir; /* The directory to store tmp files at this recursion depth. */
|
||||
evidence_t evidence; /* Stores the evidence for this scan to alert (alerting indicators). */
|
||||
unsigned long int *scanned;
|
||||
char *target_filepath; /* (optional) The filepath of the original scan target. */
|
||||
char *this_layer_tmpdir; /* Pointer to current temporary directory, MAY vary with recursion depth. For convenience. */
|
||||
uint64_t *scanned;
|
||||
const struct cli_matcher *root;
|
||||
const struct cl_engine *engine;
|
||||
uint64_t scansize;
|
||||
struct cl_scan_options *options;
|
||||
unsigned int scannedfiles;
|
||||
unsigned int corrupted_input; /* Setting this flag will prevent the PE parser from reporting "broken executable" for unpacked/reconstructed files that may not be 100% to spec. */
|
||||
recursion_level_t *recursion_stack; /* Array of recursion levels used as a stack. */
|
||||
uint32_t recursion_stack_size; /* stack size must == engine->max_recursion_level */
|
||||
uint32_t recursion_level; /* Index into recursion_stack; current fmap recursion level from start of scan. */
|
||||
fmap_t *fmap; /* Pointer to current fmap in recursion_stack, varies with recursion depth. For convenience. */
|
||||
unsigned char handlertype_hash[16];
|
||||
uint32_t scannedfiles;
|
||||
unsigned int corrupted_input; /* Setting this flag will prevent the PE parser from reporting "broken executable" for unpacked/reconstructed files that may not be 100% to spec. */
|
||||
cli_scan_layer_t *recursion_stack; /* Array of recursion levels used as a stack. */
|
||||
uint32_t recursion_stack_size; /* stack size must == engine->max_recursion_level */
|
||||
uint32_t recursion_level; /* Index into recursion_stack; current fmap recursion level from start of scan. */
|
||||
evidence_t this_layer_evidence; /* Pointer to current evidence in recursion_stack, varies with recursion depth. For convenience. */
|
||||
fmap_t *fmap; /* Pointer to current fmap in recursion_stack, varies with recursion depth. For convenience. */
|
||||
size_t object_count; /* Counter for number of unique entities/contained files (including normalized files) processed. */
|
||||
struct cli_dconf *dconf;
|
||||
bitset_t *hook_lsig_matches;
|
||||
void *cb_ctx;
|
||||
cli_events_t *perf;
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
int sha_collect;
|
||||
#endif
|
||||
struct json_object *properties;
|
||||
struct json_object *wrkproperty;
|
||||
struct json_object *metadata_json; /* Top level metadata JSON object for the whole scan. */
|
||||
struct json_object *this_layer_metadata_json; /* Pointer to current metadata JSON object in recursion_stack, varies with recursion depth. For convenience. */
|
||||
struct timeval time_limit;
|
||||
bool limit_exceeded; /* To guard against alerting on limits exceeded more than once, or storing that in the JSON metadata more than once. */
|
||||
bool abort_scan; /* So we can guarantee a scan is aborted, even if CL_ETIMEOUT/etc. status is lost in the scan recursion stack. */
|
||||
|
@ -228,7 +207,7 @@ typedef struct cli_ctx_tag {
|
|||
|
||||
typedef struct cli_flagged_sample {
|
||||
char **virus_name;
|
||||
char md5[16];
|
||||
char md5[MD5_HASH_SIZE];
|
||||
uint32_t size; /* A size of zero means size is unavailable (why would this ever happen?) */
|
||||
uint32_t hits;
|
||||
stats_section_t *sections;
|
||||
|
@ -405,8 +384,13 @@ struct cl_engine {
|
|||
crtmgr cmgr;
|
||||
|
||||
/* Callback(s) */
|
||||
clcb_file_inspection cb_file_inspection;
|
||||
clcb_scan cb_scan_pre_hash;
|
||||
clcb_scan cb_scan_pre_scan;
|
||||
clcb_scan cb_scan_post_scan;
|
||||
clcb_scan cb_scan_alert;
|
||||
clcb_scan cb_scan_file_type;
|
||||
clcb_pre_cache cb_pre_cache;
|
||||
clcb_file_inspection cb_file_inspection;
|
||||
clcb_pre_scan cb_pre_scan;
|
||||
clcb_post_scan cb_post_scan;
|
||||
clcb_virus_found cb_virus_found;
|
||||
|
@ -556,6 +540,7 @@ extern LIBCLAMAV_EXPORT int have_rar;
|
|||
#define SCAN_UNPRIVILEGED (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
|
||||
#define SCAN_STORE_HTML_URIS (ctx->options->general & CL_SCAN_GENERAL_STORE_HTML_URIS)
|
||||
#define SCAN_STORE_PDF_URIS (ctx->options->general & CL_SCAN_GENERAL_STORE_PDF_URIS)
|
||||
#define SCAN_STORE_EXTRA_HASHES (ctx->options->general & CL_SCAN_GENERAL_STORE_EXTRA_HASHES)
|
||||
|
||||
#define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
|
||||
#define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
|
||||
|
@ -586,21 +571,20 @@ extern LIBCLAMAV_EXPORT int have_rar;
|
|||
|
||||
#define SCAN_MAIL_PARTIAL_MESSAGE (ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
|
||||
|
||||
#define SCAN_DEV_COLLECT_SHA (ctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
|
||||
#define SCAN_DEV_COLLECT_PERF_INFO (ctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
|
||||
|
||||
/* based on macros from A. Melnikoff */
|
||||
#define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
|
||||
#define cbswap32(v) ((((v)&0x000000ff) << 24) | (((v)&0x0000ff00) << 8) | \
|
||||
(((v)&0x00ff0000) >> 8) | (((v)&0xff000000) >> 24))
|
||||
#define cbswap64(v) ((((v)&0x00000000000000ffULL) << 56) | \
|
||||
(((v)&0x000000000000ff00ULL) << 40) | \
|
||||
(((v)&0x0000000000ff0000ULL) << 24) | \
|
||||
(((v)&0x00000000ff000000ULL) << 8) | \
|
||||
(((v)&0x000000ff00000000ULL) >> 8) | \
|
||||
(((v)&0x0000ff0000000000ULL) >> 24) | \
|
||||
(((v)&0x00ff000000000000ULL) >> 40) | \
|
||||
(((v)&0xff00000000000000ULL) >> 56))
|
||||
#define cbswap32(v) ((((v) & 0x000000ff) << 24) | (((v) & 0x0000ff00) << 8) | \
|
||||
(((v) & 0x00ff0000) >> 8) | (((v) & 0xff000000) >> 24))
|
||||
#define cbswap64(v) ((((v) & 0x00000000000000ffULL) << 56) | \
|
||||
(((v) & 0x000000000000ff00ULL) << 40) | \
|
||||
(((v) & 0x0000000000ff0000ULL) << 24) | \
|
||||
(((v) & 0x00000000ff000000ULL) << 8) | \
|
||||
(((v) & 0x000000ff00000000ULL) >> 8) | \
|
||||
(((v) & 0x0000ff0000000000ULL) >> 24) | \
|
||||
(((v) & 0x00ff000000000000ULL) >> 40) | \
|
||||
(((v) & 0xff00000000000000ULL) >> 56))
|
||||
|
||||
#ifndef HAVE_ATTRIB_PACKED
|
||||
#define __attribute__(x)
|
||||
|
@ -751,7 +735,18 @@ void cli_append_potentially_unwanted_if_heur_exceedsmax(cli_ctx *ctx, char *virn
|
|||
|
||||
const char *cli_get_last_virus(const cli_ctx *ctx);
|
||||
const char *cli_get_last_virus_str(const cli_ctx *ctx);
|
||||
void cli_virus_found_cb(cli_ctx *ctx, const char *virname);
|
||||
|
||||
/**
|
||||
* @brief Dispatch the alert / virus found callbacks.
|
||||
*
|
||||
* AKA for clamscan it will print FOUND message.
|
||||
*
|
||||
* @param ctx The scan context.
|
||||
* @param virname The name of the virus.
|
||||
* @param is_potentially_unwanted true if the alert is for a potentially unwanted application (PUA).
|
||||
* @return cl_error_t
|
||||
*/
|
||||
cl_error_t cli_virus_found_cb(cli_ctx *ctx, const char *virname, bool is_potentially_unwanted);
|
||||
|
||||
/**
|
||||
* @brief Push a new fmap onto our scan recursion stack.
|
||||
|
@ -770,7 +765,7 @@ cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t typ
|
|||
/**
|
||||
* @brief Pop off a layer of our scan recursion stack.
|
||||
*
|
||||
* Returns the fmap for the popped layer. Does NOT funmap() the fmap for you.
|
||||
* Returns the fmap for the popped layer. Does NOT fmap_free() the fmap for you.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @return cl_fmap_t* A pointer to the fmap for the popped layer, may return NULL instead if the stack is empty.
|
||||
|
@ -780,10 +775,13 @@ cl_fmap_t *cli_recursion_stack_pop(cli_ctx *ctx);
|
|||
/**
|
||||
* @brief Re-assign the type for the current layer.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param type The new file type.
|
||||
* @param ctx The scanning context.
|
||||
* @param type The new file type.
|
||||
* @param run_callback Whether to run the scan callback for file type corrections.
|
||||
*
|
||||
* @return cl_error_t CL_SUCCESS if successful, else an error code.
|
||||
*/
|
||||
void cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type);
|
||||
cl_error_t cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type, bool run_callback);
|
||||
|
||||
/**
|
||||
* @brief Get the type of a specific layer.
|
||||
|
@ -823,11 +821,20 @@ cli_file_t cli_recursion_stack_get_type(cli_ctx *ctx, int index);
|
|||
*/
|
||||
size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index);
|
||||
|
||||
/**
|
||||
* @brief Dispatch scan callback based on location.
|
||||
*
|
||||
* @param ctx Current scan context.
|
||||
* @param location Callback location.
|
||||
* @return cl_error_t
|
||||
*/
|
||||
cl_error_t cli_dispatch_scan_callback(cli_ctx *ctx, cl_scan_callback_t location);
|
||||
|
||||
/* used by: spin, yc (C) aCaB */
|
||||
#define __SHIFTBITS(a) (sizeof(a) << 3)
|
||||
#define __SHIFTMASK(a) (__SHIFTBITS(a) - 1)
|
||||
#define CLI_ROL(a, b) a = (a << ((b)&__SHIFTMASK(a))) | (a >> ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
||||
#define CLI_ROR(a, b) a = (a >> ((b)&__SHIFTMASK(a))) | (a << ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
||||
#define CLI_ROL(a, b) a = (a << ((b) & __SHIFTMASK(a))) | (a >> ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
||||
#define CLI_ROR(a, b) a = (a >> ((b) & __SHIFTMASK(a))) | (a << ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
||||
|
||||
/* Implementation independent sign-extended signed right shift */
|
||||
#ifdef HAVE_SAR
|
||||
|
@ -1029,8 +1036,25 @@ void *cli_safer_realloc_or_free(void *ptr, size_t size);
|
|||
char *cli_safer_strdup(const char *s);
|
||||
|
||||
int cli_rmdirs(const char *dirname);
|
||||
char *cli_hashstream(FILE *fs, unsigned char *digcpy, int type);
|
||||
char *cli_hashfile(const char *filename, int type);
|
||||
|
||||
/**
|
||||
* @brief Calculate a hash of a stream.
|
||||
* @param fs The file stream to read from.
|
||||
* @param[out] hash (Optional) The buffer to store the calculated raw binary hash.
|
||||
* @param type The type of hash to calculate.
|
||||
* @return char* Returns the allocated hash string or NULL if allocation failed.
|
||||
*/
|
||||
char *cli_hashstream(FILE *fs, uint8_t *hash, cli_hash_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Calculate a hash of a file.
|
||||
*
|
||||
* @param filename The file to read from.
|
||||
* @param[out] hash (Optional) The buffer to store the calculated raw binary hash.
|
||||
* @param type The type of hash to calculate.
|
||||
* @return char* Returns the allocated hash string or NULL if allocation failed.
|
||||
*/
|
||||
char *cli_hashfile(const char *filename, uint8_t *hash, cli_hash_type_t type);
|
||||
|
||||
/**
|
||||
* @brief unlink() with error checking
|
||||
|
@ -1299,6 +1323,26 @@ uint8_t cli_get_debug_flag(void);
|
|||
*/
|
||||
uint8_t cli_set_debug_flag(uint8_t debug_flag);
|
||||
|
||||
/**
|
||||
* @brief Trust the current layer by removing any evidence and setting the verdict to trusted.
|
||||
*
|
||||
* @param ctx The scan context.
|
||||
* @param source The source of the trust request.
|
||||
* @return cl_error_t CL_SUCCESS on success, or an error code.
|
||||
*/
|
||||
cl_error_t cli_trust_this_layer(cli_ctx *ctx, const char *source);
|
||||
|
||||
/**
|
||||
* @brief Trust a range of layers by removing any evidence and setting the verdict to trusted.
|
||||
*
|
||||
* @param ctx The scan context.
|
||||
* @param start_layer The layer to start trusting from (inclusive).
|
||||
* @param end_layer The layer to stop trusting at (inclusive).
|
||||
* @param source The source of the trust request.
|
||||
* @return cl_error_t CL_SUCCESS on success, or an error code.
|
||||
*/
|
||||
cl_error_t cli_trust_layers(cli_ctx *ctx, uint32_t start_layer, uint32_t end_layer, const char *source);
|
||||
|
||||
#ifndef CLI_SAFER_STRDUP_OR_GOTO_DONE
|
||||
/**
|
||||
* @brief Wrapper around strdup that does a NULL check.
|
||||
|
|
|
@ -1058,7 +1058,7 @@ static size_t find_length(struct pdf_struct *pdf, struct pdf_obj *obj, const cha
|
|||
|
||||
#define DUMP_MASK ((1 << OBJ_CONTENTS) | (1 << OBJ_FILTER_FLATE) | (1 << OBJ_FILTER_DCT) | (1 << OBJ_FILTER_AH) | (1 << OBJ_FILTER_A85) | (1 << OBJ_EMBEDDED_FILE) | (1 << OBJ_JAVASCRIPT) | (1 << OBJ_OPENACTION) | (1 << OBJ_LAUNCHACTION))
|
||||
|
||||
static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd)
|
||||
static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd, const char *filepath)
|
||||
{
|
||||
int ret;
|
||||
struct cli_bc_ctx *bc_ctx;
|
||||
|
@ -1078,7 +1078,8 @@ static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd)
|
|||
|
||||
map = ctx->fmap;
|
||||
if (fd != -1) {
|
||||
map = fmap(fd, 0, 0, NULL);
|
||||
/* The fmap in this bytecode context is an extracted pdf object. */
|
||||
map = fmap_new(fd, 0, 0, NULL, filepath);
|
||||
if (!map) {
|
||||
cli_dbgmsg("run_pdf_hooks: can't mmap pdf extracted obj\n");
|
||||
map = ctx->fmap;
|
||||
|
@ -1092,7 +1093,7 @@ static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd)
|
|||
cli_bytecode_context_destroy(bc_ctx);
|
||||
|
||||
if (fd != -1)
|
||||
funmap(map);
|
||||
fmap_free(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1802,10 +1803,10 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t
|
|||
}
|
||||
}
|
||||
|
||||
if ((pdf->ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) && pdf->ctx->wrkproperty != NULL) {
|
||||
if ((pdf->ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||
struct json_object *pdfobj, *jbig2arr;
|
||||
|
||||
if (NULL == (pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats"))) {
|
||||
if (NULL == (pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats"))) {
|
||||
cli_errmsg("pdf_extract_obj: failed to get PDFStats JSON object\n");
|
||||
} else if (NULL == (jbig2arr = cli_jsonarray(pdfobj, "JavascriptObjects"))) {
|
||||
cli_errmsg("pdf_extract_obj: failed to get JavascriptObjects JSON object\n");
|
||||
|
@ -1886,7 +1887,7 @@ scan_extracted_objects:
|
|||
}
|
||||
|
||||
if ((status == CL_CLEAN) || (status == CL_VIRUS)) {
|
||||
ret = run_pdf_hooks(pdf, PDF_PHASE_POSTDUMP, fout);
|
||||
ret = run_pdf_hooks(pdf, PDF_PHASE_POSTDUMP, fout, fullname);
|
||||
if (ret == CL_VIRUS) {
|
||||
status = ret;
|
||||
goto done;
|
||||
|
@ -2238,8 +2239,8 @@ void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
|
|||
if (!nextobj || bytesleft < 0) {
|
||||
cli_dbgmsg("pdf_parseobj: %u %u obj: no dictionary\n", obj->id >> 8, obj->id & 0xff);
|
||||
|
||||
if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
if (!(pdfobj) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj))
|
||||
return;
|
||||
}
|
||||
|
@ -2285,8 +2286,8 @@ void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
|
|||
if (bytesleft < 0) {
|
||||
cli_dbgmsg("pdf_parseobj: %u %u obj: broken dictionary\n", obj->id >> 8, obj->id & 0xff);
|
||||
|
||||
if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
if (!(pdfobj) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj))
|
||||
return;
|
||||
}
|
||||
|
@ -2334,8 +2335,8 @@ void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
|
|||
/* probably truncated */
|
||||
cli_dbgmsg("pdf_parseobj: %u %u obj broken dictionary\n", obj->id >> 8, obj->id & 0xff);
|
||||
|
||||
if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
if (!(pdfobj) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj))
|
||||
return;
|
||||
}
|
||||
|
@ -2883,7 +2884,7 @@ static void compute_hash_r6(const char *password, size_t pwlen, const unsigned c
|
|||
int32_t block_size = 32;
|
||||
size_t in_data_len = 0, out_data_len;
|
||||
int32_t i, j, sum;
|
||||
uint8_t sha256[32], sha384[48], sha512[64];
|
||||
uint8_t sha2_256[32], sha2_384[48], sha2_512[64];
|
||||
|
||||
/*
|
||||
* Compute a SHA-256 hash of the UTF-8 password concatenated with the 8 bytes of the owner or user validation salt.
|
||||
|
@ -2923,18 +2924,18 @@ static void compute_hash_r6(const char *password, size_t pwlen, const unsigned c
|
|||
block_size = 32 + (sum % 3) * 16;
|
||||
switch (block_size) {
|
||||
case 32:
|
||||
cl_sha256(data, in_data_len * 64, sha256, NULL);
|
||||
memcpy(block, sha256, 32);
|
||||
cl_sha256(data, in_data_len * 64, sha2_256, NULL);
|
||||
memcpy(block, sha2_256, 32);
|
||||
break;
|
||||
|
||||
case 48:
|
||||
cl_sha384(data, in_data_len * 64, sha384, NULL);
|
||||
memcpy(block, sha384, 48);
|
||||
cl_sha384(data, in_data_len * 64, sha2_384, NULL);
|
||||
memcpy(block, sha2_384, 48);
|
||||
break;
|
||||
|
||||
case 64:
|
||||
cl_sha512(data, in_data_len * 64, sha512, NULL);
|
||||
memcpy(block, sha512, 64);
|
||||
cl_sha512(data, in_data_len * 64, sha2_512, NULL);
|
||||
memcpy(block, sha2_512, 64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3692,7 +3693,7 @@ static cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf)
|
|||
}
|
||||
|
||||
if (CL_SUCCESS == status) {
|
||||
status = run_pdf_hooks(pdf, PDF_PHASE_PARSED, -1);
|
||||
status = run_pdf_hooks(pdf, PDF_PHASE_PARSED, -1, NULL);
|
||||
cli_dbgmsg("pdf_find_and_extract_objs: (parsed hooks) returned %d\n", status);
|
||||
}
|
||||
|
||||
|
@ -3776,8 +3777,8 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (ctx->wrkproperty)
|
||||
pdfobj = cli_jsonobj(ctx->wrkproperty, "PDFStats");
|
||||
if (ctx->this_layer_metadata_json)
|
||||
pdfobj = cli_jsonobj(ctx->this_layer_metadata_json, "PDFStats");
|
||||
|
||||
/* offset is 0 when coming from filetype2 */
|
||||
tmp = cli_memstr(pdfver, versize, "%PDF-", 5);
|
||||
|
@ -3919,7 +3920,7 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
|||
|
||||
pdf.startoff = offset;
|
||||
|
||||
rc = run_pdf_hooks(&pdf, PDF_PHASE_PRE, -1);
|
||||
rc = run_pdf_hooks(&pdf, PDF_PHASE_PRE, -1, NULL);
|
||||
if (CL_SUCCESS != rc) {
|
||||
cli_dbgmsg("cli_pdf: (pre hooks) returning %d\n", rc);
|
||||
|
||||
|
@ -3948,7 +3949,7 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
|||
|
||||
if (pdf.flags && CL_SUCCESS == rc) {
|
||||
cli_dbgmsg("cli_pdf: flags 0x%02x\n", pdf.flags);
|
||||
rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1);
|
||||
rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1, NULL);
|
||||
|
||||
if (CL_SUCCESS == rc && SCAN_HEURISTICS && (ctx->dconf->other & OTHER_CONF_PDFNAMEOBJ)) {
|
||||
if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
|
||||
|
@ -4222,10 +4223,10 @@ static void JBIG2Decode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct p
|
|||
if (!(SCAN_COLLECT_METADATA))
|
||||
return;
|
||||
|
||||
if (!(pdf->ctx->wrkproperty))
|
||||
if (!(pdf->ctx->this_layer_metadata_json))
|
||||
return;
|
||||
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj))
|
||||
return;
|
||||
|
||||
|
@ -4612,7 +4613,7 @@ static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname
|
|||
|
||||
UNUSEDPARAM(act);
|
||||
|
||||
if (!(pdf) || !(pdf->ctx->wrkproperty))
|
||||
if (!(pdf) || !(pdf->ctx->this_layer_metadata_json))
|
||||
return;
|
||||
|
||||
ctx = pdf->ctx;
|
||||
|
@ -4620,7 +4621,7 @@ static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname
|
|||
if (!(SCAN_COLLECT_METADATA))
|
||||
return;
|
||||
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj))
|
||||
return;
|
||||
|
||||
|
@ -4688,7 +4689,7 @@ static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
|
|||
|
||||
UNUSEDPARAM(act);
|
||||
|
||||
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->wrkproperty))
|
||||
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->this_layer_metadata_json))
|
||||
return;
|
||||
|
||||
ctx = pdf->ctx;
|
||||
|
@ -4723,7 +4724,7 @@ static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
|
|||
if (ncolors < 1 << 24)
|
||||
return;
|
||||
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj))
|
||||
return;
|
||||
|
||||
|
@ -4745,7 +4746,7 @@ static void URI_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_a
|
|||
|
||||
UNUSEDPARAM(act);
|
||||
|
||||
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->wrkproperty) || !obj) {
|
||||
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->this_layer_metadata_json) || !obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4796,7 +4797,7 @@ static void URI_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_a
|
|||
strncpy(uri_heap, uri_start, end);
|
||||
uri_heap[end] = '\0';
|
||||
|
||||
uriarr = cli_jsonarray(pdf->ctx->wrkproperty, "URIs");
|
||||
uriarr = cli_jsonarray(pdf->ctx->this_layer_metadata_json, "URIs");
|
||||
if (!uriarr) {
|
||||
cli_errmsg("cli_pdf: malloc() failed (URI array)\n");
|
||||
goto done;
|
||||
|
@ -4885,11 +4886,11 @@ static void pdf_export_json(struct pdf_struct *pdf)
|
|||
|
||||
ctx = pdf->ctx;
|
||||
|
||||
if (!(SCAN_COLLECT_METADATA) || !(pdf->ctx->wrkproperty)) {
|
||||
if (!(SCAN_COLLECT_METADATA) || !(pdf->ctx->this_layer_metadata_json)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
||||
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||
if (!(pdfobj)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
201
libclamav/pe.c
201
libclamav/pe.c
|
@ -125,7 +125,7 @@
|
|||
}
|
||||
|
||||
#define CLI_UNPTEMP(NAME, FREEME) \
|
||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) { \
|
||||
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) { \
|
||||
cli_exe_info_destroy(peinfo); \
|
||||
cli_multifree FREEME; \
|
||||
return CL_EMEM; \
|
||||
|
@ -146,24 +146,6 @@
|
|||
} \
|
||||
}
|
||||
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
#define SHA_OFF \
|
||||
do { \
|
||||
ctx->sha_collect = -1; \
|
||||
} while (0)
|
||||
#define SHA_RESET \
|
||||
do { \
|
||||
ctx->sha_collect = sha_collect; \
|
||||
} while (0)
|
||||
#else
|
||||
#define SHA_OFF \
|
||||
do { \
|
||||
} while (0)
|
||||
#define SHA_RESET \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define FSGCASE(NAME, FREESEC) \
|
||||
case 0: /* Unpacked and NOT rebuilt */ \
|
||||
cli_dbgmsg(NAME ": Successfully decompressed\n"); \
|
||||
|
@ -201,15 +183,12 @@
|
|||
cli_exe_info_destroy(peinfo); \
|
||||
lseek(ndesc, 0, SEEK_SET); \
|
||||
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \
|
||||
SHA_OFF; \
|
||||
if (CL_SUCCESS != (ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { \
|
||||
close(ndesc); \
|
||||
SHA_RESET; \
|
||||
CLI_TMPUNLK(); \
|
||||
free(tempfile); \
|
||||
return ret; \
|
||||
} \
|
||||
SHA_RESET; \
|
||||
close(ndesc); \
|
||||
CLI_TMPUNLK(); \
|
||||
free(tempfile); \
|
||||
|
@ -241,8 +220,6 @@
|
|||
|
||||
#define DETECT_BROKEN_PE (SCAN_HEURISTIC_BROKEN && !ctx->corrupted_input)
|
||||
|
||||
extern const unsigned int hashlen[];
|
||||
|
||||
struct offset_list {
|
||||
uint32_t offset;
|
||||
struct offset_list *next;
|
||||
|
@ -530,49 +507,49 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc
|
|||
fmap_unneed_ptr(map, oentry, entries * 8);
|
||||
}
|
||||
|
||||
static unsigned int cli_hashsect(fmap_t *map, struct cli_exe_section *s, unsigned char **digest, int *foundhash, int *foundwild)
|
||||
static bool cli_hashsect(fmap_t *map, struct cli_exe_section *s, uint8_t **digest, bool *foundhash, bool *foundwild)
|
||||
{
|
||||
const void *hashme;
|
||||
|
||||
if (s->rsz > CLI_MAX_ALLOCATION) {
|
||||
cli_dbgmsg("cli_hashsect: skipping hash calculation for too big section\n");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!s->rsz) return 0;
|
||||
if (!s->rsz) return false;
|
||||
if (!(hashme = fmap_need_off_once(map, s->raw, s->rsz))) {
|
||||
cli_dbgmsg("cli_hashsect: unable to read section data\n");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (foundhash[CLI_HASH_MD5] || foundwild[CLI_HASH_MD5])
|
||||
cl_hash_data("md5", hashme, s->rsz, digest[CLI_HASH_MD5], NULL);
|
||||
if (foundhash[CLI_HASH_SHA1] || foundwild[CLI_HASH_SHA1])
|
||||
cl_sha1(hashme, s->rsz, digest[CLI_HASH_SHA1], NULL);
|
||||
if (foundhash[CLI_HASH_SHA256] || foundwild[CLI_HASH_SHA256])
|
||||
cl_sha256(hashme, s->rsz, digest[CLI_HASH_SHA256], NULL);
|
||||
if (foundhash[CLI_HASH_SHA2_256] || foundwild[CLI_HASH_SHA2_256])
|
||||
cl_sha256(hashme, s->rsz, digest[CLI_HASH_SHA2_256], NULL);
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* check hash section sigs */
|
||||
static cl_error_t scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
||||
{
|
||||
struct cli_matcher *mdb_sect = ctx->engine->hm_mdb;
|
||||
unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
|
||||
uint8_t *hashset[CLI_HASH_AVAIL_TYPES];
|
||||
const char *virname = NULL;
|
||||
int foundsize[CLI_HASH_AVAIL_TYPES];
|
||||
int foundwild[CLI_HASH_AVAIL_TYPES];
|
||||
bool foundsize[CLI_HASH_AVAIL_TYPES];
|
||||
bool foundwild[CLI_HASH_AVAIL_TYPES];
|
||||
cli_hash_type_t type;
|
||||
cl_error_t ret = CL_CLEAN;
|
||||
unsigned char *md5 = NULL;
|
||||
cl_error_t ret = CL_CLEAN;
|
||||
uint8_t *md5 = NULL;
|
||||
|
||||
/* pick hashtypes to generate */
|
||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||
foundsize[type] = cli_hm_have_size(mdb_sect, type, exe_section->rsz);
|
||||
foundwild[type] = cli_hm_have_wild(mdb_sect, type);
|
||||
if (foundsize[type] || foundwild[type]) {
|
||||
hashset[type] = malloc(hashlen[type]);
|
||||
hashset[type] = malloc(cli_hash_len(type));
|
||||
if (!hashset[type]) {
|
||||
cli_errmsg("scan_pe_mdb: malloc failed!\n");
|
||||
for (; type > 0;)
|
||||
|
@ -639,7 +616,7 @@ static cl_error_t scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
|||
}
|
||||
|
||||
end:
|
||||
for (type = CLI_HASH_AVAIL_TYPES; type > 0;)
|
||||
for (type = CLI_HASH_AVAIL_TYPES; type > CLI_HASH_MD5;)
|
||||
free(hashset[--type]);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2258,8 +2235,8 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str
|
|||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
if (ctx->wrkproperty) {
|
||||
imptbl = cli_jsonarray(ctx->wrkproperty, "ImportTable");
|
||||
if (ctx->this_layer_metadata_json) {
|
||||
imptbl = cli_jsonarray(ctx->this_layer_metadata_json, "ImportTable");
|
||||
if (!imptbl) {
|
||||
cli_dbgmsg("scan_pe: cannot allocate import table json object\n");
|
||||
return CL_EMEM;
|
||||
|
@ -2405,7 +2382,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *impsz, int *genhash, struct cli_exe_info *peinfo)
|
||||
static cl_error_t hash_imptbl(cli_ctx *ctx, uint8_t **digest, uint32_t *impsz, bool *genhash, struct cli_exe_info *peinfo)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
cl_error_t ret;
|
||||
|
@ -2415,7 +2392,7 @@ static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *im
|
|||
size_t left, fsize = map->len;
|
||||
uint32_t impoff, offset;
|
||||
const char *buffer;
|
||||
void *hashctx[CLI_HASH_AVAIL_TYPES] = {0};
|
||||
void *hashctx[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||
cli_hash_type_t type;
|
||||
int nimps = 0;
|
||||
unsigned int err;
|
||||
|
@ -2451,25 +2428,14 @@ static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *im
|
|||
* would have failed if the size exceeds the end of the fmap. */
|
||||
left = peinfo->dirs[1].Size;
|
||||
|
||||
if (genhash[CLI_HASH_MD5]) {
|
||||
hashctx[CLI_HASH_MD5] = cl_hash_init("md5");
|
||||
if (hashctx[CLI_HASH_MD5] == NULL) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (genhash[CLI_HASH_SHA1]) {
|
||||
hashctx[CLI_HASH_SHA1] = cl_hash_init("sha1");
|
||||
if (hashctx[CLI_HASH_SHA1] == NULL) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (genhash[CLI_HASH_SHA256]) {
|
||||
hashctx[CLI_HASH_SHA256] = cl_hash_init("sha256");
|
||||
if (hashctx[CLI_HASH_SHA256] == NULL) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||
if (genhash[type]) {
|
||||
hashctx[type] = cl_hash_init(cli_hash_name(type));
|
||||
if (hashctx[type] == NULL) {
|
||||
cli_dbgmsg("scan_pe: cannot initialize hash context for %s\n", cli_hash_name(type));
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2570,11 +2536,11 @@ done:
|
|||
|
||||
static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||
{
|
||||
struct cli_matcher *imp = ctx->engine->hm_imp;
|
||||
unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
|
||||
const char *virname = NULL;
|
||||
int genhash[CLI_HASH_AVAIL_TYPES];
|
||||
uint32_t impsz = 0;
|
||||
struct cli_matcher *imp = ctx->engine->hm_imp;
|
||||
uint8_t *hashset[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||
bool genhash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||
const char *virname = NULL;
|
||||
uint32_t impsz = 0;
|
||||
cli_hash_type_t type;
|
||||
cl_error_t ret = CL_CLEAN;
|
||||
|
||||
|
@ -2582,7 +2548,7 @@ static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||
genhash[type] = cli_hm_have_any(imp, type);
|
||||
if (genhash[type]) {
|
||||
hashset[type] = malloc(hashlen[type]);
|
||||
hashset[type] = malloc(cli_hash_len(type));
|
||||
if (!hashset[type]) {
|
||||
cli_errmsg("scan_pe: malloc failed!\n");
|
||||
for (; type > 0;)
|
||||
|
@ -2595,9 +2561,9 @@ static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
}
|
||||
|
||||
/* Force md5 hash generation for debug and preclass */
|
||||
if ((cli_debug_flag || ctx->wrkproperty) && !genhash[CLI_HASH_MD5]) {
|
||||
genhash[CLI_HASH_MD5] = 1;
|
||||
hashset[CLI_HASH_MD5] = calloc(hashlen[CLI_HASH_MD5], sizeof(char));
|
||||
if ((cli_debug_flag || ctx->this_layer_metadata_json) && !genhash[CLI_HASH_MD5]) {
|
||||
genhash[CLI_HASH_MD5] = true;
|
||||
hashset[CLI_HASH_MD5] = calloc(cli_hash_len(CLI_HASH_MD5), sizeof(char));
|
||||
if (!hashset[CLI_HASH_MD5]) {
|
||||
cli_errmsg("scan_pe: calloc failed!\n");
|
||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
|
||||
|
@ -2619,12 +2585,12 @@ static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
}
|
||||
|
||||
/* Print hash */
|
||||
if (cli_debug_flag || ctx->wrkproperty) {
|
||||
char *dstr = cli_str2hex((char *)hashset[CLI_HASH_MD5], hashlen[CLI_HASH_MD5]);
|
||||
if (cli_debug_flag || ctx->this_layer_metadata_json) {
|
||||
char *dstr = cli_str2hex((char *)hashset[CLI_HASH_MD5], cli_hash_len(CLI_HASH_MD5));
|
||||
cli_dbgmsg("IMP: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
|
||||
|
||||
if (ctx->wrkproperty)
|
||||
cli_jsonstr(ctx->wrkproperty, "Imphash", dstr ? dstr : "(NULL)");
|
||||
if (ctx->this_layer_metadata_json)
|
||||
cli_jsonstr(ctx->this_layer_metadata_json, "Imphash", dstr ? dstr : "(NULL)");
|
||||
|
||||
if (dstr)
|
||||
free(dstr);
|
||||
|
@ -2655,15 +2621,15 @@ static struct json_object *get_pe_property(cli_ctx *ctx)
|
|||
{
|
||||
struct json_object *pe;
|
||||
|
||||
if (!(ctx) || !(ctx->wrkproperty))
|
||||
if (!(ctx) || !(ctx->this_layer_metadata_json))
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(ctx->wrkproperty, "PE", &pe)) {
|
||||
if (!json_object_object_get_ex(ctx->this_layer_metadata_json, "PE", &pe)) {
|
||||
pe = json_object_new_object();
|
||||
if (!(pe))
|
||||
return NULL;
|
||||
|
||||
json_object_object_add(ctx->wrkproperty, "PE", pe);
|
||||
json_object_object_add(ctx->this_layer_metadata_json, "PE", pe);
|
||||
}
|
||||
|
||||
return pe;
|
||||
|
@ -2781,9 +2747,6 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
struct cli_bc_ctx *bc_ctx;
|
||||
fmap_t *map;
|
||||
struct cli_pe_hook_data pedata;
|
||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
||||
int sha_collect = ctx->sha_collect;
|
||||
#endif
|
||||
int toval = 0;
|
||||
struct json_object *pe_json = NULL;
|
||||
|
||||
|
@ -2900,7 +2863,7 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
|
||||
/* CLI_UNPTEMP("cli_scanpe: DISASM",(peinfo->sections,0)); */
|
||||
/* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */
|
||||
/* ret = cli_scan_desc(ndesc, ctx, CL_TYPE_PE_DISASM, true, NULL, AC_SCAN_VIR); */
|
||||
/* ret = cli_scan_desc(ndesc, ctx, CL_TYPE_PE_DISASM, true, NULL, NULL, AC_SCAN_VIR); */
|
||||
/* close(ndesc); */
|
||||
/* if(ret == CL_VIRUS) { */
|
||||
/* cli_exe_info_destroy(peinfo); */
|
||||
|
@ -2962,7 +2925,7 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
|
||||
/* Attempt to run scans on import table */
|
||||
/* Run if there are existing signatures and/or preclassing */
|
||||
if (DCONF & PE_CONF_IMPTBL && (ctx->engine->hm_imp || ctx->wrkproperty)) {
|
||||
if (DCONF & PE_CONF_IMPTBL && (ctx->engine->hm_imp || ctx->this_layer_metadata_json)) {
|
||||
ret = scan_pe_imp(ctx, peinfo);
|
||||
switch (ret) {
|
||||
case CL_SUCCESS:
|
||||
|
@ -3932,7 +3895,6 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
if (lseek(ndesc, 0, SEEK_SET) == -1) {
|
||||
cli_dbgmsg("cli_scanpe: UPX/FSG: lseek() failed\n");
|
||||
close(ndesc);
|
||||
SHA_RESET;
|
||||
CLI_TMPUNLK();
|
||||
free(tempfile);
|
||||
return CL_ESEEK;
|
||||
|
@ -3942,17 +3904,14 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
cli_dbgmsg("cli_scanpe: UPX/FSG: Decompressed data saved in %s\n", tempfile);
|
||||
|
||||
cli_dbgmsg("***** Scanning decompressed file *****\n");
|
||||
SHA_OFF;
|
||||
ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||
if (CL_SUCCESS != ret) {
|
||||
close(ndesc);
|
||||
SHA_RESET;
|
||||
CLI_TMPUNLK();
|
||||
free(tempfile);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SHA_RESET;
|
||||
close(ndesc);
|
||||
CLI_TMPUNLK();
|
||||
free(tempfile);
|
||||
|
@ -4119,7 +4078,7 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
cli_jsonstr(pe_json, "Packer", "yC");
|
||||
|
||||
// record number of alerts before unpacking and scanning
|
||||
num_alerts = evidence_num_alerts(ctx->evidence);
|
||||
num_alerts = evidence_num_alerts(ctx->this_layer_evidence);
|
||||
|
||||
cli_dbgmsg("%d,%d,%d,%d\n", peinfo->nsections - 1, peinfo->e_lfanew, ecx, offset);
|
||||
CLI_UNPTEMP("cli_scanpe: yC", (spinned, 0));
|
||||
|
@ -4131,7 +4090,7 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
//
|
||||
// This preserves the intention of https://github.com/Cisco-Talos/clamav/commit/771c23099893f02f1316960fbe84f62b115a3556
|
||||
// although that commit had it bailing if a match occurred even in allmatch-mode, which we do not want to do.
|
||||
if (!SCAN_ALLMATCHES && num_alerts != evidence_num_alerts(ctx->evidence)) {
|
||||
if (!SCAN_ALLMATCHES && num_alerts != evidence_num_alerts(ctx->this_layer_evidence)) {
|
||||
cli_exe_info_destroy(peinfo);
|
||||
return CL_VIRUS;
|
||||
}
|
||||
|
@ -5436,7 +5395,8 @@ cl_error_t cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts,
|
|||
} /* look for stringfileinfo - NOT RESUMABLE */
|
||||
break;
|
||||
} /* look for version_info - NOT RESUMABLE */
|
||||
} /* enum all version_information res - RESUMABLE */
|
||||
|
||||
} /* enum all version_information res - RESUMABLE */
|
||||
break;
|
||||
} /* while(dirs[2].Size) */
|
||||
|
||||
|
@ -5495,6 +5455,9 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
uint32_t sec_dir_size;
|
||||
struct cli_exe_info _peinfo;
|
||||
|
||||
char *source = NULL;
|
||||
size_t source_len = 0;
|
||||
|
||||
// If Authenticode parsing has been disabled via DCONF or an engine
|
||||
// option, then don't continue on.
|
||||
if (!(DCONF & PE_CONF_CERTS))
|
||||
|
@ -5525,7 +5488,7 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
// for the 'PE' .cat Authenticode hash file type.
|
||||
if (sec_dir_size < 8 &&
|
||||
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 2) &&
|
||||
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, 2)) {
|
||||
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA2_256, 2)) {
|
||||
ret = CL_BREAK;
|
||||
goto finish;
|
||||
}
|
||||
|
@ -5656,7 +5619,7 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
const char *hashctx_name;
|
||||
} supported_hashes[] = {
|
||||
{CLI_HASH_SHA1, "sha1"},
|
||||
{CLI_HASH_SHA256, "sha256"},
|
||||
{CLI_HASH_SHA2_256, "sha2-256"},
|
||||
};
|
||||
|
||||
for (i = 0; i < (sizeof(supported_hashes) / sizeof(supported_hashes[0])); i++) {
|
||||
|
@ -5695,6 +5658,20 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
|
||||
if (cli_hm_scan(authsha, 2, NULL, ctx->engine->hm_fp, hashtype) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_check_auth_header: PE file trusted by catalog file (%s)\n", hashctx_name);
|
||||
|
||||
source_len = strlen("authenticode catalog file: ") + strlen(hashctx_name) + 1;
|
||||
source = malloc(source_len);
|
||||
if (!source) {
|
||||
cli_errmsg("dispatch_scan_callback: no memory for source string\n");
|
||||
goto finish;
|
||||
}
|
||||
snprintf(source, source_len, "authenticode catalog file: %s", hashctx_name);
|
||||
|
||||
// Remove any evidence for this layer and set the verdict to trusted.
|
||||
(void)cli_trust_this_layer(ctx, source);
|
||||
|
||||
CLI_FREE_AND_SET_NULL(source);
|
||||
|
||||
ret = CL_VERIFIED;
|
||||
goto finish;
|
||||
}
|
||||
|
@ -5715,10 +5692,13 @@ finish:
|
|||
if (&_peinfo == peinfo) {
|
||||
cli_exe_info_destroy(peinfo);
|
||||
}
|
||||
|
||||
CLI_FREE_AND_SET_NULL(source);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print out either the MD5, SHA1, or SHA256 associated with the imphash or
|
||||
/* Print out either the MD5, SHA1, or SHA2-256 associated with the imphash or
|
||||
* the individual sections. Also, this function computes the hashes of each
|
||||
* section (sorted based on the RVAs of the sections) if hashes is non-NULL.
|
||||
*
|
||||
|
@ -5737,15 +5717,16 @@ finish:
|
|||
* - If a section exists completely outside of the file, it won't be included
|
||||
* in the list of sections, and nsections will be adjusted accordingly.
|
||||
*/
|
||||
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *hashes)
|
||||
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, cli_hash_type_t type, stats_section_t *hashes)
|
||||
{
|
||||
unsigned int i;
|
||||
struct cli_exe_info _peinfo;
|
||||
struct cli_exe_info *peinfo = &_peinfo;
|
||||
|
||||
unsigned char *hash, *hashset[CLI_HASH_AVAIL_TYPES];
|
||||
int genhash[CLI_HASH_AVAIL_TYPES];
|
||||
int hlen = 0;
|
||||
uint8_t *hash = NULL;
|
||||
uint8_t *hashset[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||
bool genhash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||
int hlen = 0;
|
||||
|
||||
if (hashes) {
|
||||
hashes->sections = NULL;
|
||||
|
@ -5771,26 +5752,16 @@ cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_sect
|
|||
cli_qsort(peinfo->sections, peinfo->nsections, sizeof(*(peinfo->sections)), sort_sects);
|
||||
|
||||
/* pick hashtypes to generate */
|
||||
memset(genhash, 0, sizeof(genhash));
|
||||
memset(hashset, 0, sizeof(hashset));
|
||||
switch (type) {
|
||||
case 1:
|
||||
genhash[CLI_HASH_MD5] = 1;
|
||||
hlen = hashlen[CLI_HASH_MD5];
|
||||
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] = calloc(hlen, sizeof(char));
|
||||
break;
|
||||
default:
|
||||
genhash[CLI_HASH_SHA256] = 1;
|
||||
hlen = hashlen[CLI_HASH_SHA256];
|
||||
hash = hashset[CLI_HASH_SHA256] = calloc(hlen, sizeof(char));
|
||||
break;
|
||||
genhash[type] = true;
|
||||
|
||||
hlen = cli_hash_len(type);
|
||||
if (hlen <= 0) {
|
||||
cli_dbgmsg("cli_genhash_pe: Invalid hash type %u\n", type);
|
||||
cli_exe_info_destroy(peinfo);
|
||||
return CL_EARG;
|
||||
}
|
||||
|
||||
hash = hashset[type] = calloc(hlen, sizeof(char));
|
||||
if (!hash) {
|
||||
cli_errmsg("cli_genhash_pe: calloc failed!\n");
|
||||
cli_exe_info_destroy(peinfo);
|
||||
|
@ -5813,7 +5784,7 @@ cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_sect
|
|||
|
||||
for (i = 0; i < peinfo->nsections; i++) {
|
||||
/* Generate hashes */
|
||||
if (cli_hashsect(ctx->fmap, &peinfo->sections[i], hashset, genhash, genhash) == 1) {
|
||||
if (cli_hashsect(ctx->fmap, &peinfo->sections[i], hashset, genhash, genhash)) {
|
||||
if (cli_debug_flag) {
|
||||
dstr = cli_str2hex((char *)hash, hlen);
|
||||
cli_dbgmsg("Section{%u}: %u:%s\n", i, peinfo->sections[i].rsz, dstr ? (char *)dstr : "(NULL)");
|
||||
|
|
|
@ -91,7 +91,7 @@ cl_error_t cli_pe_targetinfo(cli_ctx *ctx, struct cli_exe_info *peinfo);
|
|||
cl_error_t cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ctx *ctx);
|
||||
|
||||
cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo);
|
||||
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *hashes);
|
||||
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, cli_hash_type_t type, stats_section_t *hashes);
|
||||
|
||||
uint32_t cli_rawaddr(uint32_t, const struct cli_exe_section *, uint16_t, unsigned int *, size_t, uint32_t);
|
||||
void findres(uint32_t, uint32_t, fmap_t *map, struct cli_exe_info *, int (*)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *);
|
||||
|
|
|
@ -1369,7 +1369,7 @@ static int parseicon(struct ICON_ENV *icon_env, uint32_t rva)
|
|||
if (!ctx || !ctx->engine || !(matcher = ctx->engine->iconcheck))
|
||||
return CL_SUCCESS;
|
||||
map = ctx->fmap;
|
||||
tempd = (cli_debug_flag && ctx->engine->keeptmp) ? (ctx->sub_tmpdir ? ctx->sub_tmpdir : cli_gettmpdir()) : NULL;
|
||||
tempd = (cli_debug_flag && ctx->engine->keeptmp) ? (ctx->this_layer_tmpdir ? ctx->this_layer_tmpdir : cli_gettmpdir()) : NULL;
|
||||
icoff = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size);
|
||||
|
||||
/* read the bitmap header */
|
||||
|
|
|
@ -1168,37 +1168,37 @@ static cl_error_t hash_match(const struct regex_matcher* rlist,
|
|||
|
||||
*phishing_verdict = CL_PHISH_NODECISION;
|
||||
|
||||
if (rlist->sha256_hashes.bm_patterns) {
|
||||
if (rlist->sha2_256_hashes.bm_patterns) {
|
||||
const char hexchars[] = "0123456789ABCDEF";
|
||||
unsigned char h[65];
|
||||
unsigned char sha256_dig[32];
|
||||
unsigned char sha2_256_dig[32];
|
||||
unsigned i;
|
||||
void* sha256;
|
||||
void* sha2_256;
|
||||
|
||||
sha256 = cl_hash_init("sha256");
|
||||
if (!(sha256))
|
||||
sha2_256 = cl_hash_init("sha2-256");
|
||||
if (!(sha2_256))
|
||||
return CL_EMEM;
|
||||
|
||||
cl_update_hash(sha256, (void*)host, hlen);
|
||||
cl_update_hash(sha256, (void*)path, plen);
|
||||
cl_finish_hash(sha256, sha256_dig);
|
||||
cl_update_hash(sha2_256, (void*)host, hlen);
|
||||
cl_update_hash(sha2_256, (void*)path, plen);
|
||||
cl_finish_hash(sha2_256, sha2_256_dig);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
h[2 * i] = hexchars[sha256_dig[i] >> 4];
|
||||
h[2 * i + 1] = hexchars[sha256_dig[i] & 0xf];
|
||||
h[2 * i] = hexchars[sha2_256_dig[i] >> 4];
|
||||
h[2 * i + 1] = hexchars[sha2_256_dig[i] & 0xf];
|
||||
}
|
||||
h[64] = '\0';
|
||||
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
|
||||
#if 0
|
||||
if (prefix_matched) {
|
||||
if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
|
||||
if (cli_bm_scanbuff(sha2_256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
|
||||
cli_dbgmsg("prefix matched\n");
|
||||
*prefix_matched = 1;
|
||||
} else
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes, 0, NULL, NULL, NULL) == CL_VIRUS) {
|
||||
if (cli_bm_scanbuff(sha2_256_dig, 32, &virname, NULL, &rlist->sha2_256_hashes, 0, NULL, NULL, NULL) == CL_VIRUS) {
|
||||
cli_dbgmsg("This hash matched: %s\n", h);
|
||||
switch (*virname) {
|
||||
case 'W':
|
||||
|
@ -1347,7 +1347,7 @@ static cl_error_t url_hash_match(
|
|||
char urlbuff[URL_MAX_LEN + 3]; /* htmlnorm truncates at 1024 bytes + terminating null + slash + host end null */
|
||||
unsigned count;
|
||||
|
||||
if (!rlist || !rlist->sha256_hashes.bm_patterns) {
|
||||
if (!rlist || !rlist->sha2_256_hashes.bm_patterns) {
|
||||
/* no hashes loaded -> don't waste time canonicalizing and
|
||||
* looking up */
|
||||
goto done;
|
||||
|
|
|
@ -2615,7 +2615,7 @@ static int cli_loadinfo(FILE *fs, struct cl_engine *engine, unsigned int options
|
|||
return CL_EMALFDB;
|
||||
}
|
||||
|
||||
ctx = cl_hash_init("sha256");
|
||||
ctx = cl_hash_init("sha2-256");
|
||||
if (!(ctx))
|
||||
return CL_EMALFDB;
|
||||
|
||||
|
@ -2695,7 +2695,7 @@ static int cli_loadinfo(FILE *fs, struct cl_engine *engine, unsigned int options
|
|||
new->size = atoi(tokens[1]);
|
||||
|
||||
if (strlen(tokens[2]) != 64 || !(new->hash = CLI_MPOOL_HEX2STR(engine->mempool, tokens[2]))) {
|
||||
cli_errmsg("cli_loadinfo: Malformed SHA256 string at line %u\n", line);
|
||||
cli_errmsg("cli_loadinfo: Malformed SHA2-256 string at line %u\n", line);
|
||||
MPOOL_FREE(engine->mempool, new->name);
|
||||
MPOOL_FREE(engine->mempool, new);
|
||||
ret = CL_EMALFDB;
|
||||
|
@ -2820,48 +2820,20 @@ static int cli_loadign(FILE *fs, struct cl_engine *engine, unsigned int options,
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
#define MD5_HDB 0
|
||||
#define MD5_MDB 1
|
||||
#define MD5_FP 2
|
||||
#define MD5_IMP 3
|
||||
|
||||
#define MD5_TOKENS 5
|
||||
static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int mode, unsigned int options, struct cli_dbio *dbio, const char *dbname)
|
||||
#define HASH_DB_TOKENS 5
|
||||
static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, hash_purpose_t purpose, unsigned int options, struct cli_dbio *dbio, const char *dbname)
|
||||
{
|
||||
const char *tokens[MD5_TOKENS + 1];
|
||||
const char *tokens[HASH_DB_TOKENS + 1];
|
||||
char buffer[FILEBUFF], *buffer_cpy = NULL;
|
||||
const char *pt, *virname;
|
||||
int ret = CL_SUCCESS;
|
||||
unsigned int size_field = 1, md5_field = 0, line = 0, sigs = 0, tokens_count;
|
||||
unsigned int size_field = 1, hash_field = 0, line = 0, sigs = 0, tokens_count;
|
||||
unsigned int req_fl = 0;
|
||||
struct cli_matcher *db;
|
||||
unsigned long size;
|
||||
|
||||
if (mode == MD5_MDB) {
|
||||
if (purpose == HASH_PURPOSE_PE_SECTION_DETECT) {
|
||||
size_field = 0;
|
||||
md5_field = 1;
|
||||
db = engine->hm_mdb;
|
||||
} else if (mode == MD5_HDB)
|
||||
db = engine->hm_hdb;
|
||||
else if (mode == MD5_IMP)
|
||||
db = engine->hm_imp;
|
||||
else
|
||||
db = engine->hm_fp;
|
||||
|
||||
if (!db) {
|
||||
if (!(db = MPOOL_CALLOC(engine->mempool, 1, sizeof(*db))))
|
||||
return CL_EMEM;
|
||||
#ifdef USE_MPOOL
|
||||
db->mempool = engine->mempool;
|
||||
#endif
|
||||
if (mode == MD5_HDB)
|
||||
engine->hm_hdb = db;
|
||||
else if (mode == MD5_MDB)
|
||||
engine->hm_mdb = db;
|
||||
else if (mode == MD5_IMP)
|
||||
engine->hm_imp = db;
|
||||
else
|
||||
engine->hm_fp = db;
|
||||
hash_field = 1;
|
||||
}
|
||||
|
||||
if (engine->ignored)
|
||||
|
@ -2878,23 +2850,23 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo,
|
|||
if (engine->ignored)
|
||||
strcpy(buffer_cpy, buffer);
|
||||
|
||||
tokens_count = cli_strtokenize(buffer, ':', MD5_TOKENS + 1, tokens);
|
||||
tokens_count = cli_strtokenize(buffer, ':', HASH_DB_TOKENS + 1, tokens);
|
||||
if (tokens_count < 3) {
|
||||
ret = CL_EMALFDB;
|
||||
break;
|
||||
}
|
||||
if (tokens_count > MD5_TOKENS - 2) {
|
||||
req_fl = atoi(tokens[MD5_TOKENS - 2]);
|
||||
if (tokens_count > HASH_DB_TOKENS - 2) {
|
||||
req_fl = atoi(tokens[HASH_DB_TOKENS - 2]);
|
||||
|
||||
if (tokens_count > MD5_TOKENS) {
|
||||
if (tokens_count > HASH_DB_TOKENS) {
|
||||
ret = CL_EMALFDB;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cl_retflevel() < req_fl)
|
||||
continue;
|
||||
if (tokens_count == MD5_TOKENS) {
|
||||
int max_fl = atoi(tokens[MD5_TOKENS - 1]);
|
||||
if (tokens_count == HASH_DB_TOKENS) {
|
||||
int max_fl = atoi(tokens[HASH_DB_TOKENS - 1]);
|
||||
if (cl_retflevel() > (unsigned int)max_fl)
|
||||
continue;
|
||||
}
|
||||
|
@ -2914,7 +2886,7 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo,
|
|||
// is specified. This check doesn't apply to .imp rules, though,
|
||||
// since this rule category wasn't introduced until FLEVEL 90, and
|
||||
// has always supported wildcard usage in rules.
|
||||
if (mode != MD5_IMP && ((tokens_count < MD5_TOKENS - 1) || (req_fl < 73))) {
|
||||
if (purpose != HASH_PURPOSE_PE_IMPORT_DETECT && ((tokens_count < HASH_DB_TOKENS - 1) || (req_fl < 73))) {
|
||||
cli_errmsg("cli_loadhash: Minimum FLEVEL field must be at least 73 for wildcard size hash signatures."
|
||||
" For reference, running FLEVEL is %d\n",
|
||||
cl_retflevel());
|
||||
|
@ -2949,7 +2921,7 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo,
|
|||
break;
|
||||
}
|
||||
|
||||
if (CL_SUCCESS != (ret = hm_addhash_str(db, tokens[md5_field], size, virname))) {
|
||||
if (CL_SUCCESS != (ret = hm_addhash_str(engine, purpose, tokens[hash_field], size, virname))) {
|
||||
cli_errmsg("cli_loadhash: Malformed hash string at line %u\n", line);
|
||||
MPOOL_FREE(engine->mempool, (void *)virname);
|
||||
break;
|
||||
|
@ -3536,7 +3508,7 @@ static int cli_loadmscat(FILE *fs, const char *dbname, struct cl_engine *engine,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!(map = fmap(fileno(fs), 0, 0, dbname))) {
|
||||
if (!(map = fmap_new(fileno(fs), 0, 0, dbname, NULL))) {
|
||||
cli_dbgmsg("Can't map cat: %s\n", dbname);
|
||||
return 0;
|
||||
}
|
||||
|
@ -3545,7 +3517,7 @@ static int cli_loadmscat(FILE *fs, const char *dbname, struct cl_engine *engine,
|
|||
cli_dbgmsg("Failed to load certificates from cat: %s\n", dbname);
|
||||
}
|
||||
|
||||
funmap(map);
|
||||
fmap_free(map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4776,35 +4748,35 @@ cl_error_t cli_load(const char *filename, struct cl_engine *engine, unsigned int
|
|||
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname);
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".cvd")) {
|
||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CVD, filename, sign_verifier, 0);
|
||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CVD, filename, sign_verifier, false);
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".cld")) {
|
||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CLD, filename, sign_verifier, 0);
|
||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CLD, filename, sign_verifier, false);
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".cud")) {
|
||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CUD, filename, sign_verifier, 0);
|
||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CUD, filename, sign_verifier, false);
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".crb")) {
|
||||
ret = cli_loadcrt(fs, engine, dbio);
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".hdb") || cli_strbcasestr(dbname, ".hsb")) {
|
||||
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options, dbio, dbname);
|
||||
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_WHOLE_FILE_DETECT, options, dbio, dbname);
|
||||
} else if (cli_strbcasestr(dbname, ".hdu") || cli_strbcasestr(dbname, ".hsu")) {
|
||||
if (options & CL_DB_PUA)
|
||||
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options | CL_DB_PUA_MODE, dbio, dbname);
|
||||
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_WHOLE_FILE_DETECT, options | CL_DB_PUA_MODE, dbio, dbname);
|
||||
else
|
||||
skipped = 1;
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".sfp")) {
|
||||
ret = cli_loadhash(fs, engine, signo, MD5_FP, options, dbio, dbname);
|
||||
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_WHOLE_FILE_FP_CHECK, options, dbio, dbname);
|
||||
} else if (cli_strbcasestr(dbname, ".mdb") || cli_strbcasestr(dbname, ".msb")) {
|
||||
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options, dbio, dbname);
|
||||
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_PE_SECTION_DETECT, options, dbio, dbname);
|
||||
} else if (cli_strbcasestr(dbname, ".imp")) {
|
||||
ret = cli_loadhash(fs, engine, signo, MD5_IMP, options, dbio, dbname);
|
||||
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_PE_IMPORT_DETECT, options, dbio, dbname);
|
||||
|
||||
} else if (cli_strbcasestr(dbname, ".mdu") || cli_strbcasestr(dbname, ".msu")) {
|
||||
if (options & CL_DB_PUA)
|
||||
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options | CL_DB_PUA_MODE, dbio, dbname);
|
||||
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_PE_SECTION_DETECT, options | CL_DB_PUA_MODE, dbio, dbname);
|
||||
else
|
||||
skipped = 1;
|
||||
|
||||
|
@ -5289,7 +5261,7 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
|||
}
|
||||
|
||||
if (engine->dboptions & CL_DB_COMPILED) {
|
||||
cli_errmsg("cl_load(): can't load new databases when engine is already compiled\n");
|
||||
cli_errmsg("cl_load: can't load new databases when engine is already compiled\n");
|
||||
return CL_EARG;
|
||||
}
|
||||
|
||||
|
@ -5297,27 +5269,27 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
|||
switch (errno) {
|
||||
#if defined(EACCES)
|
||||
case EACCES:
|
||||
cli_errmsg("cl_load(): Access denied for path: %s\n", path);
|
||||
cli_errmsg("cl_load: Access denied for path: %s\n", path);
|
||||
break;
|
||||
#endif
|
||||
#if defined(ENOENT)
|
||||
case ENOENT:
|
||||
cli_errmsg("cl_load(): No such file or directory: %s\n", path);
|
||||
cli_errmsg("cl_load: No such file or directory: %s\n", path);
|
||||
break;
|
||||
#endif
|
||||
#if defined(ELOOP)
|
||||
case ELOOP:
|
||||
cli_errmsg("cl_load(): Too many symbolic links encountered in path: %s\n", path);
|
||||
cli_errmsg("cl_load: Too many symbolic links encountered in path: %s\n", path);
|
||||
break;
|
||||
#endif
|
||||
#if defined(EOVERFLOW)
|
||||
case EOVERFLOW:
|
||||
cli_errmsg("cl_load(): File size is too large to be recognized. Path: %s\n", path);
|
||||
cli_errmsg("cl_load: File size is too large to be recognized. Path: %s\n", path);
|
||||
break;
|
||||
#endif
|
||||
#if defined(EIO)
|
||||
case EIO:
|
||||
cli_errmsg("cl_load(): An I/O error occurred while reading from path: %s\n", path);
|
||||
cli_errmsg("cl_load: An I/O error occurred while reading from path: %s\n", path);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -5338,8 +5310,13 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
|||
cli_dbgmsg("Bytecode engine disabled\n");
|
||||
}
|
||||
|
||||
if (!engine->cache && clean_cache_init(engine))
|
||||
return CL_EMEM;
|
||||
if (!engine->cache) {
|
||||
ret = clean_cache_init(engine);
|
||||
if (ret != CL_SUCCESS) {
|
||||
cli_errmsg("cl_load: Failed to initialize the cache: %s\n", cl_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
engine->dboptions |= dboptions;
|
||||
|
||||
|
@ -5365,7 +5342,7 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
|||
break;
|
||||
|
||||
default:
|
||||
cli_errmsg("cl_load(%s): Not supported database file type\n", path);
|
||||
cli_errmsg("cl_load: Not supported database file type: %s\n", path);
|
||||
if (sign_verifier) {
|
||||
codesign_verifier_free(sign_verifier);
|
||||
}
|
||||
|
|
|
@ -320,10 +320,10 @@ cl_error_t init_regex_list(struct regex_matcher *matcher, uint8_t dconf_prefilte
|
|||
goto done;
|
||||
}
|
||||
#ifdef USE_MPOOL
|
||||
matcher->sha256_hashes.mempool = mp;
|
||||
matcher->hostkey_prefix.mempool = mp;
|
||||
matcher->sha2_256_hashes.mempool = mp;
|
||||
matcher->hostkey_prefix.mempool = mp;
|
||||
#endif
|
||||
if ((rc = cli_bm_init(&matcher->sha256_hashes))) {
|
||||
if ((rc = cli_bm_init(&matcher->sha2_256_hashes))) {
|
||||
goto done;
|
||||
}
|
||||
if ((rc = cli_bm_init(&matcher->hostkey_prefix))) {
|
||||
|
@ -406,18 +406,18 @@ static int add_hash(struct regex_matcher *matcher, char *pattern, const char fl,
|
|||
pat->length = 4;
|
||||
bm = &matcher->hostkey_prefix;
|
||||
} else {
|
||||
bm = &matcher->sha256_hashes;
|
||||
bm = &matcher->sha2_256_hashes;
|
||||
}
|
||||
|
||||
if (!matcher->sha256_pfx_set.keys) {
|
||||
if ((rc = cli_hashset_init(&matcher->sha256_pfx_set, 1048576, 90))) {
|
||||
if (!matcher->sha2_256_pfx_set.keys) {
|
||||
if ((rc = cli_hashset_init(&matcher->sha2_256_pfx_set, 1048576, 90))) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (fl != 'W' && pat->length == 32 &&
|
||||
cli_hashset_contains(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)) &&
|
||||
cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha256_hashes, 0, NULL, NULL, NULL) == CL_VIRUS) {
|
||||
cli_hashset_contains(&matcher->sha2_256_pfx_set, cli_readint32(pat->pattern)) &&
|
||||
cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha2_256_hashes, 0, NULL, NULL, NULL) == CL_VIRUS) {
|
||||
if (*vname == 'W') {
|
||||
/* hash is allowed in local.gdb */
|
||||
cli_dbgmsg("Skipping hash %s\n", pattern);
|
||||
|
@ -432,7 +432,7 @@ static int add_hash(struct regex_matcher *matcher, char *pattern, const char fl,
|
|||
goto done;
|
||||
}
|
||||
*pat->virname = fl;
|
||||
cli_hashset_addkey(&matcher->sha256_pfx_set, cli_readint32(pat->pattern));
|
||||
cli_hashset_addkey(&matcher->sha2_256_pfx_set, cli_readint32(pat->pattern));
|
||||
if ((rc = cli_bm_addpatt(bm, pat, "*"))) {
|
||||
cli_errmsg("add_hash: failed to add BM pattern\n");
|
||||
rc = CL_EMALFDB;
|
||||
|
@ -597,7 +597,7 @@ cl_error_t cli_build_regex_list(struct regex_matcher *matcher)
|
|||
if ((rc = cli_ac_buildtrie(&matcher->suffixes)))
|
||||
return rc;
|
||||
matcher->list_built = 1;
|
||||
cli_hashset_destroy(&matcher->sha256_pfx_set);
|
||||
cli_hashset_destroy(&matcher->sha2_256_pfx_set);
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
@ -635,7 +635,7 @@ void regex_list_done(struct regex_matcher *matcher)
|
|||
MPOOL_FREE(matcher->mempool, matcher->all_pregs);
|
||||
}
|
||||
cli_hashtab_free(&matcher->suffix_hash);
|
||||
cli_bm_free(&matcher->sha256_hashes);
|
||||
cli_bm_free(&matcher->sha2_256_hashes);
|
||||
cli_bm_free(&matcher->hostkey_prefix);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ struct regex_matcher {
|
|||
size_t regex_cnt;
|
||||
regex_t** all_pregs;
|
||||
struct cli_matcher suffixes;
|
||||
struct cli_matcher sha256_hashes;
|
||||
struct cli_hashset sha256_pfx_set;
|
||||
struct cli_matcher sha2_256_hashes;
|
||||
struct cli_hashset sha2_256_pfx_set;
|
||||
struct cli_matcher hostkey_prefix;
|
||||
struct filter filter;
|
||||
#ifdef USE_MPOOL
|
||||
|
|
|
@ -532,7 +532,7 @@ int cli_scanrtf(cli_ctx* ctx)
|
|||
return CL_EMEM;
|
||||
}
|
||||
|
||||
if (!(tempname = cli_gentemp_with_prefix(ctx->sub_tmpdir, "rtf-tmp")))
|
||||
if (!(tempname = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "rtf-tmp")))
|
||||
return CL_EMEM;
|
||||
|
||||
if (mkdir(tempname, 0700)) {
|
||||
|
|
232
libclamav/scan_layer.c
Normal file
232
libclamav/scan_layer.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright (C) 2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Valerie Snyder
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "scan_layer.h"
|
||||
|
||||
#include "clamav_rust.h"
|
||||
|
||||
/**
|
||||
* @brief Get the file map associated with a scan layer.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param fmap_out Pointer to a variable to receive the file map.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_fmap(
|
||||
cl_scan_layer_t *layer,
|
||||
cl_fmap_t **fmap_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !fmap_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*fmap_out = l->fmap;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the parent layer of a scan layer.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param parent_layer_out Pointer to a variable to receive the parent layer.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_parent_layer(
|
||||
cl_scan_layer_t *layer,
|
||||
cl_scan_layer_t **parent_layer_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !parent_layer_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*parent_layer_out = (cl_scan_layer_t *)l->parent;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the file type of a scan layer.
|
||||
*
|
||||
* The file type as clamav currently believes it to be.
|
||||
* It may change later in the scan, so consider using `clcb_file_type_correction`
|
||||
* callback to access the file again if it is re-typed.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param type_out Pointer to a variable to receive the file type.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_type(
|
||||
cl_scan_layer_t *layer,
|
||||
const char **type_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !type_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*type_out = cli_ftname(l->type);
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the recursion level of a scan layer.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param recursion_level_out Pointer to a variable to receive the recursion level.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_recursion_level(
|
||||
cl_scan_layer_t *layer,
|
||||
uint32_t *recursion_level_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !recursion_level_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*recursion_level_out = l->recursion_level;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the object ID of a scan layer.
|
||||
*
|
||||
* Object ID is a unique identifier for the scan layer. It counts up from 0, although the callback interface
|
||||
* may skip some IDs if the scan layer is processed immediately rather than being handled as distinct file type.
|
||||
* For example, HTML may be normalized several ways and they're each given an Object ID, but we immediately
|
||||
* pattern match them and do not handle them as distinct file types that were contained within the HTML.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param object_id_out Pointer to a variable to receive the object ID.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_object_id(
|
||||
cl_scan_layer_t *layer,
|
||||
uint64_t *object_id_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !object_id_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*object_id_out = l->object_id;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the last detected alert (aka Strong indicator) name from a scan layer.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param alert_name_out Pointer to a variable to receive the alert name.
|
||||
* If the layer has no alerts, this will be set to NULL.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_last_alert(
|
||||
cl_scan_layer_t *layer,
|
||||
const char **alert_name_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !alert_name_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (NULL != l->evidence) {
|
||||
const char *alert_name = evidence_get_last_alert(l->evidence);
|
||||
if (alert_name) {
|
||||
*alert_name_out = alert_name;
|
||||
} else {
|
||||
*alert_name_out = NULL;
|
||||
}
|
||||
} else {
|
||||
*alert_name_out = NULL;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the attributes of a scan layer.
|
||||
*
|
||||
* @param layer The scan layer to query.
|
||||
* @param attributes_out Pointer to a variable to receive the layer attributes.
|
||||
* @return cl_error_t CL_SUCCESS if successful.
|
||||
*/
|
||||
extern cl_error_t cl_scan_layer_get_attributes(
|
||||
cl_scan_layer_t *layer,
|
||||
uint32_t *attributes_out)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
cli_scan_layer_t *l = (cli_scan_layer_t *)layer;
|
||||
|
||||
if (!layer || !attributes_out) {
|
||||
status = CL_ENULLARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*attributes_out = l->attributes;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
52
libclamav/scan_layer.h
Normal file
52
libclamav/scan_layer.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2021-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Valerie Snyder
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __SCAN_LAYER_H_LC
|
||||
#define __SCAN_LAYER_H_LC
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#include "clamav.h"
|
||||
#include "filetypes.h"
|
||||
#include "other_types.h"
|
||||
|
||||
#include "json.h"
|
||||
|
||||
typedef struct cli_scan_layer {
|
||||
cli_file_t type;
|
||||
size_t size;
|
||||
cl_fmap_t *fmap; /* The fmap for this layer. This used to be in an array in the ctx. */
|
||||
uint32_t recursion_level; /* The recursion level of this layer in the scan stack. */
|
||||
uint32_t recursion_level_buffer; /* Which buffer layer in scan recursion. */
|
||||
uint32_t recursion_level_buffer_fmap; /* Which fmap layer in this buffer. */
|
||||
uint32_t attributes; /* layer attributes. */
|
||||
image_fuzzy_hash_t image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */
|
||||
bool calculated_image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */
|
||||
size_t object_id; /* Unique ID for this object. */
|
||||
json_object *metadata_json; /* JSON object for this recursion level, e.g. for JSON metadata. */
|
||||
evidence_t evidence; /* Store signature matches for this layer and its children. */
|
||||
cl_verdict_t verdict; /* Verdict for this layer, e.g. CL_VERDICT_STRONG_INDICATOR, CL_VERDICT_NOTHING_FOUND, CL_VERDICT_TRUSTED. */
|
||||
char *tmpdir; /* The directory to store tmp files created when processing this layer. */
|
||||
struct cli_scan_layer *parent; /* Pointer to the parent layer, if any. */
|
||||
} cli_scan_layer_t;
|
||||
|
||||
#endif /* __SCAN_LAYER_H_LC */
|
2244
libclamav/scanners.c
2244
libclamav/scanners.c
File diff suppressed because it is too large
Load diff
|
@ -74,7 +74,7 @@ cl_error_t cli_scansis(cli_ctx *ctx)
|
|||
|
||||
cli_dbgmsg("in scansis()\n");
|
||||
|
||||
if (!(tmpd = cli_gentemp_with_prefix(ctx->sub_tmpdir, "sis-tmp")))
|
||||
if (!(tmpd = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "sis-tmp")))
|
||||
return CL_ETMPDIR;
|
||||
if (mkdir(tmpd, 0700)) {
|
||||
cli_dbgmsg("SIS: Can't create temporary directory %s\n", tmpd);
|
||||
|
|
|
@ -1110,3 +1110,39 @@ cl_error_t cli_basename(
|
|||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
cl_error_t cli_hexstr_to_bytes(const char *hexstr, size_t hexlen, uint8_t *outbuf)
|
||||
{
|
||||
size_t i;
|
||||
if (!hexstr || !outbuf || (hexlen % 2 != 0)) {
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
for (i = 0; i < hexlen / 2; ++i) {
|
||||
int hi, lo;
|
||||
char c1 = hexstr[2 * i];
|
||||
char c2 = hexstr[2 * i + 1];
|
||||
|
||||
if (!isxdigit((unsigned char)c1) || !isxdigit((unsigned char)c2)) {
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
hi = (c1 >= '0' && c1 <= '9') ? c1 - '0' :
|
||||
(c1 >= 'a' && c1 <= 'f') ? c1 - 'a' + 10 :
|
||||
(c1 >= 'A' && c1 <= 'F') ? c1 - 'A' + 10 : -1;
|
||||
|
||||
lo = (c2 >= '0' && c2 <= '9') ? c2 - '0' :
|
||||
(c2 >= 'a' && c2 <= 'f') ? c2 - 'a' + 10 :
|
||||
(c2 >= 'A' && c2 <= 'F') ? c2 - 'A' + 10 : -1;
|
||||
// clang-format on
|
||||
|
||||
if (hi < 0 || lo < 0) {
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
outbuf[i] = (uint8_t)((hi << 4) | lo);
|
||||
}
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -115,4 +115,14 @@ cl_error_t cli_basename(
|
|||
char **filebase,
|
||||
bool posix_support_backslash_pathsep);
|
||||
|
||||
/**
|
||||
* @brief Convert a hex string to an appropriately sized byte array.
|
||||
*
|
||||
* @param hexstr The input hex string (not null-terminated, length must be even).
|
||||
* @param hexlen The length of the hex string.
|
||||
* @param outbuf The output buffer (must be at least hexlen/2 bytes).
|
||||
* @return CL_SUCCESS on success, CL_EFORMAT on error.
|
||||
*/
|
||||
cl_error_t cli_hexstr_to_bytes(const char *hexstr, size_t hexlen, uint8_t *outbuf);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -135,7 +135,7 @@ static cl_error_t scanzws(cli_ctx *ctx, struct swf_file_hdr *hdr)
|
|||
int fd;
|
||||
size_t n_read;
|
||||
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
cli_errmsg("scanzws: Can't generate temporary file\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ static cl_error_t scancws(cli_ctx *ctx, struct swf_file_hdr *hdr)
|
|||
char *tmpname;
|
||||
int fd;
|
||||
|
||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
cli_errmsg("scancws: Can't generate temporary file\n");
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
*/
|
||||
if (cli_debug_flag) {
|
||||
int fout = -1;
|
||||
char *filename = cli_gentemp(ctx->sub_tmpdir);
|
||||
char *filename = cli_gentemp(ctx->this_layer_tmpdir);
|
||||
char buffer[BUFSIZ];
|
||||
|
||||
if (filename)
|
||||
|
|
|
@ -68,7 +68,7 @@ static cl_error_t writeWholeFile(cli_ctx *ctx, const char *const fileName, const
|
|||
}
|
||||
|
||||
/* Not sure if I care about the name that is actually created. */
|
||||
if (cli_gentempfd_with_prefix(ctx->sub_tmpdir, fileName, &tmpf, &fd) != CL_SUCCESS) {
|
||||
if (cli_gentempfd_with_prefix(ctx->this_layer_tmpdir, fileName, &tmpf, &fd) != CL_SUCCESS) {
|
||||
cli_warnmsg("writeWholeFile: Can't create temp file\n");
|
||||
status = CL_ETMPFILE;
|
||||
goto done;
|
||||
|
|
|
@ -859,7 +859,7 @@ static int arj_read_main_header(arj_metadata_t *metadata)
|
|||
goto done;
|
||||
}
|
||||
if (header_size > HEADERSIZE_MAX) {
|
||||
cli_dbgmsg("arj_read_header: invalid header_size: %u\n ", header_size);
|
||||
cli_dbgmsg("arj_read_header: invalid header_size: %u\n", header_size);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -131,9 +131,9 @@ static cl_error_t unz(
|
|||
}
|
||||
} else {
|
||||
if (ctx->engine->keeptmp && (NULL != original_filename)) {
|
||||
if (!(tempfile = cli_gentemp_with_prefix(ctx->sub_tmpdir, original_filename))) return CL_EMEM;
|
||||
if (!(tempfile = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, original_filename))) return CL_EMEM;
|
||||
} else {
|
||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) return CL_EMEM;
|
||||
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) return CL_EMEM;
|
||||
}
|
||||
}
|
||||
if ((out_file = open(tempfile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) == -1) {
|
||||
|
@ -507,7 +507,7 @@ static inline cl_error_t zdecrypt(
|
|||
snprintf(name, sizeof(name), "%s" PATHSEP "zip.decrypt.%03zu", tmpd, *num_files_unzipped);
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
} else {
|
||||
if (!(tempfile = cli_gentemp_with_prefix(ctx->sub_tmpdir, "zip-decrypt"))) return CL_EMEM;
|
||||
if (!(tempfile = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "zip-decrypt"))) return CL_EMEM;
|
||||
}
|
||||
if ((out_file = open(tempfile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) == -1) {
|
||||
cli_warnmsg("cli_unzip: decrypt - failed to create temporary file %s\n", tempfile);
|
||||
|
@ -541,7 +541,7 @@ static inline cl_error_t zdecrypt(
|
|||
cli_dbgmsg("cli_unzip: decrypt - decrypted %zu bytes to %s\n", total, tempfile);
|
||||
|
||||
/* decrypt data to new fmap -> buffer */
|
||||
if (!(dcypt_map = fmap(out_file, 0, total, NULL))) {
|
||||
if (!(dcypt_map = fmap_new(out_file, 0, total, NULL, tempfile))) {
|
||||
cli_warnmsg("cli_unzip: decrypt - failed to create fmap on decrypted file %s\n", tempfile);
|
||||
ret = CL_EMAP;
|
||||
goto zd_clean;
|
||||
|
@ -549,7 +549,7 @@ static inline cl_error_t zdecrypt(
|
|||
|
||||
if (!(dcypt_zip = fmap_need_off_once(dcypt_map, 0, total))) {
|
||||
cli_warnmsg("cli_unzip: decrypt - failed to acquire buffer on decrypted file %s\n", tempfile);
|
||||
funmap(dcypt_map);
|
||||
fmap_free(dcypt_map);
|
||||
ret = CL_EREAD;
|
||||
goto zd_clean;
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ static inline cl_error_t zdecrypt(
|
|||
num_files_unzipped, ctx, tmpd, zcb, original_filename, true);
|
||||
|
||||
/* clean-up and return */
|
||||
funmap(dcypt_map);
|
||||
fmap_free(dcypt_map);
|
||||
zd_clean:
|
||||
close(out_file);
|
||||
if (!ctx->engine->keeptmp)
|
||||
|
|
|
@ -395,7 +395,7 @@ cl_error_t cli_vba_readdir_new(cli_ctx *ctx, const char *dir, struct uniq *U, co
|
|||
|
||||
*has_macros = *has_macros + 1;
|
||||
|
||||
if ((ret = cli_gentempfd_with_prefix(ctx->sub_tmpdir, "vba_project", tempfile, tempfd)) != CL_SUCCESS) {
|
||||
if ((ret = cli_gentempfd_with_prefix(ctx->this_layer_tmpdir, "vba_project", tempfile, tempfd)) != CL_SUCCESS) {
|
||||
cli_warnmsg("vba_readdir_new: VBA project cannot be dumped to file\n");
|
||||
goto done;
|
||||
}
|
||||
|
@ -1755,7 +1755,7 @@ int cli_scan_ole10(int fd, cli_ctx *ctx)
|
|||
if (!read_uint32(fd, &object_size, FALSE))
|
||||
return CL_CLEAN;
|
||||
}
|
||||
if (!(fullname = cli_gentemp(ctx ? ctx->sub_tmpdir : NULL))) {
|
||||
if (!(fullname = cli_gentemp(ctx ? ctx->this_layer_tmpdir : NULL))) {
|
||||
return CL_EMEM;
|
||||
}
|
||||
ofd = open(fullname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_EXCL,
|
||||
|
@ -1944,7 +1944,7 @@ cli_ppt_vba_read(int ifd, cli_ctx *ctx)
|
|||
const char *ret;
|
||||
|
||||
/* Create a directory to store the extracted OLE2 objects */
|
||||
dir = cli_gentemp_with_prefix(ctx ? ctx->sub_tmpdir : NULL, "ppt-ole2-tmp");
|
||||
dir = cli_gentemp_with_prefix(ctx ? ctx->this_layer_tmpdir : NULL, "ppt-ole2-tmp");
|
||||
if (dir == NULL)
|
||||
return NULL;
|
||||
if (mkdir(dir, 0700)) {
|
||||
|
|
|
@ -129,8 +129,8 @@ static void xar_get_checksum_values(xmlTextReaderPtr reader, unsigned char **cks
|
|||
xmlval = xmlTextReaderConstValue(reader);
|
||||
if (xmlval) {
|
||||
cli_dbgmsg("cli_scanxar: checksum value is %s.\n", xmlval);
|
||||
if (((*hash == XAR_CKSUM_SHA1) && (xmlStrlen(xmlval) == 2 * CLI_HASHLEN_SHA1)) ||
|
||||
((*hash == XAR_CKSUM_MD5) && (xmlStrlen(xmlval) == 2 * CLI_HASHLEN_MD5))) {
|
||||
if (((*hash == XAR_CKSUM_SHA1) && (xmlStrlen(xmlval) == 2 * SHA1_HASH_SIZE)) ||
|
||||
((*hash == XAR_CKSUM_MD5) && (xmlStrlen(xmlval) == 2 * MD5_HASH_SIZE))) {
|
||||
*cksum = xmlStrdup(xmlval);
|
||||
} else {
|
||||
cli_dbgmsg("cli_scanxar: checksum type is unknown or length is invalid.\n");
|
||||
|
@ -311,7 +311,7 @@ static int xar_scan_subdocuments(xmlTextReaderPtr reader, cli_ctx *ctx)
|
|||
|
||||
/* make a file to leave if --leave-temps in effect */
|
||||
if (ctx->engine->keeptmp) {
|
||||
if ((rc = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
if ((rc = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
cli_dbgmsg("cli_scanxar: Can't create temporary file for subdocument.\n");
|
||||
} else {
|
||||
cli_dbgmsg("cli_scanxar: Writing subdoc to temp file %s.\n", tmpname);
|
||||
|
@ -395,10 +395,10 @@ static int xar_hash_check(int hash, const void *result, const void *expected)
|
|||
return 1;
|
||||
switch (hash) {
|
||||
case XAR_CKSUM_SHA1:
|
||||
len = CLI_HASHLEN_SHA1;
|
||||
len = SHA1_HASH_SIZE;
|
||||
break;
|
||||
case XAR_CKSUM_MD5:
|
||||
len = CLI_HASHLEN_MD5;
|
||||
len = MD5_HASH_SIZE;
|
||||
break;
|
||||
case XAR_CKSUM_OTHER:
|
||||
case XAR_CKSUM_NONE:
|
||||
|
@ -519,7 +519,7 @@ int cli_scanxar(cli_ctx *ctx)
|
|||
|
||||
/* make a file to leave if --leave-temps in effect */
|
||||
if (ctx->engine->keeptmp) {
|
||||
if ((rc = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
if ((rc = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
cli_dbgmsg("cli_scanxar: Can't create temporary file for TOC.\n");
|
||||
goto exit_toc;
|
||||
}
|
||||
|
@ -568,7 +568,7 @@ int cli_scanxar(cli_ctx *ctx)
|
|||
|
||||
at = offset + hdr.toc_length_compressed + hdr.size;
|
||||
|
||||
if ((rc = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
if ((rc = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
|
||||
cli_dbgmsg("cli_scanxar: Can't generate temporary file.\n");
|
||||
goto exit_reader;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue