mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
libclamav: Fix scan recursion tracking
Scan recursion is the process of identifying files embedded in other files and then scanning them, recursively. Internally this process is more complex than it may sound because a file may have multiple layers of types before finding a new "file". At present we treat the recursion count in the scanning context as an index into both our fmap list AND our container list. These two lists are conceptually a part of the same thing and should be unified. But what's concerning is that the "recursion level" isn't actually incremented or decremented at the same time that we add a layer to the fmap or container lists but instead is more touchy-feely, increasing when we find a new "file". To account for this shadiness, the size of the fmap and container lists has always been a little longer than our "max scan recursion" limit so we don't accidentally overflow the fmap or container arrays (!). I've implemented a single recursion-stack as an array, similar to before, which includes a pointer to each fmap at each layer, along with the size and type. Push and pop functions add and remove layers whenever a new fmap is added. A boolean argument when pushing indicates if the new layer represents a new buffer or new file (descriptor). A new buffer will reset the "nested fmap level" (described below). This commit also provides a solution for an issue where we detect embedded files more than once during scan recursion. For illustration, imagine a tarball named foo.tar.gz with this structure: | description | type | rec level | nested fmap level | | ------------------------- | ----- | --------- | ----------------- | | foo.tar.gz | GZ | 0 | 0 | | └── foo.tar | TAR | 1 | 0 | | ├── bar.zip | ZIP | 2 | 1 | | │ └── hola.txt | ASCII | 3 | 0 | | └── baz.exe | PE | 2 | 1 | But suppose baz.exe embeds a ZIP archive and a 7Z archive, like this: | description | type | rec level | nested fmap level | | ------------------------- | ----- | --------- | ----------------- | | baz.exe | PE | 0 | 0 | | ├── sfx.zip | ZIP | 1 | 1 | | │ └── hello.txt | ASCII | 2 | 0 | | └── sfx.7z | 7Z | 1 | 1 | | └── world.txt | ASCII | 2 | 0 | (A) If we scan for embedded files at any layer, we may detect: | description | type | rec level | nested fmap level | | ------------------------- | ----- | --------- | ----------------- | | foo.tar.gz | GZ | 0 | 0 | | ├── foo.tar | TAR | 1 | 0 | | │ ├── bar.zip | ZIP | 2 | 1 | | │ │ └── hola.txt | ASCII | 3 | 0 | | │ ├── baz.exe | PE | 2 | 1 | | │ │ ├── sfx.zip | ZIP | 3 | 1 | | │ │ │ └── hello.txt | ASCII | 4 | 0 | | │ │ └── sfx.7z | 7Z | 3 | 1 | | │ │ └── world.txt | ASCII | 4 | 0 | | │ ├── sfx.zip | ZIP | 2 | 1 | | │ │ └── hello.txt | ASCII | 3 | 0 | | │ └── sfx.7z | 7Z | 2 | 1 | | │ └── world.txt | ASCII | 3 | 0 | | ├── sfx.zip | ZIP | 1 | 1 | | └── sfx.7z | 7Z | 1 | 1 | (A) is bad because it scans content more than once. Note that for the GZ layer, it may detect the ZIP and 7Z if the signature hits on the compressed data, which it might, though extracting the ZIP and 7Z will likely fail. The reason the above doesn't happen now is that we restrict embedded type scans for a bunch of archive formats to include GZ and TAR. (B) If we scan for embedded files at the foo.tar layer, we may detect: | description | type | rec level | nested fmap level | | ------------------------- | ----- | --------- | ----------------- | | foo.tar.gz | GZ | 0 | 0 | | └── foo.tar | TAR | 1 | 0 | | ├── bar.zip | ZIP | 2 | 1 | | │ └── hola.txt | ASCII | 3 | 0 | | ├── baz.exe | PE | 2 | 1 | | ├── sfx.zip | ZIP | 2 | 1 | | │ └── hello.txt | ASCII | 3 | 0 | | └── sfx.7z | 7Z | 2 | 1 | | └── world.txt | ASCII | 3 | 0 | (B) is almost right. But we can achieve it easily enough only scanning for embedded content in the current fmap when the "nested fmap level" is 0. The upside is that it should safely detect all embedded content, even if it may think the sfz.zip and sfx.7z are in foo.tar instead of in baz.exe. The biggest risk I can think of affects ZIPs. SFXZIP detection is identical to ZIP detection, which is why we don't allow SFXZIP to be detected if insize of a ZIP. If we only allow embedded type scanning at fmap-layer 0 in each buffer, this will fail to detect the embedded ZIP if the bar.exe was not compressed in foo.zip and if non-compressed files extracted from ZIPs aren't extracted as new buffers: | description | type | rec level | nested fmap level | | ------------------------- | ----- | --------- | ----------------- | | foo.zip | ZIP | 0 | 0 | | └── bar.exe | PE | 1 | 1 | | └── sfx.zip | ZIP | 2 | 2 | Provided that we ensure all files extracted from zips are scanned in new buffers, option (B) should be safe. (C) If we scan for embedded files at the baz.exe layer, we may detect: | description | type | rec level | nested fmap level | | ------------------------- | ----- | --------- | ----------------- | | foo.tar.gz | GZ | 0 | 0 | | └── foo.tar | TAR | 1 | 0 | | ├── bar.zip | ZIP | 2 | 1 | | │ └── hola.txt | ASCII | 3 | 0 | | └── baz.exe | PE | 2 | 1 | | ├── sfx.zip | ZIP | 3 | 1 | | │ └── hello.txt | ASCII | 4 | 0 | | └── sfx.7z | 7Z | 3 | 1 | | └── world.txt | ASCII | 4 | 0 | (C) is right. But it's harder to achieve. For this example we can get it by restricting 7ZSFX and ZIPSFX detection only when scanning an executable. But that may mean losing detection of archives embedded elsewhere. And we'd have to identify allowable container types for each possible embedded type, which would be very difficult. So this commit aims to solve the issue the (B)-way. Note that in all situations, we still have to scan with file typing enabled to determine if we need to reassign the current file type, such as re-identifying a Bzip2 archive as a DMG that happens to be Bzip2- compressed. Detection of DMG and a handful of other types rely on finding data partway through or near the ned of a file before reassigning the entire file as the new type. Other fixes and considerations in this commit: - The utf16 HTML parser has weak error handling, particularly with respect to creating a nested fmap for scanning the ascii decoded file. This commit cleans up the error handling and wraps the nested scan with the recursion-stack push()/pop() for correct recursion tracking. Before this commit, each container layer had a flag to indicate if the container layer is valid. We need something similar so that the cli_recursion_stack_get_*() functions ignore normalized layers. Details... Imagine an LDB signature for HTML content that specifies a ZIP container. If the signature actually alerts on the normalized HTML and you don't ignore normalized layers for the container check, it will appear as though the alert is in an HTML container rather than a ZIP container. This commit accomplishes this with a boolean you set in the scan context before scanning a new layer. Then when the new fmap is created, it will use that flag to set similar flag for the layer. The context flag is reset those that anything after this doesn't have that flag. The flag allows the new recursion_stack_get() function to ignore normalized layers when iterating the stack to return a layer at a requested index, negative or positive. Scanning normalized extracted/normalized javascript and VBA should also use the 'layer is normalized' flag. - This commit also fixes Heuristic.Broken.Executable alert for ELF files to make sure that: A) these only alert if cli_append_virus() returns CL_VIRUS (aka it respects the FP check). B) all broken-executable alerts for ELF only happen if the SCAN_HEURISTIC_BROKEN option is enabled. - This commit also cleans up the error handling in cli_magic_scan_dir(). This was needed so we could correctly apply the layer-is-normalized-flag to all VBA macros extracted to a directory when scanning the directory. - Also fix an issue where exceeding scan maximums wouldn't cause embedded file detection scans to abort. Granted we don't actually want to abort if max filesize or max recursion depth are exceeded... only if max scansize, max files, and max scantime are exceeded. Add 'abort_scan' flag to scan context, to protect against depending on correct error propagation for fatal conditions. Instead, setting this flag in the scan context should guarantee that a fatal condition deep in scan recursion isn't lost which result in more stuff being scanned instead of aborting. This shouldn't be necessary, but some status codes like CL_ETIMEOUT never used to be fatal and it's easier to do this than to verify every parser only returns CL_ETIMEOUT and other "fatal status codes" in fatal conditions. - Remove duplicate is_tar() prototype from filestypes.c and include is_tar.h instead. - Presently we create the fmap hash when creating the fmap. This wastes a bit of CPU if the hash is never needed. Now that we're creating fmap's for all embedded files discovered with file type recognition scans, this is a much more frequent occurence and really slows things down. This commit fixes the issue by only creating fmap hashes as needed. This should not only resolve the perfomance impact of creating fmap's for all embedded files, but also should improve performance in general. - Add allmatch check to the zip parser after the central-header meta match. That way we don't multiple alerts with the same match except in allmatch mode. Clean up error handling in the zip parser a tiny bit. - Fixes to ensure that the scan limits such as scansize, filesize, recursion depth, # of embedded files, and scantime are always reported if AlertExceedsMax (--alert-exceeds-max) is enabled. - Fixed an issue where non-fatal alerts for exceeding scan maximums may mask signature matches later on. I changed it so these alerts use the "possibly unwanted" alert-type and thus only alert if no other alerts were found or if all-match or heuristic-precedence are enabled. - Added the "Heuristics.Limits.Exceeded.*" events to the JSON metadata when the --gen-json feature is enabled. These will show up once under "ParseErrors" the first time a limit is exceeded. In the present implementation, only one limits-exceeded events will be added, so as to prevent a malicious or malformed sample from filling the JSON buffer with millions of events and using a tonne of RAM.
This commit is contained in:
parent
a45bf34802
commit
db013a2bfd
77 changed files with 2453 additions and 1713 deletions
|
@ -367,6 +367,7 @@ int main(int argc, char *argv[])
|
|||
struct cl_engine *engine = cl_engine_new();
|
||||
fmap_t *map = NULL;
|
||||
memset(&cctx, 0, sizeof(cctx));
|
||||
|
||||
if (!engine) {
|
||||
fprintf(stderr, "Unable to create engine\n");
|
||||
optfree(opts);
|
||||
|
@ -394,11 +395,22 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
ctx->ctx = &cctx;
|
||||
cctx.engine = engine;
|
||||
cctx.fmap = cli_calloc(sizeof(fmap_t *), engine->maxreclevel + 2);
|
||||
if (!cctx.fmap) {
|
||||
|
||||
cctx.recursion_stack_size = cctx.engine->max_recursion_level;
|
||||
cctx.recursion_stack = cli_calloc(sizeof(recursion_level_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 - map->nested_offset; /* Realistically nested_offset will be 0,
|
||||
* but taking the diff is the "right" way. */
|
||||
|
||||
cctx.fmap = cctx.recursion_stack[cctx.recursion_level].fmap;
|
||||
|
||||
memset(&dbg_state, 0, sizeof(dbg_state));
|
||||
dbg_state.file = "<libclamav>";
|
||||
dbg_state.line = 0;
|
||||
|
@ -466,7 +478,7 @@ int main(int argc, char *argv[])
|
|||
if (map)
|
||||
funmap(map);
|
||||
cl_engine_free(engine);
|
||||
free(cctx.fmap);
|
||||
free(cctx.recursion_stack);
|
||||
}
|
||||
cli_bytecode_destroy(bc);
|
||||
cli_bytecode_done(&bcs);
|
||||
|
|
|
@ -439,7 +439,7 @@ const struct clam_option __clam_options[] = {
|
|||
|
||||
{"MaxFileSize", "max-filesize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXFILESIZE, NULL, 0, OPT_CLAMD | OPT_MILTER | OPT_CLAMSCAN, "Files/messages larger than this limit won't be scanned. Affects the input\nfile itself as well as files contained inside it (when the input file is\nan archive, a document or some other kind of container).\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "25M"},
|
||||
|
||||
{"MaxRecursion", "max-recursion", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_MAXRECLEVEL, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR\nfile, all files within it will also be scanned. This option specifies how\ndeeply the process should be continued.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "16"},
|
||||
{"MaxRecursion", "max-recursion", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_MAXRECLEVEL, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR\nfile, all files within it will also be scanned. This option specifies how\ndeeply the process should be continued.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "17"},
|
||||
|
||||
{"MaxFiles", "max-files", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_MAXFILES, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Number of files to be scanned within an archive, a document, or any other\ncontainer file.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "10000"},
|
||||
|
||||
|
|
|
@ -556,7 +556,7 @@ Default: 25M
|
|||
\fBMaxRecursion NUMBER\fR
|
||||
Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR file, all files within it will also be scanned. This options specifies how deeply the process should be continued. \fBWarning: setting this limit too high may result in severe damage to the system.\fR
|
||||
.br
|
||||
Default: 16
|
||||
Default: 17
|
||||
.TP
|
||||
\fBMaxFiles NUMBER\fR
|
||||
Number of files to be scanned within an archive, a document, or any other kind of container. \fBWarning: disabling this limit or setting it too high may result in severe damage to the system.\fR
|
||||
|
|
|
@ -220,7 +220,7 @@ Extract and scan at most #n bytes from each archive. The size the archive plus t
|
|||
Extract at most #n files from each scanned file (when this is an archive, a document or another kind of container). This option protects your system against DoS attacks (default: 10000)
|
||||
.TP
|
||||
\fB\-\-max\-recursion=#n\fR
|
||||
Set archive recursion level limit. This option protects your system against DoS attacks (default: 16).
|
||||
Set archive recursion level limit. This option protects your system against DoS attacks (default: 17).
|
||||
.TP
|
||||
\fB\-\-max\-dir\-recursion=#n\fR
|
||||
Maximum depth directories are scanned at (default: 15).
|
||||
|
|
|
@ -542,7 +542,7 @@ Example
|
|||
# file, all files within it will also be scanned. This options specifies how
|
||||
# deeply the process should be continued.
|
||||
# Note: setting this limit too high may result in severe damage to the system.
|
||||
# Default: 16
|
||||
# Default: 17
|
||||
#MaxRecursion 10
|
||||
|
||||
# Number of files to be scanned within an archive, a document, or any other
|
||||
|
|
|
@ -97,7 +97,7 @@ int cli_7unz(cli_ctx *ctx, size_t offset)
|
|||
archiveStream.s.Read = FileInStream_fmap_Read;
|
||||
archiveStream.s.Seek = FileInStream_fmap_Seek;
|
||||
archiveStream.s.curpos = 0;
|
||||
archiveStream.file.fmap = *ctx->fmap;
|
||||
archiveStream.file.fmap = ctx->fmap;
|
||||
|
||||
LookToRead_CreateVTable(&lookStream, False);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ int cli_scanapm(cli_ctx *ctx)
|
|||
}
|
||||
|
||||
/* read driver description map at sector 0 */
|
||||
if (fmap_readn(*ctx->fmap, &ddm, pos, sizeof(ddm)) != sizeof(ddm)) {
|
||||
if (fmap_readn(ctx->fmap, &ddm, pos, sizeof(ddm)) != sizeof(ddm)) {
|
||||
cli_dbgmsg("cli_scanapm: Invalid Apple driver description map\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ int cli_scanapm(cli_ctx *ctx)
|
|||
sectorsize = ddm.blockSize;
|
||||
|
||||
/* size of total file must be described by the ddm */
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
if ((ddm.blockSize * ddm.blockCount) != maplen) {
|
||||
cli_dbgmsg("cli_scanapm: File described %u size does not match %lu actual size\n",
|
||||
(ddm.blockSize * ddm.blockCount), (unsigned long)maplen);
|
||||
|
@ -92,7 +92,7 @@ int cli_scanapm(cli_ctx *ctx)
|
|||
|
||||
/* check for old-school partition map */
|
||||
if (sectorsize == 2048) {
|
||||
if (fmap_readn(*ctx->fmap, &aptable, APM_FALLBACK_SECTOR_SIZE, sizeof(aptable)) != sizeof(aptable)) {
|
||||
if (fmap_readn(ctx->fmap, &aptable, APM_FALLBACK_SECTOR_SIZE, sizeof(aptable)) != sizeof(aptable)) {
|
||||
cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ int cli_scanapm(cli_ctx *ctx)
|
|||
/* read partition table at sector 1 (or after the ddm if old-school) */
|
||||
pos = APM_PTABLE_BLOCK * sectorsize;
|
||||
|
||||
if (fmap_readn(*ctx->fmap, &aptable, pos, sizeof(aptable)) != sizeof(aptable)) {
|
||||
if (fmap_readn(ctx->fmap, &aptable, pos, sizeof(aptable)) != sizeof(aptable)) {
|
||||
cli_dbgmsg("cli_scanapm: Invalid Apple partition table\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ int cli_scanapm(cli_ctx *ctx)
|
|||
for (i = 2; i <= max_prtns; ++i) {
|
||||
/* read partition table entry */
|
||||
pos = i * sectorsize;
|
||||
if (fmap_readn(*ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
|
||||
if (fmap_readn(ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
|
||||
cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ int cli_scanapm(cli_ctx *ctx)
|
|||
apentry.pBlockStart, apentry.pBlockCount, partoff, partsize);
|
||||
|
||||
/* send the partition to cli_magic_scan_nested_fmap_type */
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, (const char *)apentry.name);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, (const char *)apentry.name);
|
||||
if (ret != CL_CLEAN) {
|
||||
if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
|
||||
detection = CL_VIRUS;
|
||||
|
@ -261,7 +261,7 @@ static int apm_partition_intersection(cli_ctx *ctx, struct apm_partition_info *a
|
|||
for (i = 1; i <= max_prtns; ++i) {
|
||||
/* read partition table entry */
|
||||
pos = i * sectorsize;
|
||||
if (fmap_readn(*ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
|
||||
if (fmap_readn(ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
|
||||
cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
|
||||
partition_intersection_list_free(&prtncheck);
|
||||
return CL_EFORMAT;
|
||||
|
|
|
@ -646,7 +646,7 @@ static int ea05(cli_ctx *ctx, const uint8_t *base, char *tmpd)
|
|||
unsigned int files = 0;
|
||||
char tempfile[1024];
|
||||
struct UNP UNP;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
if (!fmap_need_ptr_once(map, base, 16))
|
||||
return CL_CLEAN;
|
||||
|
@ -972,7 +972,7 @@ static int ea06(cli_ctx *ctx, const uint8_t *base, char *tmpd)
|
|||
const char prefixes[] = {'\0', '\0', '@', '$', '\0', '.', '"', '\0'};
|
||||
const char *opers[] = {",", "=", ">", "<", "<>", ">=", "<=", "(", ")", "+", "-", "/", "*", "&", "[", "]", "==", "^", "+=", "-=", "/=", "*=", "&=", "?", ":"};
|
||||
struct UNP UNP;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
/* Useless due to a bug in CRC calculation - LMAO!!1 */
|
||||
/* if (cli_readn(desc, buf, 24)!=24) */
|
||||
|
@ -1499,7 +1499,7 @@ int cli_scanautoit(cli_ctx *ctx, off_t offset)
|
|||
const uint8_t *version;
|
||||
int r;
|
||||
char *tmpd;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
cli_dbgmsg("in scanautoit()\n");
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ static const uint8_t hqxtbl[] = {
|
|||
|
||||
int cli_binhex(cli_ctx *ctx)
|
||||
{
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
const uint8_t *encoded = NULL;
|
||||
uint8_t decoded[BUFSIZ], spare_bits = 0, last_byte = 0, this_byte = 0, offset = 0;
|
||||
size_t enc_done = 0, enc_todo = map->len;
|
||||
|
|
|
@ -165,12 +165,17 @@ static int cli_bytecode_context_reset(struct cli_bc_ctx *ctx)
|
|||
snprintf(fullname, 1024, "%s" PATHSEP "javascript", ctx->jsnormdir);
|
||||
fd = open(fullname, O_RDONLY | O_BINARY);
|
||||
if (fd >= 0) {
|
||||
cctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push().
|
||||
|
||||
ret = cli_scan_desc(fd, cctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL, NULL);
|
||||
if (ret == CL_CLEAN) {
|
||||
if (lseek(fd, 0, SEEK_SET) == -1)
|
||||
cli_dbgmsg("cli_bytecode: call to lseek() has failed\n");
|
||||
else
|
||||
else {
|
||||
cctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push().
|
||||
|
||||
ret = cli_scan_desc(fd, cctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL, NULL);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
@ -2769,7 +2774,7 @@ int cli_bytecode_done(struct cli_all_bc *allbc)
|
|||
int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, fmap_t *map)
|
||||
{
|
||||
ctx->fmap = map;
|
||||
ctx->file_size = map->len + map->offset;
|
||||
ctx->file_size = map->len + map->nested_offset;
|
||||
ctx->hooks.filesize = &ctx->file_size;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2904,9 +2909,9 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c
|
|||
cli_dbgmsg("Bytecode %u unpacked file\n", bc->id);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
cli_dbgmsg("***** Scanning unpacked file ******\n");
|
||||
cctx->recursion++;
|
||||
|
||||
ret = cli_magic_scan_desc(fd, tempfile, cctx, NULL);
|
||||
cctx->recursion--;
|
||||
|
||||
if (!cctx->engine->keeptmp)
|
||||
if (ftruncate(fd, 0) == -1)
|
||||
cli_dbgmsg("ftruncate failed on %d\n", fd);
|
||||
|
|
|
@ -548,13 +548,7 @@ int32_t cli_bcapi_extract_new(struct cli_bc_ctx *ctx, int32_t id)
|
|||
cli_dbgmsg("bytecode: scanning extracted file %s\n", ctx->tempfile);
|
||||
cctx = (cli_ctx *)ctx->ctx;
|
||||
if (cctx) {
|
||||
cctx->recursion++;
|
||||
if (ctx->containertype != CL_TYPE_ANY) {
|
||||
size_t csize = cli_get_container_size(cctx, -2);
|
||||
cli_set_container(cctx, ctx->containertype, csize);
|
||||
}
|
||||
res = cli_magic_scan_desc(ctx->outfd, ctx->tempfile, cctx, NULL);
|
||||
cctx->recursion--;
|
||||
res = cli_magic_scan_desc_type(ctx->outfd, ctx->tempfile, cctx, ctx->containertype, NULL);
|
||||
if (res == CL_VIRUS) {
|
||||
ctx->virname = cli_get_last_virus(cctx);
|
||||
ctx->found = 1;
|
||||
|
|
|
@ -456,7 +456,7 @@ static void printnode(const char *prefix, struct cache_set *cs, struct node *n)
|
|||
printf("NULL\n");
|
||||
}
|
||||
#else
|
||||
#define printnode(a, b, c) (0)
|
||||
#define printnode(a, b, c)
|
||||
#endif
|
||||
|
||||
/* #define PRINT_CHAINS */
|
||||
|
@ -551,7 +551,7 @@ 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 reclevel)
|
||||
static inline int cacheset_lookup(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t recursion_level)
|
||||
{
|
||||
int64_t hash[2];
|
||||
|
||||
|
@ -576,7 +576,15 @@ static inline int cacheset_lookup(struct cache_set *cs, unsigned char *md5, size
|
|||
#ifdef PRINT_CHAINS
|
||||
printchain("after", cs);
|
||||
#endif
|
||||
if (reclevel >= p->minrec)
|
||||
|
||||
// The recursion_level check here to prevent a "clean" result from exceeding max recursion from
|
||||
// causing a false negative if the same file is scanned where the recursion depth is lower.
|
||||
// e.g. if max-rec set to 4 and "file5" is malicious, a scan of file1 should not cause a scan of file3 to be "clean"
|
||||
// root
|
||||
// ├── file1 -> file2 -> file3 -> file4 -> file5
|
||||
// └── file3 -> file4 -> file5
|
||||
// See: https://bugzilla.clamav.net/show_bug.cgi?id=1856
|
||||
if (recursion_level >= p->minrec)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -585,15 +593,15 @@ 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 void cacheset_add(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t reclevel)
|
||||
static inline void cacheset_add(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t recursion_level)
|
||||
{
|
||||
struct node *newnode;
|
||||
int64_t hash[2];
|
||||
|
||||
memcpy(hash, md5, 16);
|
||||
if (splay(hash, size, cs)) {
|
||||
if (cs->root->minrec > reclevel)
|
||||
cs->root->minrec = reclevel;
|
||||
if (cs->root->minrec > recursion_level)
|
||||
cs->root->minrec = recursion_level;
|
||||
return; /* Already there */
|
||||
}
|
||||
|
||||
|
@ -666,7 +674,7 @@ static inline void cacheset_add(struct cache_set *cs, unsigned char *md5, size_t
|
|||
newnode->digest[1] = hash[1];
|
||||
newnode->up = NULL;
|
||||
newnode->size = size;
|
||||
newnode->minrec = reclevel;
|
||||
newnode->minrec = recursion_level;
|
||||
cs->root = newnode;
|
||||
|
||||
ptree("3: %lld\n", hash[1]);
|
||||
|
@ -826,7 +834,7 @@ void cli_cache_destroy(struct cl_engine *engine)
|
|||
}
|
||||
|
||||
/* Looks up an hash in the proper tree */
|
||||
static int cache_lookup_hash(unsigned char *md5, size_t len, struct CACHE *cache, uint32_t reclevel)
|
||||
static int cache_lookup_hash(unsigned char *md5, size_t len, struct CACHE *cache, uint32_t recursion_level)
|
||||
{
|
||||
unsigned int key = getkey(md5);
|
||||
int ret = CL_VIRUS;
|
||||
|
@ -842,7 +850,7 @@ static int cache_lookup_hash(unsigned char *md5, size_t len, struct CACHE *cache
|
|||
|
||||
/* cli_warnmsg("cache_lookup_hash: key is %u\n", key); */
|
||||
|
||||
ret = (cacheset_lookup(&c->cacheset, md5, len, reclevel)) ? CL_CLEAN : CL_VIRUS;
|
||||
ret = (cacheset_lookup(&c->cacheset, md5, len, recursion_level)) ? CL_CLEAN : CL_VIRUS;
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
// if(ret == CL_CLEAN) cli_warnmsg("cached\n");
|
||||
|
@ -865,8 +873,8 @@ void cache_add(unsigned char *md5, size_t size, cli_ctx *ctx)
|
|||
return;
|
||||
}
|
||||
|
||||
level = (*ctx->fmap && (*ctx->fmap)->dont_cache_flag) ? ctx->recursion : 0;
|
||||
if (ctx->found_possibly_unwanted && (level || !ctx->recursion))
|
||||
level = (ctx->fmap && ctx->fmap->dont_cache_flag) ? ctx->recursion_level : 0;
|
||||
if (ctx->found_possibly_unwanted && (level || 0 == ctx->recursion_level))
|
||||
return;
|
||||
if (SCAN_ALLMATCHES && (ctx->num_viruses > 0)) {
|
||||
cli_dbgmsg("cache_add: alert found within same topfile, skipping cache\n");
|
||||
|
@ -956,8 +964,8 @@ cl_error_t cache_check(unsigned char *hash, cli_ctx *ctx)
|
|||
return CL_VIRUS;
|
||||
}
|
||||
|
||||
map = *ctx->fmap;
|
||||
ret = cache_lookup_hash(hash, map->len, ctx->engine->cache, ctx->recursion);
|
||||
map = ctx->fmap;
|
||||
ret = cache_lookup_hash(hash, map->len, ctx->engine->cache, ctx->recursion_level);
|
||||
cli_dbgmsg("cache_check: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], (ret == CL_VIRUS) ? "negative" : "positive");
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ int cli_scancpio_old(cli_ctx *ctx)
|
|||
|
||||
memset(name, 0, sizeof(name));
|
||||
|
||||
while (fmap_readn(*ctx->fmap, &hdr_old, pos, sizeof(hdr_old)) == sizeof(hdr_old)) {
|
||||
while (fmap_readn(ctx->fmap, &hdr_old, pos, sizeof(hdr_old)) == sizeof(hdr_old)) {
|
||||
pos += sizeof(hdr_old);
|
||||
if (!hdr_old.magic && trailer) {
|
||||
ret = CL_SUCCESS;
|
||||
|
@ -130,7 +130,7 @@ int cli_scancpio_old(cli_ctx *ctx)
|
|||
if (hdr_old.namesize) {
|
||||
hdr_namesize = EC16(hdr_old.namesize, conv);
|
||||
namesize = MIN(sizeof(name), hdr_namesize);
|
||||
if (fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) {
|
||||
if (fmap_readn(ctx->fmap, &name, pos, namesize) != namesize) {
|
||||
cli_dbgmsg("cli_scancpio_old: Can't read file name\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ int cli_scancpio_old(cli_ctx *ctx)
|
|||
if (ret == CL_EMAXFILES) {
|
||||
goto leave;
|
||||
} else if (ret == CL_SUCCESS) {
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, fmap_name);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, fmap_name);
|
||||
if (ret == CL_VIRUS) {
|
||||
if (!SCAN_ALLMATCHES)
|
||||
return ret;
|
||||
|
@ -200,7 +200,7 @@ int cli_scancpio_odc(cli_ctx *ctx)
|
|||
|
||||
memset(&hdr_odc, 0, sizeof(hdr_odc));
|
||||
|
||||
while (fmap_readn(*ctx->fmap, &hdr_odc, pos, sizeof(hdr_odc)) == sizeof(hdr_odc)) {
|
||||
while (fmap_readn(ctx->fmap, &hdr_odc, pos, sizeof(hdr_odc)) == sizeof(hdr_odc)) {
|
||||
pos += sizeof(hdr_odc);
|
||||
if (!hdr_odc.magic[0] && trailer)
|
||||
goto leave;
|
||||
|
@ -222,7 +222,7 @@ int cli_scancpio_odc(cli_ctx *ctx)
|
|||
}
|
||||
if (hdr_namesize) {
|
||||
namesize = MIN(sizeof(name), hdr_namesize);
|
||||
if (fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) {
|
||||
if (fmap_readn(ctx->fmap, &name, pos, namesize) != namesize) {
|
||||
cli_dbgmsg("cli_scancpio_odc: Can't read file name\n");
|
||||
ret = CL_EFORMAT;
|
||||
goto leave;
|
||||
|
@ -259,7 +259,7 @@ int cli_scancpio_odc(cli_ctx *ctx)
|
|||
if (ret == CL_EMAXFILES) {
|
||||
goto leave;
|
||||
} else if (ret == CL_SUCCESS) {
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, name);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, name);
|
||||
if (ret == CL_VIRUS) {
|
||||
if (!SCAN_ALLMATCHES)
|
||||
return ret;
|
||||
|
@ -288,7 +288,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc)
|
|||
|
||||
memset(name, 0, 513);
|
||||
|
||||
while (fmap_readn(*ctx->fmap, &hdr_newc, pos, sizeof(hdr_newc)) == sizeof(hdr_newc)) {
|
||||
while (fmap_readn(ctx->fmap, &hdr_newc, pos, sizeof(hdr_newc)) == sizeof(hdr_newc)) {
|
||||
pos += sizeof(hdr_newc);
|
||||
if (!hdr_newc.magic[0] && trailer)
|
||||
goto leave;
|
||||
|
@ -310,7 +310,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc)
|
|||
}
|
||||
if (hdr_namesize) {
|
||||
namesize = MIN(sizeof(name), hdr_namesize);
|
||||
if (fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) {
|
||||
if (fmap_readn(ctx->fmap, &name, pos, namesize) != namesize) {
|
||||
cli_dbgmsg("cli_scancpio_newc: Can't read file name\n");
|
||||
ret = CL_EFORMAT;
|
||||
goto leave;
|
||||
|
@ -352,7 +352,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc)
|
|||
if (ret == CL_EMAXFILES) {
|
||||
goto leave;
|
||||
} else if (ret == CL_SUCCESS) {
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, name);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY, name);
|
||||
if (ret == CL_VIRUS) {
|
||||
if (!SCAN_ALLMATCHES)
|
||||
return ret;
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
|
||||
#define CLI_DEFAULT_BM_OFFMODE_FSIZE 262144
|
||||
|
||||
#define CLI_DEFAULT_TIMELIMIT 120000
|
||||
#define CLI_DEFAULT_MAXSCANSIZE 104857600
|
||||
#define CLI_DEFAULT_MAXFILESIZE 26214400
|
||||
#define CLI_DEFAULT_MAXRECLEVEL 16
|
||||
#define CLI_DEFAULT_TIMELIMIT (1000 * 60 * 2) // 2 minutes
|
||||
#define CLI_DEFAULT_MAXSCANSIZE (1024 * 1024 * 100) // 100 MB
|
||||
#define CLI_DEFAULT_MAXFILESIZE (1024 * 1024 * 25) // 25 MB
|
||||
#define CLI_DEFAULT_MAXRECLEVEL 17
|
||||
#define CLI_DEFAULT_MAXFILES 10000
|
||||
#define CLI_DEFAULT_MIN_CC_COUNT 3
|
||||
#define CLI_DEFAULT_MIN_SSN_COUNT 3
|
||||
|
|
|
@ -113,7 +113,7 @@ int cli_scandmg(cli_ctx *ctx)
|
|||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
if (maplen <= 512) {
|
||||
cli_dbgmsg("cli_scandmg: DMG smaller than DMG koly block!\n");
|
||||
return CL_CLEAN;
|
||||
|
@ -121,7 +121,7 @@ int cli_scandmg(cli_ctx *ctx)
|
|||
pos = maplen - 512;
|
||||
|
||||
/* Grab koly block */
|
||||
if (fmap_readn(*ctx->fmap, &hdr, pos, sizeof(hdr)) != sizeof(hdr)) {
|
||||
if (fmap_readn(ctx->fmap, &hdr, pos, sizeof(hdr)) != sizeof(hdr)) {
|
||||
cli_dbgmsg("cli_scandmg: Invalid DMG trailer block\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ int cli_scandmg(cli_ctx *ctx)
|
|||
}
|
||||
|
||||
/* scan XML with cli_magic_scan_nested_fmap_type */
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, (size_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx, CL_TYPE_ANY, NULL);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, (size_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx, CL_TYPE_ANY, NULL);
|
||||
if (ret != CL_CLEAN) {
|
||||
cli_dbgmsg("cli_scandmg: retcode from scanning TOC xml: %s\n", cl_strerror(ret));
|
||||
if (!ctx->engine->keeptmp)
|
||||
|
@ -189,7 +189,7 @@ int cli_scandmg(cli_ctx *ctx)
|
|||
}
|
||||
|
||||
/* page data from map */
|
||||
outdata = fmap_need_off_once_len(*ctx->fmap, hdr.xmlOffset, hdr.xmlLength, &nread);
|
||||
outdata = fmap_need_off_once_len(ctx->fmap, hdr.xmlOffset, hdr.xmlLength, &nread);
|
||||
if (!outdata || (nread != hdr.xmlLength)) {
|
||||
cli_errmsg("cli_scandmg: Failed getting XML from map, len %d\n", (int)hdr.xmlLength);
|
||||
if (!ctx->engine->keeptmp)
|
||||
|
@ -663,7 +663,7 @@ static int dmg_stripe_store(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mis
|
|||
if (len == 0)
|
||||
return CL_CLEAN;
|
||||
|
||||
obuf = (void *)fmap_need_off_once(*ctx->fmap, off, len);
|
||||
obuf = (void *)fmap_need_off_once(ctx->fmap, off, len);
|
||||
if (!obuf) {
|
||||
cli_warnmsg("dmg_stripe_store: fmap need failed on stripe " STDu32 "\n", index);
|
||||
return CL_EMAP;
|
||||
|
@ -696,7 +696,7 @@ static int dmg_stripe_adc(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_
|
|||
return CL_CLEAN;
|
||||
|
||||
memset(&strm, 0, sizeof(strm));
|
||||
strm.next_in = (uint8_t *)fmap_need_off_once(*ctx->fmap, off, len);
|
||||
strm.next_in = (uint8_t *)fmap_need_off_once(ctx->fmap, off, len);
|
||||
if (!strm.next_in) {
|
||||
cli_warnmsg("dmg_stripe_adc: fmap need failed on stripe " STDu32 "\n", index);
|
||||
return CL_EMAP;
|
||||
|
@ -778,7 +778,7 @@ static int dmg_stripe_inflate(cli_ctx *ctx, int fd, uint32_t index, struct dmg_m
|
|||
return CL_CLEAN;
|
||||
|
||||
memset(&strm, 0, sizeof(strm));
|
||||
strm.next_in = (void *)fmap_need_off_once(*ctx->fmap, off, len);
|
||||
strm.next_in = (void *)fmap_need_off_once(ctx->fmap, off, len);
|
||||
if (!strm.next_in) {
|
||||
cli_warnmsg("dmg_stripe_inflate: fmap need failed on stripe " STDu32 "\n", index);
|
||||
return CL_EMAP;
|
||||
|
@ -890,7 +890,7 @@ static int dmg_stripe_bzip(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish
|
|||
if (strm.avail_in == 0) {
|
||||
size_t next_len = (len > sizeof(obuf)) ? sizeof(obuf) : len;
|
||||
dmg_bzipmsg("dmg_stripe_bzip: off %lu len %lu next_len %lu\n", off, len, next_len);
|
||||
strm.next_in = (void *)fmap_need_off_once(*ctx->fmap, off, next_len);
|
||||
strm.next_in = (void *)fmap_need_off_once(ctx->fmap, off, next_len);
|
||||
if (strm.next_in == NULL) {
|
||||
cli_dbgmsg("dmg_stripe_bzip: expected more stream\n");
|
||||
ret = CL_EMAP;
|
||||
|
@ -1101,7 +1101,7 @@ static int dmg_extract_xml(cli_ctx *ctx, char *dir, struct dmg_koly_block *hdr)
|
|||
int ofd;
|
||||
|
||||
/* Prep TOC XML for output */
|
||||
outdata = fmap_need_off_once_len(*ctx->fmap, hdr->xmlOffset, hdr->xmlLength, &nread);
|
||||
outdata = fmap_need_off_once_len(ctx->fmap, hdr->xmlOffset, hdr->xmlLength, &nread);
|
||||
if (!outdata || (nread != hdr->xmlLength)) {
|
||||
cli_errmsg("cli_scandmg: Failed getting XML from map, len " STDu64 "\n", hdr->xmlLength);
|
||||
return CL_EMAP;
|
||||
|
|
|
@ -1590,7 +1590,7 @@ done:
|
|||
return status;
|
||||
}
|
||||
|
||||
cl_error_t cli_egg_open(fmap_t* map, size_t sfx_offset, void** hArchive, char*** comments, uint32_t* nComments)
|
||||
cl_error_t cli_egg_open(fmap_t* map, void** hArchive, char*** comments, uint32_t* nComments)
|
||||
{
|
||||
cl_error_t status = CL_EPARSE;
|
||||
cl_error_t retval;
|
||||
|
@ -1610,7 +1610,7 @@ cl_error_t cli_egg_open(fmap_t* map, size_t sfx_offset, void** hArchive, char***
|
|||
goto done;
|
||||
}
|
||||
handle->map = map;
|
||||
handle->offset = sfx_offset;
|
||||
handle->offset = 0;
|
||||
|
||||
/*
|
||||
* 1st:
|
||||
|
|
|
@ -61,7 +61,6 @@ typedef struct cl_egg_metadata {
|
|||
*/
|
||||
cl_error_t cli_egg_open(
|
||||
fmap_t* map,
|
||||
size_t sfx_offset,
|
||||
void** hArchive,
|
||||
char*** comments,
|
||||
uint32_t* nComments);
|
||||
|
|
|
@ -127,9 +127,10 @@ static int cli_elf_fileheader(cli_ctx *ctx, fmap_t *map, union elf_file_hdr *fil
|
|||
break;
|
||||
default:
|
||||
cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr->hdr64.e_ident[4]);
|
||||
if (ctx)
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
return CL_VIRUS;
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
/* Need to know to endian convert */
|
||||
|
@ -219,8 +220,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
|
||||
if (phnum > 128) {
|
||||
cli_dbgmsg("ELF: Suspicious number of program headers\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -232,8 +232,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
/* Sanity check */
|
||||
if (phentsize != sizeof(struct elf_program_hdr32)) {
|
||||
cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -267,8 +266,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
cli_dbgmsg("ELF: Possibly broken ELF file\n");
|
||||
}
|
||||
free(program_hdr);
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_BREAK;
|
||||
|
@ -289,8 +287,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
free(program_hdr);
|
||||
if (err) {
|
||||
cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -323,8 +320,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
|
||||
if (phnum > 128) {
|
||||
cli_dbgmsg("ELF: Suspicious number of program headers\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -336,8 +332,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
/* Sanity check */
|
||||
if (phentsize != sizeof(struct elf_program_hdr64)) {
|
||||
cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -371,8 +366,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
cli_dbgmsg("ELF: Possibly broken ELF file\n");
|
||||
}
|
||||
free(program_hdr);
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_BREAK;
|
||||
|
@ -393,8 +387,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
free(program_hdr);
|
||||
if (err) {
|
||||
cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -437,8 +430,7 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
/* Sanity check */
|
||||
if (shentsize != sizeof(struct elf_section_hdr32)) {
|
||||
cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -481,8 +473,7 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
cli_dbgmsg("ELF: Possibly broken ELF file\n");
|
||||
}
|
||||
free(section_hdr);
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_BREAK;
|
||||
|
@ -538,8 +529,7 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
/* Sanity check */
|
||||
if (shentsize != sizeof(struct elf_section_hdr64)) {
|
||||
cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_EFORMAT;
|
||||
|
@ -582,8 +572,7 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
|
|||
cli_dbgmsg("ELF: Possibly broken ELF file\n");
|
||||
}
|
||||
free(section_hdr);
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN) {
|
||||
cli_append_virus(ctx, "Heuristics.Broken.Executable");
|
||||
if (ctx && SCAN_HEURISTIC_BROKEN && (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable"))) {
|
||||
return CL_VIRUS;
|
||||
}
|
||||
return CL_BREAK;
|
||||
|
@ -686,7 +675,7 @@ static void cli_elf_sectionlog(uint32_t sh_type, uint32_t sh_flags)
|
|||
int cli_scanelf(cli_ctx *ctx)
|
||||
{
|
||||
union elf_file_hdr file_hdr;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
int ret;
|
||||
uint8_t conv = 0, is64 = 0;
|
||||
|
||||
|
@ -802,7 +791,7 @@ int cli_scanelf(cli_ctx *ctx)
|
|||
/* ELF header parsing only
|
||||
* Returns 0 on success, -1 on error
|
||||
*/
|
||||
int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
|
||||
int cli_elfheader(cli_ctx *ctx, struct cli_exe_info *elfinfo)
|
||||
{
|
||||
union elf_file_hdr file_hdr;
|
||||
uint8_t conv = 0, is64 = 0;
|
||||
|
@ -816,16 +805,16 @@ int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
|
|||
cli_dbgmsg("cli_elfheader: Assumption Violated: elfinfo->offset != 0\n");
|
||||
}
|
||||
|
||||
ret = cli_elf_fileheader(NULL, map, &file_hdr, &conv, &is64);
|
||||
ret = cli_elf_fileheader(NULL, ctx->fmap, &file_hdr, &conv, &is64);
|
||||
if (ret != CL_CLEAN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Program headers and Entry */
|
||||
if (is64) {
|
||||
ret = cli_elf_ph64(NULL, map, elfinfo, &(file_hdr.hdr64), conv);
|
||||
ret = cli_elf_ph64(NULL, ctx->fmap, elfinfo, &(file_hdr.hdr64), conv);
|
||||
} else {
|
||||
ret = cli_elf_ph32(NULL, map, elfinfo, &(file_hdr.hdr32.hdr), conv);
|
||||
ret = cli_elf_ph32(NULL, ctx->fmap, elfinfo, &(file_hdr.hdr32.hdr), conv);
|
||||
}
|
||||
if (ret != CL_CLEAN) {
|
||||
return -1;
|
||||
|
@ -833,9 +822,9 @@ int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
|
|||
|
||||
/* Section Headers */
|
||||
if (is64) {
|
||||
ret = cli_elf_sh64(NULL, map, elfinfo, &(file_hdr.hdr64), conv);
|
||||
ret = cli_elf_sh64(NULL, ctx->fmap, elfinfo, &(file_hdr.hdr64), conv);
|
||||
} else {
|
||||
ret = cli_elf_sh32(NULL, map, elfinfo, &(file_hdr.hdr32.hdr), conv);
|
||||
ret = cli_elf_sh32(NULL, ctx->fmap, elfinfo, &(file_hdr.hdr32.hdr), conv);
|
||||
}
|
||||
if (ret != CL_CLEAN) {
|
||||
return -1;
|
||||
|
@ -853,7 +842,7 @@ int cli_unpackelf(cli_ctx *ctx)
|
|||
int ndesc;
|
||||
struct cli_bc_ctx *bc_ctx;
|
||||
int ret;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
/* Bytecode BC_ELF_UNPACKER hook */
|
||||
bc_ctx = cli_bytecode_context_alloc();
|
||||
|
|
|
@ -145,7 +145,7 @@ struct elf_section_hdr64 {
|
|||
|
||||
int cli_scanelf(cli_ctx *ctx);
|
||||
|
||||
int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo);
|
||||
int cli_elfheader(cli_ctx *ctx, struct cli_exe_info *elfinfo);
|
||||
|
||||
int cli_unpackelf(cli_ctx *ctx);
|
||||
|
||||
|
|
|
@ -21,15 +21,6 @@
|
|||
#include "execs.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Initialize a struct cli_exe_info so that it's ready to be populated
|
||||
* by the EXE header parsing functions (cli_peheader, cli_elfheader, and
|
||||
* cli_machoheader) and/or cli_exe_info_destroy.
|
||||
*
|
||||
* @param exeinfo a pointer to the struct cli_exe_info to initialize
|
||||
* @param offset the file offset corresponding to the start of the
|
||||
* executable that exeinfo stores information about
|
||||
*/
|
||||
void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset)
|
||||
{
|
||||
|
||||
|
@ -59,12 +50,6 @@ void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset)
|
|||
//cli_hashset_init_noalloc(&(exeinfo->vinfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* Free resources associated with a struct cli_exe_info initialized
|
||||
* via cli_exe_info_init
|
||||
*
|
||||
* @param exeinfo a pointer to the struct cli_exe_info to destroy
|
||||
*/
|
||||
void cli_exe_info_destroy(struct cli_exe_info *exeinfo)
|
||||
{
|
||||
|
||||
|
|
|
@ -161,7 +161,23 @@ struct cli_exe_info {
|
|||
/***************** End PE-specific Section *****************/
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a struct cli_exe_info so that it's ready to be populated
|
||||
* by the EXE header parsing functions (cli_peheader, cli_elfheader, and
|
||||
* cli_machoheader) and/or cli_exe_info_destroy.
|
||||
*
|
||||
* @param exeinfo a pointer to the struct cli_exe_info to initialize
|
||||
* @param offset the file offset corresponding to the start of the
|
||||
* executable that exeinfo stores information about
|
||||
*/
|
||||
void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset);
|
||||
|
||||
/**
|
||||
* Free resources associated with a struct cli_exe_info initialized
|
||||
* via cli_exe_info_init
|
||||
*
|
||||
* @param exeinfo a pointer to the struct cli_exe_info to destroy
|
||||
*/
|
||||
void cli_exe_info_destroy(struct cli_exe_info *exeinfo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "mpool.h"
|
||||
#define UNZIP_PRIVATE
|
||||
#include "unzip.h"
|
||||
#include "is_tar.h"
|
||||
|
||||
// clang-format off
|
||||
static const struct ftmap_s {
|
||||
|
@ -219,8 +220,6 @@ cli_file_t cli_compare_ftm_file(const unsigned char *buf, size_t buflen, const s
|
|||
return cli_texttype(buf, buflen);
|
||||
}
|
||||
|
||||
int is_tar(const unsigned char *buf, unsigned int nbytes);
|
||||
|
||||
/* organize by length, cannot exceed SIZEOF_LOCAL_HEADER */
|
||||
// clang-format off
|
||||
const struct ooxml_ftcodes {
|
||||
|
|
113
libclamav/fmap.c
113
libclamav/fmap.c
|
@ -259,11 +259,12 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char
|
|||
}
|
||||
|
||||
if (offset > 0 || length < map->len) {
|
||||
/* Caller requested a window into the current map, not the whole map */
|
||||
unsigned char hash[16] = {'\0'};
|
||||
/*
|
||||
* Caller requested a window into the current map, not the whole map.
|
||||
*/
|
||||
|
||||
/* Set the new nested offset and (nested) length for the new map */
|
||||
/* can't change offset because then we'd have to discard/move cached
|
||||
/* Note: We can't change offset because then we'd have to discard/move cached
|
||||
* data, instead use nested_offset to reuse the already cached data */
|
||||
duplicate_map->nested_offset += offset;
|
||||
duplicate_map->len = MIN(length, map->len - offset);
|
||||
|
@ -278,19 +279,17 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char
|
|||
duplicate_map->offset, len2);
|
||||
}
|
||||
|
||||
/* Calculate the fmap hash to be used by the FP check later */
|
||||
if (CL_SUCCESS != fmap_get_MD5(hash, duplicate_map)) {
|
||||
cli_warnmsg("fmap_duplicate: failed to get fmap MD5\n");
|
||||
goto done;
|
||||
}
|
||||
memcpy(duplicate_map->maphash, hash, 16);
|
||||
/* This also means the hash will be different.
|
||||
* Clear the have_maphash flag.
|
||||
* It will be calculated when next it is needed. */
|
||||
duplicate_map->have_maphash = false;
|
||||
}
|
||||
|
||||
if (NULL != name) {
|
||||
duplicate_map->name = cli_strdup(name);
|
||||
if (NULL == duplicate_map->name) {
|
||||
free(duplicate_map);
|
||||
return NULL;
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
duplicate_map->name = NULL;
|
||||
|
@ -351,8 +350,6 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
|
|||
cl_fmap_t *m = NULL;
|
||||
int pgsz = cli_getpagesize();
|
||||
|
||||
unsigned char hash[16] = {'\0'};
|
||||
|
||||
if ((off_t)offset < 0 || offset != fmap_align_to(offset, pgsz)) {
|
||||
cli_warnmsg("fmap: attempted mapping with unaligned offset\n");
|
||||
goto done;
|
||||
|
@ -427,13 +424,7 @@ 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 = 1;
|
||||
|
||||
/* Calculate the fmap hash to be used by the FP check later */
|
||||
if (CL_SUCCESS != fmap_get_MD5(hash, m)) {
|
||||
cli_warnmsg("fmap: failed to get MD5\n");
|
||||
goto done;
|
||||
}
|
||||
memcpy(m->maphash, hash, 16);
|
||||
m->have_maphash = false;
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
|
@ -833,13 +824,13 @@ static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len);
|
|||
|
||||
fmap_t *fmap_open_memory(const void *start, size_t len, const char *name)
|
||||
{
|
||||
unsigned char hash[16] = {'\0'};
|
||||
cl_error_t status = CL_ERROR;
|
||||
|
||||
int pgsz = cli_getpagesize();
|
||||
cl_fmap_t *m = cli_calloc(1, sizeof(*m));
|
||||
if (!m) {
|
||||
cli_warnmsg("fmap: map allocation failed\n");
|
||||
return NULL;
|
||||
goto done;
|
||||
}
|
||||
m->data = start;
|
||||
m->len = len;
|
||||
|
@ -853,22 +844,24 @@ fmap_t *fmap_open_memory(const void *start, size_t len, const char *name)
|
|||
m->unneed_off = mem_unneed_off;
|
||||
|
||||
if (NULL != name) {
|
||||
/* Copy the name, if one is given */
|
||||
m->name = cli_strdup(name);
|
||||
if (NULL == m->name) {
|
||||
free(m);
|
||||
return NULL;
|
||||
cli_warnmsg("fmap: failed to duplicate map name\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the fmap hash to be used by the FP check later */
|
||||
if (CL_SUCCESS != fmap_get_MD5(hash, m)) {
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (CL_SUCCESS != status) {
|
||||
if (NULL != m->name) {
|
||||
free(m->name);
|
||||
}
|
||||
free(m);
|
||||
return NULL;
|
||||
m = NULL;
|
||||
}
|
||||
memcpy(m->maphash, hash, 16);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -1071,39 +1064,57 @@ extern void cl_fmap_close(cl_fmap_t *map)
|
|||
funmap(map);
|
||||
}
|
||||
|
||||
cl_error_t fmap_get_MD5(unsigned char *hash, fmap_t *map)
|
||||
cl_error_t fmap_get_MD5(fmap_t *map, unsigned char **hash)
|
||||
{
|
||||
cl_error_t status = CL_ERROR;
|
||||
size_t todo, at = 0;
|
||||
void *hashctx;
|
||||
void *hashctx = NULL;
|
||||
|
||||
todo = map->len;
|
||||
|
||||
hashctx = cl_hash_init("md5");
|
||||
if (!(hashctx)) {
|
||||
cli_errmsg("ctx_get_MD5: error initializing new md5 hash!\n");
|
||||
return CL_ERROR;
|
||||
}
|
||||
|
||||
while (todo) {
|
||||
const void *buf;
|
||||
size_t readme = todo < 1024 * 1024 * 10 ? todo : 1024 * 1024 * 10;
|
||||
|
||||
if (!(buf = fmap_need_off_once(map, at, readme))) {
|
||||
cl_hash_destroy(hashctx);
|
||||
return CL_EREAD;
|
||||
if (!map->have_maphash) {
|
||||
/* Need to calculate the hash */
|
||||
hashctx = cl_hash_init("md5");
|
||||
if (!(hashctx)) {
|
||||
cli_errmsg("fmap_get_MD5: error initializing new md5 hash!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
todo -= readme;
|
||||
at += readme;
|
||||
while (todo) {
|
||||
const void *buf;
|
||||
size_t readme = todo < 1024 * 1024 * 10 ? todo : 1024 * 1024 * 10;
|
||||
|
||||
if (cl_update_hash(hashctx, (void *)buf, readme)) {
|
||||
cl_hash_destroy(hashctx);
|
||||
cli_errmsg("ctx_get_MD5: error reading while generating hash!\n");
|
||||
return CL_EREAD;
|
||||
if (!(buf = fmap_need_off_once(map, at, readme))) {
|
||||
cli_errmsg("fmap_get_MD5: error reading while generating hash!\n");
|
||||
status = CL_EREAD;
|
||||
goto done;
|
||||
}
|
||||
|
||||
todo -= readme;
|
||||
at += readme;
|
||||
|
||||
if (cl_update_hash(hashctx, (void *)buf, readme)) {
|
||||
cli_errmsg("fmap_get_MD5: error calculating hash!\n");
|
||||
status = CL_EREAD;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
cl_finish_hash(hashctx, map->maphash);
|
||||
hashctx = NULL;
|
||||
|
||||
map->have_maphash = true;
|
||||
}
|
||||
|
||||
cl_finish_hash(hashctx, hash);
|
||||
*hash = map->maphash;
|
||||
|
||||
return CL_CLEAN;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
|
||||
if (NULL != hashctx) {
|
||||
cl_hash_destroy(hashctx);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "clamav.h"
|
||||
|
||||
|
@ -80,6 +81,7 @@ struct cl_fmap {
|
|||
HANDLE fh;
|
||||
HANDLE mh;
|
||||
#endif
|
||||
bool have_maphash;
|
||||
unsigned char maphash[16];
|
||||
uint64_t *bitmap;
|
||||
char *name;
|
||||
|
@ -273,6 +275,15 @@ cl_error_t fmap_dump_to_file(fmap_t *map, const char *filepath, const char *tmpd
|
|||
*/
|
||||
int fmap_fd(fmap_t *m);
|
||||
|
||||
cl_error_t fmap_get_MD5(unsigned char *hash, fmap_t *map);
|
||||
/**
|
||||
* @brief Get a pointer to the fmap hash.
|
||||
*
|
||||
* Will calculate the hash if not already previously calculated.
|
||||
*
|
||||
* @param map The map in question.
|
||||
* @param[out] hash A pointer to the hash.
|
||||
* @return cl_error_t CL_SUCCESS if was able to get the hash, else some error.
|
||||
*/
|
||||
cl_error_t fmap_get_MD5(fmap_t *map, unsigned char **hash);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -180,7 +180,7 @@ cl_error_t cli_parsegif(cli_ctx *ctx)
|
|||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
|
||||
/*
|
||||
* Skip the "GIF" Signature and "87a" or "89a" Version.
|
||||
|
|
|
@ -116,7 +116,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
|
|||
|
||||
/* sector size calculation */
|
||||
if (sectorsize == 0) {
|
||||
sectorsize = gpt_detect_size((*ctx->fmap));
|
||||
sectorsize = gpt_detect_size(ctx->fmap);
|
||||
cli_dbgmsg("cli_scangpt: detected %lu sector size\n", (unsigned long)sectorsize);
|
||||
}
|
||||
if (sectorsize == 0) {
|
||||
|
@ -125,7 +125,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
|
|||
}
|
||||
|
||||
/* size of total file must be a multiple of the sector size */
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
if ((maplen % sectorsize) != 0) {
|
||||
cli_dbgmsg("cli_scangpt: File sized %lu is not a multiple of sector size %lu\n",
|
||||
(unsigned long)maplen, (unsigned long)sectorsize);
|
||||
|
@ -145,7 +145,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
|
|||
|
||||
/* read primary gpt header */
|
||||
cli_dbgmsg("cli_scangpt: Using primary GPT header\n");
|
||||
if (fmap_readn(*ctx->fmap, &phdr, pos, sizeof(phdr)) != sizeof(phdr)) {
|
||||
if (fmap_readn(ctx->fmap, &phdr, pos, sizeof(phdr)) != sizeof(phdr)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid primary GPT header\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
|
|||
state = SECONDARY_ONLY;
|
||||
|
||||
/* read secondary gpt header */
|
||||
if (fmap_readn(*ctx->fmap, &shdr, pos, sizeof(shdr)) != sizeof(shdr)) {
|
||||
if (fmap_readn(ctx->fmap, &shdr, pos, sizeof(shdr)) != sizeof(shdr)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
|
|||
state = PRIMARY_ONLY;
|
||||
|
||||
/* check validity of secondary header; still using the primary */
|
||||
if (fmap_readn(*ctx->fmap, &shdr, pos, sizeof(shdr)) != sizeof(shdr)) {
|
||||
if (fmap_readn(ctx->fmap, &shdr, pos, sizeof(shdr)) != sizeof(shdr)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
|
||||
} else if (gpt_validate_header(ctx, shdr, sectorsize)) {
|
||||
cli_dbgmsg("cli_scangpt: Secondary GPT header is invalid\n");
|
||||
|
@ -289,7 +289,7 @@ static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t secto
|
|||
cli_dbgmsg("Partition Entry Count: %u\n", hdr.tableNumEntries);
|
||||
cli_dbgmsg("Partition Entry Size: %u\n", hdr.tableEntrySize);
|
||||
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
|
||||
/* check engine maxpartitions limit */
|
||||
if (hdr.tableNumEntries < ctx->engine->maxpartitions) {
|
||||
|
@ -302,7 +302,7 @@ static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t secto
|
|||
pos = hdr.tableStartLBA * sectorsize;
|
||||
for (i = 0; i < max_prtns; ++i) {
|
||||
/* read in partition entry */
|
||||
if (fmap_readn(*ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
|
||||
if (fmap_readn(ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid GPT partition entry\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t secto
|
|||
/* send the partition to cli_magic_scan_nested_fmap_type */
|
||||
part_off = gpe.firstLBA * sectorsize;
|
||||
part_size = (gpe.lastLBA - gpe.firstLBA + 1) * sectorsize;
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, part_off, part_size, ctx, CL_TYPE_PART_ANY, namestr);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, part_off, part_size, ctx, CL_TYPE_PART_ANY, namestr);
|
||||
if (NULL != namestr) {
|
||||
free(namestr);
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto
|
|||
size_t maplen, ptable_start, ptable_len;
|
||||
unsigned char *ptable;
|
||||
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
|
||||
/* checking header crc32 checksum */
|
||||
crc32_ref = le32_to_host(hdr.headerCRC32);
|
||||
|
@ -468,7 +468,7 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto
|
|||
/** END HEADER CHECKS **/
|
||||
|
||||
/* checking partition table crc32 checksum */
|
||||
ptable = (unsigned char *)fmap_need_off_once((*ctx->fmap), ptable_start, ptable_len);
|
||||
ptable = (unsigned char *)fmap_need_off_once(ctx->fmap, ptable_start, ptable_len);
|
||||
crc32_calc = crc32(0, ptable, ptable_len);
|
||||
if (crc32_calc != hdr.tableCRC32) {
|
||||
cli_dbgmsg("cli_scangpt: GPT partition table checksum mismatch\n");
|
||||
|
@ -490,7 +490,7 @@ static int gpt_check_mbr(cli_ctx *ctx, size_t sectorsize)
|
|||
mbr_base = sectorsize - sizeof(struct mbr_boot_record);
|
||||
pos = (MBR_SECTOR * sectorsize) + mbr_base;
|
||||
|
||||
if (fmap_readn(*ctx->fmap, &pmbr, pos, sizeof(pmbr)) != sizeof(pmbr)) {
|
||||
if (fmap_readn(ctx->fmap, &pmbr, pos, sizeof(pmbr)) != sizeof(pmbr)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid primary MBR header\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -540,17 +540,17 @@ static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize)
|
|||
/* sector size calculation */
|
||||
sectorsize = GPT_DEFAULT_SECTOR_SIZE;
|
||||
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
|
||||
ppos = 1 * sectorsize; /* sector 1 (second sector) is the primary gpt header */
|
||||
spos = maplen - sectorsize; /* last sector is the secondary gpt header */
|
||||
|
||||
/* read in the primary and secondary gpt headers */
|
||||
if (fmap_readn(*ctx->fmap, &phdr, ppos, sizeof(phdr)) != sizeof(phdr)) {
|
||||
if (fmap_readn(ctx->fmap, &phdr, ppos, sizeof(phdr)) != sizeof(phdr)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid primary GPT header\n");
|
||||
return;
|
||||
}
|
||||
if (fmap_readn(*ctx->fmap, &shdr, spos, sizeof(shdr)) != sizeof(shdr)) {
|
||||
if (fmap_readn(ctx->fmap, &shdr, spos, sizeof(shdr)) != sizeof(shdr)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
|
||||
return;
|
||||
}
|
||||
|
@ -591,7 +591,7 @@ static int gpt_partition_intersection(cli_ctx *ctx, struct gpt_header hdr, size_
|
|||
uint32_t max_prtns = 0;
|
||||
int virus_found = 0;
|
||||
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
|
||||
/* convert endian to host to check partition table */
|
||||
hdr.tableStartLBA = le64_to_host(hdr.tableStartLBA);
|
||||
|
@ -609,7 +609,7 @@ static int gpt_partition_intersection(cli_ctx *ctx, struct gpt_header hdr, size_
|
|||
pos = hdr.tableStartLBA * sectorsize;
|
||||
for (i = 0; i < max_prtns; ++i) {
|
||||
/* read in partition entry */
|
||||
if (fmap_readn(*ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
|
||||
if (fmap_readn(ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
|
||||
cli_dbgmsg("cli_scangpt: Invalid GPT partition entry\n");
|
||||
partition_intersection_list_free(&prtncheck);
|
||||
return CL_EFORMAT;
|
||||
|
|
|
@ -138,11 +138,11 @@ static int hfsplus_volumeheader(cli_ctx *ctx, hfsPlusVolumeHeader **header)
|
|||
}
|
||||
|
||||
/* Start with volume header, 512 bytes at offset 1024 */
|
||||
if ((*ctx->fmap)->len < 1536) {
|
||||
if (ctx->fmap->len < 1536) {
|
||||
cli_dbgmsg("hfsplus_volumeheader: too short for HFS+\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
mPtr = fmap_need_off_once(*ctx->fmap, 1024, 512);
|
||||
mPtr = fmap_need_off_once(ctx->fmap, 1024, 512);
|
||||
if (!mPtr) {
|
||||
cli_errmsg("hfsplus_volumeheader: cannot read header from map\n");
|
||||
return CL_EMAP;
|
||||
|
@ -244,7 +244,7 @@ static int hfsplus_readheader(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hfsN
|
|||
cli_errmsg("hfsplus_readheader: %s: invalid headerType %d\n", name, headerType);
|
||||
return CL_EARG;
|
||||
}
|
||||
mPtr = fmap_need_off_once(*ctx->fmap, offset, volHeader->blockSize);
|
||||
mPtr = fmap_need_off_once(ctx->fmap, offset, volHeader->blockSize);
|
||||
if (!mPtr) {
|
||||
cli_dbgmsg("hfsplus_readheader: %s: headerNode is out-of-range\n", name);
|
||||
return CL_EFORMAT;
|
||||
|
@ -400,7 +400,7 @@ static cl_error_t hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader,
|
|||
size_t written;
|
||||
off_t offset = currBlock * volHeader->blockSize;
|
||||
/* move map to next block */
|
||||
mPtr = fmap_need_off_once(*ctx->fmap, offset, volHeader->blockSize);
|
||||
mPtr = fmap_need_off_once(ctx->fmap, offset, volHeader->blockSize);
|
||||
if (!mPtr) {
|
||||
cli_errmsg("hfsplus_scanfile: map error\n");
|
||||
ret = CL_EMAP;
|
||||
|
@ -714,7 +714,7 @@ static int hfsplus_fetch_node(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hfsH
|
|||
readSize = endSize;
|
||||
}
|
||||
|
||||
if (fmap_readn(*ctx->fmap, buff + buffOffset, fileOffset, readSize) != readSize) {
|
||||
if (fmap_readn(ctx->fmap, buff + buffOffset, fileOffset, readSize) != readSize) {
|
||||
cli_dbgmsg("hfsplus_fetch_node: not all bytes read\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
|
|
@ -59,17 +59,17 @@
|
|||
#if HWP5_DEBUG
|
||||
#define hwp5_debug(...) cli_dbgmsg(__VA_ARGS__)
|
||||
#else
|
||||
#define hwp5_debug(...) ;
|
||||
#define hwp5_debug(...) {};
|
||||
#endif
|
||||
#if HWP3_DEBUG
|
||||
#define hwp3_debug(...) cli_dbgmsg(__VA_ARGS__)
|
||||
#else
|
||||
#define hwp3_debug(...) ;
|
||||
#define hwp3_debug(...) {};
|
||||
#endif
|
||||
#if HWPML_DEBUG
|
||||
#define hwpml_debug(...) cli_dbgmsg(__VA_ARGS__)
|
||||
#else
|
||||
#define hwpml_debug(...) ;
|
||||
#define hwpml_debug(...) {};
|
||||
#endif
|
||||
|
||||
typedef cl_error_t (*hwp_cb)(void *cbdata, int fd, const char *filepath, cli_ctx *ctx);
|
||||
|
@ -278,7 +278,7 @@ static char *convert_hstr_to_utf8(const char *begin, size_t sz, const char *pare
|
|||
/*** HWPOLE2 ***/
|
||||
cl_error_t cli_scanhwpole2(cli_ctx *ctx)
|
||||
{
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
uint32_t usize, asize;
|
||||
|
||||
asize = (uint32_t)(map->len - sizeof(usize));
|
||||
|
@ -513,7 +513,7 @@ static inline cl_error_t parsehwp3_docinfo(cli_ctx *ctx, size_t offset, struct h
|
|||
cl_error_t iret;
|
||||
|
||||
//TODO: use fmap_readn?
|
||||
if (!(hwp3_ptr = fmap_need_off_once(*ctx->fmap, offset, HWP3_DOCINFO_SIZE))) {
|
||||
if (!(hwp3_ptr = fmap_need_off_once(ctx->fmap, offset, HWP3_DOCINFO_SIZE))) {
|
||||
cli_errmsg("HWP3.x: Failed to read fmap for hwp docinfo\n");
|
||||
return CL_EMAP;
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ static inline cl_error_t parsehwp3_docsummary(cli_ctx *ctx, size_t offset)
|
|||
if (!SCAN_COLLECT_METADATA)
|
||||
return CL_SUCCESS;
|
||||
|
||||
if (!(hwp3_ptr = fmap_need_off_once(*ctx->fmap, offset, HWP3_DOCSUMMARY_SIZE))) {
|
||||
if (!(hwp3_ptr = fmap_need_off_once(ctx->fmap, offset, HWP3_DOCSUMMARY_SIZE))) {
|
||||
cli_errmsg("HWP3.x: Failed to read fmap for hwp docinfo\n");
|
||||
return CL_EMAP;
|
||||
}
|
||||
|
@ -1518,7 +1518,7 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t
|
|||
cl_error_t ret = CL_SUCCESS;
|
||||
|
||||
uint32_t infoid, infolen;
|
||||
fmap_t *map = (dmap ? dmap : *ctx->fmap);
|
||||
fmap_t *map = (dmap ? dmap : ctx->fmap);
|
||||
int i, count;
|
||||
long long unsigned infoloc = (long long unsigned)(*offset);
|
||||
#if HWP3_DEBUG
|
||||
|
@ -1780,7 +1780,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
|||
} else {
|
||||
hwp3_debug("HWP3.x: Document Content Stream starts @ offset %zu\n", offset);
|
||||
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
dmap = NULL;
|
||||
}
|
||||
|
||||
|
@ -1878,7 +1878,7 @@ cl_error_t cli_scanhwp3(cli_ctx *ctx)
|
|||
|
||||
struct hwp3_docinfo docinfo;
|
||||
size_t offset = 0, new_offset = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
#if HAVE_JSON
|
||||
/*
|
||||
|
@ -1915,7 +1915,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);
|
||||
ret = decompress_and_callback(ctx, ctx->fmap, offset, 0, "HWP3.x", hwp3_cb, NULL);
|
||||
else
|
||||
ret = hwp3_cb(&offset, 0, ctx->sub_filepath, ctx);
|
||||
|
||||
|
@ -2119,7 +2119,7 @@ cl_error_t cli_scanhwpml(cli_ctx *ctx)
|
|||
return CL_ENULLARG;
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
cbdata.map = *ctx->fmap;
|
||||
cbdata.map = ctx->fmap;
|
||||
|
||||
reader = xmlReaderForIO(msxml_read_cb, NULL, &cbdata, "hwpml.xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS);
|
||||
if (!reader) {
|
||||
|
|
|
@ -27,12 +27,6 @@
|
|||
|
||||
static int from_oct(int digs, char *where);
|
||||
|
||||
/*
|
||||
* Return
|
||||
* 0 if the checksum is bad (i.e., probably not a tar archive),
|
||||
* 1 for old UNIX tar file,
|
||||
* 2 for Unix Std (POSIX) tar file.
|
||||
*/
|
||||
int is_tar(const unsigned char *buf, unsigned int nbytes)
|
||||
{
|
||||
union record *header = (union record *)buf;
|
||||
|
|
|
@ -44,4 +44,13 @@ union record {
|
|||
/* The magic field is filled with this if uname and gname are valid. */
|
||||
#define TMAGIC "ustar " /* 7 chars and a null */
|
||||
|
||||
/**
|
||||
* @brief Figure out whether a given buffer is a tar archive.
|
||||
*
|
||||
* @param buf Pointer to the buffer
|
||||
* @param nbytes Size of the buffer
|
||||
* @return int 0 if the checksum is bad (i.e., probably not a tar archive),
|
||||
* 1 for old UNIX tar file,
|
||||
* 2 for Unix Std (POSIX) tar file.
|
||||
*/
|
||||
int is_tar(const unsigned char *buf, unsigned int nbytes);
|
||||
|
|
|
@ -193,7 +193,7 @@ int cli_scanishield_msi(cli_ctx *ctx, off_t off)
|
|||
const uint8_t *buf;
|
||||
unsigned int fcount, scanned = 0;
|
||||
int ret;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
cli_dbgmsg("in ishield-msi\n");
|
||||
if (!(buf = fmap_need_off_once(map, off, 0x20))) {
|
||||
|
@ -362,7 +362,7 @@ int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz)
|
|||
long fsize;
|
||||
off_t coff = off;
|
||||
struct IS_CABSTUFF c = {NULL, -1, 0, 0};
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
unsigned fc = 0;
|
||||
int virus_found = 0;
|
||||
|
||||
|
@ -468,7 +468,7 @@ static int is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize)
|
|||
char *fname;
|
||||
const char *buf;
|
||||
int ofd, ret = CL_CLEAN;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
if (!fsize) {
|
||||
cli_dbgmsg("ishield: skipping empty file\n");
|
||||
|
@ -518,7 +518,7 @@ static int is_parse_hdr(cli_ctx *ctx, struct IS_CABSTUFF *c)
|
|||
unsigned int off, i, scanned = 0;
|
||||
int ret = CL_BREAK;
|
||||
char hash[33], *hdr;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
const struct IS_HDR *h1;
|
||||
struct IS_OBJECTS *objs;
|
||||
|
@ -716,7 +716,7 @@ static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t cs
|
|||
z_stream z;
|
||||
uint64_t outsz = 0;
|
||||
int success = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
if (!(outbuf = cli_malloc(IS_CABBUFSZ))) {
|
||||
cli_errmsg("is_extract_cab: Unable to allocate memory for outbuf\n");
|
||||
|
|
|
@ -45,13 +45,13 @@ static const void *needblock(const iso9660_t *iso, unsigned int block, int temp)
|
|||
cli_ctx *ctx = iso->ctx;
|
||||
size_t loff;
|
||||
unsigned int blocks_per_sect = (2048 / iso->blocksz);
|
||||
if (block > (((*ctx->fmap)->len - iso->base_offset) / iso->sectsz) * blocks_per_sect)
|
||||
if (block > ((ctx->fmap->len - iso->base_offset) / iso->sectsz) * blocks_per_sect)
|
||||
return NULL; /* Block is out of file */
|
||||
loff = (block / blocks_per_sect) * iso->sectsz; /* logical sector */
|
||||
loff += (block % blocks_per_sect) * iso->blocksz; /* logical block within the sector */
|
||||
if (temp)
|
||||
return fmap_need_off_once(*ctx->fmap, iso->base_offset + loff, iso->blocksz);
|
||||
return fmap_need_off(*ctx->fmap, iso->base_offset + loff, iso->blocksz);
|
||||
return fmap_need_off_once(ctx->fmap, iso->base_offset + loff, iso->blocksz);
|
||||
return fmap_need_off(ctx->fmap, iso->base_offset + loff, iso->blocksz);
|
||||
}
|
||||
|
||||
static int iso_scan_file(const iso9660_t *iso, unsigned int block, unsigned int len)
|
||||
|
@ -217,7 +217,7 @@ static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len)
|
|||
dir += entrysz;
|
||||
}
|
||||
|
||||
fmap_unneed_ptr(*ctx->fmap, dir_orig, iso->blocksz);
|
||||
fmap_unneed_ptr(ctx->fmap, dir_orig, iso->blocksz);
|
||||
}
|
||||
if (viruses_found == 1)
|
||||
return CL_VIRUS;
|
||||
|
@ -233,7 +233,7 @@ int cli_scaniso(cli_ctx *ctx, size_t offset)
|
|||
if (offset < 32768)
|
||||
return CL_CLEAN; /* Need 16 sectors at least 2048 bytes long */
|
||||
|
||||
privol = fmap_need_off(*ctx->fmap, offset, 2448 + 6);
|
||||
privol = fmap_need_off(ctx->fmap, offset, 2448 + 6);
|
||||
if (!privol)
|
||||
return CL_CLEAN;
|
||||
|
||||
|
@ -253,7 +253,7 @@ int cli_scaniso(cli_ctx *ctx, size_t offset)
|
|||
iso.joliet = 0;
|
||||
|
||||
for (i = 16; i < 32; i++) { /* scan for a joliet secondary volume descriptor */
|
||||
next = fmap_need_off_once(*ctx->fmap, iso.base_offset + i * iso.sectsz, 2048);
|
||||
next = fmap_need_off_once(ctx->fmap, iso.base_offset + i * iso.sectsz, 2048);
|
||||
if (!next)
|
||||
break; /* Out of disk */
|
||||
if (*next == 0xff || memcmp(next + 1, "CD001", 5))
|
||||
|
@ -283,7 +283,7 @@ int cli_scaniso(cli_ctx *ctx, size_t offset)
|
|||
/* TODO rr, el torito, udf ? */
|
||||
|
||||
/* NOTE: freeing sector now. it is still safe to access as we don't alloc anymore */
|
||||
fmap_unneed_off(*ctx->fmap, offset, 2448);
|
||||
fmap_unneed_off(ctx->fmap, offset, 2448);
|
||||
if (iso.joliet)
|
||||
privol = next;
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ static cl_error_t jpeg_check_photoshop_8bim(cli_ctx *ctx, size_t *off)
|
|||
uint8_t nlength, id[2];
|
||||
uint32_t size;
|
||||
size_t offset = *off;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
if (!(buf = fmap_need_off_once(map, offset, 4 + 2 + 1))) {
|
||||
cli_dbgmsg("read bim failed\n");
|
||||
|
@ -331,7 +331,7 @@ cl_error_t cli_parsejpeg(cli_ctx *ctx)
|
|||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
|
||||
if (fmap_readn(map, buff, offset, 4) != 4)
|
||||
goto done; /* Ignore */
|
||||
|
|
|
@ -33,7 +33,7 @@ cl_error_t cli_json_timeout_cycle_check(cli_ctx *ctx, int *toval)
|
|||
if (SCAN_COLLECT_METADATA) {
|
||||
if (*toval <= 0) {
|
||||
if (cli_checktimelimit(ctx) != CL_SUCCESS) {
|
||||
cli_errmsg("cli_json_timeout_cycle_check: timeout!\n");
|
||||
cli_dbgmsg("cli_json_timeout_cycle_check: timeout!\n");
|
||||
return CL_ETIMEOUT;
|
||||
}
|
||||
(*toval)++;
|
||||
|
|
|
@ -340,7 +340,7 @@ int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
|
|||
int files;
|
||||
int virus_num = 0;
|
||||
struct mspack_name mspack_fmap = {
|
||||
.fmap = *ctx->fmap,
|
||||
.fmap = ctx->fmap,
|
||||
.org = sfx_offset,
|
||||
};
|
||||
struct mspack_system_ex ops_ex;
|
||||
|
@ -448,7 +448,7 @@ int cli_scanmschm(cli_ctx *ctx)
|
|||
int files;
|
||||
int virus_num = 0;
|
||||
struct mspack_name mspack_fmap = {
|
||||
.fmap = *ctx->fmap,
|
||||
.fmap = ctx->fmap,
|
||||
};
|
||||
struct mspack_system_ex ops_ex;
|
||||
memset(&ops_ex, 0, sizeof(struct mspack_system_ex));
|
||||
|
|
|
@ -209,7 +209,7 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
|||
unsigned int arch = 0, ep = 0, err;
|
||||
struct cli_exe_section *sections = NULL;
|
||||
char name[16];
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
ssize_t at;
|
||||
|
||||
if (fileinfo) {
|
||||
|
@ -333,12 +333,12 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
|||
}
|
||||
at += sizeof(load_cmd);
|
||||
/*
|
||||
if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
|
||||
cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
|
||||
free(sections);
|
||||
RETURN_BROKEN;
|
||||
}
|
||||
*/
|
||||
if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
|
||||
cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
|
||||
free(sections);
|
||||
RETURN_BROKEN;
|
||||
}
|
||||
*/
|
||||
load_cmd.cmd = EC32(load_cmd.cmd, conv);
|
||||
if ((m64 && load_cmd.cmd == 0x19) || (!m64 && load_cmd.cmd == 0x01)) { /* LC_SEGMENT */
|
||||
if (m64) {
|
||||
|
@ -511,11 +511,9 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
|||
}
|
||||
}
|
||||
|
||||
int cli_machoheader(fmap_t *map, struct cli_exe_info *fileinfo)
|
||||
int cli_machoheader(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
||||
{
|
||||
cli_ctx ctx;
|
||||
ctx.fmap = ↦
|
||||
return cli_scanmacho(&ctx, fileinfo);
|
||||
return cli_scanmacho(ctx, fileinfo);
|
||||
}
|
||||
|
||||
int cli_scanmacho_unibin(cli_ctx *ctx)
|
||||
|
@ -524,7 +522,7 @@ int cli_scanmacho_unibin(cli_ctx *ctx)
|
|||
struct macho_fat_arch fat_arch;
|
||||
unsigned int conv, i, matcher = 0;
|
||||
int ret = CL_CLEAN;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
ssize_t at;
|
||||
|
||||
if (fmap_readn(map, &fat_header, 0, sizeof(fat_header)) != sizeof(fat_header)) {
|
||||
|
@ -585,7 +583,6 @@ int cli_unpackmacho(cli_ctx *ctx)
|
|||
int ndesc;
|
||||
struct cli_bc_ctx *bc_ctx;
|
||||
int ret;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
|
||||
/* Bytecode BC_MACHO_UNPACKER hook */
|
||||
bc_ctx = cli_bytecode_context_alloc();
|
||||
|
@ -596,7 +593,7 @@ int cli_unpackmacho(cli_ctx *ctx)
|
|||
|
||||
cli_bytecode_context_setctx(bc_ctx, ctx);
|
||||
|
||||
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_MACHO_UNPACKER, map);
|
||||
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_MACHO_UNPACKER, ctx->fmap);
|
||||
switch (ret) {
|
||||
case CL_VIRUS:
|
||||
cli_bytecode_context_destroy(bc_ctx);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "fmap.h"
|
||||
|
||||
int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo);
|
||||
int cli_machoheader(fmap_t *map, struct cli_exe_info *fileinfo);
|
||||
int cli_machoheader(cli_ctx *ctx, struct cli_exe_info *fileinfo);
|
||||
int cli_scanmacho_unibin(cli_ctx *ctx);
|
||||
int cli_unpackmacho(cli_ctx *ctx);
|
||||
|
||||
|
|
|
@ -2395,14 +2395,13 @@ static int ac_special_altexpand(char *hexpr, char *subexpr, uint16_t maxlen, int
|
|||
inline static int ac_special_altstr(const char *hexpr, uint8_t sigopts, struct cli_ac_special *special, struct cli_matcher *root)
|
||||
{
|
||||
char *hexprcpy, *h, *c;
|
||||
int i, ret, num, fixed, slen, len;
|
||||
int i, ret, num, fixed, slen;
|
||||
|
||||
if (!(hexprcpy = cli_strdup(hexpr))) {
|
||||
cli_errmsg("ac_special_altstr: Can't duplicate alternate expression\n");
|
||||
return CL_EDUP;
|
||||
}
|
||||
|
||||
len = strlen(hexpr);
|
||||
num = ac_analyze_expr(hexprcpy, &fixed, &slen);
|
||||
|
||||
if (!sigopts && fixed) {
|
||||
|
|
|
@ -219,12 +219,13 @@ cl_error_t cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const
|
|||
cflags = NULL;
|
||||
}
|
||||
|
||||
if (lsigid)
|
||||
if (lsigid) {
|
||||
pm_dbgmsg("cli_pcre_addpatt: Adding /%s/%s%s triggered on (%s) as subsig %d for lsigid %d\n",
|
||||
pattern, cflags ? " with flags " : "", cflags ? cflags : "", trigger, lsigid[1], lsigid[0]);
|
||||
else
|
||||
} else {
|
||||
pm_dbgmsg("cli_pcre_addpatt: Adding /%s/%s%s triggered on (%s) [no lsigid]\n",
|
||||
pattern, cflags ? " with flags " : "", cflags ? cflags : "", trigger);
|
||||
}
|
||||
|
||||
#ifdef PCRE_BYPASS
|
||||
/* check for trigger bypass */
|
||||
|
@ -342,8 +343,9 @@ cl_error_t cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const
|
|||
pm->flags & CLI_PCRE_GLOBAL ? "CLAMAV_GLOBAL " : "",
|
||||
pm->flags & CLI_PCRE_ROLLING ? "CLAMAV_ROLLING " : "",
|
||||
pm->flags & CLI_PCRE_ENCOMPASS ? "CLAMAV_ENCOMPASS " : "");
|
||||
} else
|
||||
} else {
|
||||
pm_dbgmsg("Matcher: NONE\n");
|
||||
}
|
||||
|
||||
if (pm->pdata.options) {
|
||||
#if USING_PCRE2
|
||||
|
@ -367,8 +369,9 @@ cl_error_t cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const
|
|||
pm->pdata.options & PCRE_DOLLAR_ENDONLY ? "PCRE_DOLLAR_ENDONLY " : "",
|
||||
pm->pdata.options & PCRE_UNGREEDY ? "PCRE_UNGREEDY " : "");
|
||||
#endif
|
||||
} else
|
||||
} else {
|
||||
pm_dbgmsg("Compiler: NONE\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* add metadata to the performance tracker */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "clamav.h"
|
||||
#include "others.h"
|
||||
|
@ -291,7 +292,7 @@ cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t
|
|||
if (!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
|
||||
return ret;
|
||||
|
||||
ret = matcher_run(troot, buffer, length, &virname, acdata ? (acdata[0]) : (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, *ctx->fmap, NULL, NULL, ctx);
|
||||
ret = matcher_run(troot, buffer, length, &virname, acdata ? (acdata[0]) : (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, ctx->fmap, NULL, NULL, ctx);
|
||||
|
||||
if (!acdata)
|
||||
cli_ac_freedata(&mdata);
|
||||
|
@ -311,7 +312,7 @@ cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t
|
|||
if (!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
|
||||
return ret;
|
||||
|
||||
ret = matcher_run(groot, buffer, length, &virname, acdata ? (acdata[1]) : (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, *ctx->fmap, NULL, NULL, ctx);
|
||||
ret = matcher_run(groot, buffer, length, &virname, acdata ? (acdata[1]) : (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, ctx->fmap, NULL, NULL, ctx);
|
||||
|
||||
if (!acdata)
|
||||
cli_ac_freedata(&mdata);
|
||||
|
@ -504,13 +505,6 @@ cl_error_t cli_caloff(const char *offstr, const struct cli_target_info *info, un
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a struct cli_target_info so that it's ready to have its exeinfo
|
||||
* populated by the call to cli_targetinfo and/or destroyed by
|
||||
* cli_targetinfo_destroy.
|
||||
*
|
||||
* @param info a pointer to the struct cli_target_info to initialize
|
||||
*/
|
||||
void cli_targetinfo_init(struct cli_target_info *info)
|
||||
{
|
||||
|
||||
|
@ -521,27 +515,11 @@ void cli_targetinfo_init(struct cli_target_info *info)
|
|||
cli_exe_info_init(&(info->exeinfo), 0);
|
||||
}
|
||||
|
||||
/** Parse the executable headers and, if successful, populate exeinfo
|
||||
*
|
||||
* @param info A structure to populate with info from the exe header. This
|
||||
* MUST be initialized via cli_targetinfo_init prior to calling
|
||||
* @param target the target executable file type. Possible values are:
|
||||
* - 1 - PE32 / PE32+
|
||||
* - 6 - ELF
|
||||
* - 9 - MachO
|
||||
* @param map The fmap_t backing the file being scanned
|
||||
*
|
||||
* @return If target refers to a supported executable file type, the exe header
|
||||
* will be parsed and, if successful, info->status will be set to 1.
|
||||
* If parsing the exe header fails, info->status will be set to -1.
|
||||
* The caller MUST destroy info via a call to cli_targetinfo_destroy
|
||||
* regardless of what info->status is set to.
|
||||
*/
|
||||
void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
|
||||
void cli_targetinfo(struct cli_target_info *info, unsigned int target, cli_ctx *ctx)
|
||||
{
|
||||
int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
|
||||
int (*einfo)(cli_ctx *, struct cli_exe_info *) = NULL;
|
||||
|
||||
info->fsize = map->len;
|
||||
info->fsize = ctx->fmap->len;
|
||||
|
||||
if (target == 1)
|
||||
einfo = cli_pe_targetinfo;
|
||||
|
@ -552,18 +530,12 @@ void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *m
|
|||
else
|
||||
return;
|
||||
|
||||
if (einfo(map, &info->exeinfo))
|
||||
if (einfo(ctx, &info->exeinfo))
|
||||
info->status = -1;
|
||||
else
|
||||
info->status = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free resources associated with a struct cli_target_info initialized
|
||||
* via cli_targetinfo_init
|
||||
*
|
||||
* @param info a pointer to the struct cli_target_info to destroy
|
||||
*/
|
||||
void cli_targetinfo_destroy(struct cli_target_info *info)
|
||||
{
|
||||
|
||||
|
@ -575,17 +547,14 @@ void cli_targetinfo_destroy(struct cli_target_info *info)
|
|||
info->status = 0;
|
||||
}
|
||||
|
||||
cl_error_t cli_checkfp(cli_ctx *ctx)
|
||||
{
|
||||
return cli_checkfp_virus(ctx, NULL, 0);
|
||||
}
|
||||
|
||||
cl_error_t cli_checkfp_virus(cli_ctx *ctx, const char *vname, uint32_t recursion_cnt)
|
||||
cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname)
|
||||
{
|
||||
cl_error_t status = CL_VIRUS;
|
||||
char md5[33];
|
||||
unsigned int 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];
|
||||
|
@ -593,122 +562,137 @@ cl_error_t cli_checkfp_virus(cli_ctx *ctx, const char *vname, uint32_t recursion
|
|||
unsigned char *digest;
|
||||
size_t size;
|
||||
|
||||
if (*(ctx->fmap - recursion_cnt) == NULL) { /* first fmap in the list is always NULL */
|
||||
return CL_VIRUS;
|
||||
}
|
||||
stack_index = (int32_t)ctx->recursion_level;
|
||||
|
||||
digest = (*(ctx->fmap - recursion_cnt))->maphash;
|
||||
size = (*(ctx->fmap - recursion_cnt))->len;
|
||||
while (stack_index >= 0) {
|
||||
map = ctx->recursion_stack[stack_index].fmap;
|
||||
|
||||
if (cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_checkfp(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_checkfp(md5): Found false positive detection (fp sig: %s), size: *\n", virname);
|
||||
return CL_CLEAN;
|
||||
}
|
||||
if (CL_SUCCESS != fmap_get_MD5(map, &digest)) {
|
||||
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;
|
||||
|
||||
if (cli_debug_flag || ctx->engine->cb_hash) {
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(md5 + i * 2, "%02x", digest[i]);
|
||||
md5[32] = 0;
|
||||
cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int)size,
|
||||
vname ? vname : "Name");
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
map = *(ctx->fmap - recursion_cnt); /* traverse backwards in the fmap list by the number of times recurses*/
|
||||
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_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 (cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_checkfp(sha1): Found false positive detection (fp sig: %s)\n", virname);
|
||||
return CL_CLEAN;
|
||||
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 (cli_hm_scan_wild(&shash1[SHA1_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
||||
cli_dbgmsg("cli_checkfp(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_checkfp(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 (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_checkfp(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_checkfp(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_checkfp(sha256): Found .CAB false positive detection via catalog file\n");
|
||||
return CL_CLEAN;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
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 (i = 0; i < SHA256_HASH_SIZE; i++)
|
||||
sprintf((char *)shash256 + i * 2, "%02x", shash256[SHA256_HASH_SIZE + i]);
|
||||
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);
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
} else
|
||||
cli_errmsg("can't compute sha\n!");
|
||||
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);
|
||||
}
|
||||
} else
|
||||
cli_errmsg("can't compute sha\n!");
|
||||
|
||||
ctx->sha_collect = -1;
|
||||
}
|
||||
ctx->sha_collect = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 (ctx->engine->cb_hash)
|
||||
ctx->engine->cb_hash(fmap_fd(ctx->fmap), size, (const unsigned char *)md5, vname ? vname : "noname", ctx->cb_ctx);
|
||||
|
||||
if (ctx->engine->cb_stats_add_sample) {
|
||||
stats_section_t sections;
|
||||
memset(§ions, 0x00, sizeof(stats_section_t));
|
||||
if (ctx->engine->cb_stats_add_sample) {
|
||||
stats_section_t sections;
|
||||
memset(§ions, 0x00, sizeof(stats_section_t));
|
||||
|
||||
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 (!(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", digest, size, §ions, ctx->engine->stats_data);
|
||||
// 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 (sections.sections) {
|
||||
free(sections.sections);
|
||||
if (sections.sections) {
|
||||
free(sections.sections);
|
||||
}
|
||||
}
|
||||
|
||||
stack_index -= 1;
|
||||
}
|
||||
|
||||
return cli_checkfp_virus(ctx, vname, recursion_cnt + 1);
|
||||
return status;
|
||||
}
|
||||
|
||||
static cl_error_t matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
|
||||
|
@ -776,21 +760,40 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t
|
|||
|
||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name)
|
||||
{
|
||||
cl_error_t ret = CL_EMEM;
|
||||
cl_error_t status = CL_CLEAN;
|
||||
int empty;
|
||||
fmap_t *map = *ctx->fmap; /* Store off the parent fmap for easy reference */
|
||||
fmap_t *new_map = NULL;
|
||||
fmap_t *map = ctx->fmap; /* Store off the parent fmap for easy reference */
|
||||
|
||||
ctx->fmap++; /* Perform scan with child fmap */
|
||||
if (NULL != (*ctx->fmap = fmap_check_empty(desc, 0, 0, &empty, name))) {
|
||||
ret = cli_scan_fmap(ctx, ftype, ftonly, ftoffset, acmode, acres, NULL);
|
||||
map->dont_cache_flag = (*ctx->fmap)->dont_cache_flag;
|
||||
funmap(*ctx->fmap);
|
||||
new_map = fmap_check_empty(desc, 0, 0, &empty, name);
|
||||
if (NULL == new_map) {
|
||||
if (!empty) {
|
||||
cli_dbgmsg("cli_scan_desc: Failed to allocate new map for file descriptor scan.\n");
|
||||
status = CL_EMEM;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
ctx->fmap--; /* Restore the parent fmap */
|
||||
|
||||
if (empty)
|
||||
return CL_CLEAN;
|
||||
return ret;
|
||||
status = cli_recursion_stack_push(ctx, new_map, ftype, true); /* Perform scan with child fmap */
|
||||
if (CL_SUCCESS != status) {
|
||||
cli_dbgmsg("cli_scan_desc: Failed to scan fmap.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cli_scan_fmap(ctx, ftype, ftonly, ftoffset, acmode, acres, NULL);
|
||||
|
||||
map->dont_cache_flag = ctx->fmap->dont_cache_flag; /* Set the parent layer's "don't cache" flag to match the child.
|
||||
TODO: This may not be needed since `emax_reached()` should've
|
||||
already done that for us. */
|
||||
|
||||
(void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
|
||||
|
||||
done:
|
||||
if (NULL != new_map) {
|
||||
funmap(new_map);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
|
||||
|
@ -798,13 +801,13 @@ static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
|
|||
uint32_t i, icnt = ac_lsig->tdb.intermediates[0];
|
||||
int32_t j = -1;
|
||||
|
||||
if (ctx->recursion < icnt)
|
||||
if (ctx->recursion_level < icnt)
|
||||
return 0;
|
||||
|
||||
for (i = icnt; i > 0; i--) {
|
||||
if (ac_lsig->tdb.intermediates[i] == CL_TYPE_ANY)
|
||||
continue;
|
||||
if (ac_lsig->tdb.intermediates[i] != cli_get_container_intermediate(ctx, j--))
|
||||
if (ac_lsig->tdb.intermediates[i] != cli_recursion_stack_get_type(ctx, j--))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -812,72 +815,110 @@ static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
|
|||
|
||||
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)
|
||||
{
|
||||
cl_error_t status = CL_CLEAN;
|
||||
unsigned evalcnt = 0;
|
||||
uint64_t evalids = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *new_map = NULL;
|
||||
struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
|
||||
char *exp = ac_lsig->u.logic;
|
||||
char *exp_end = exp + strlen(exp);
|
||||
cl_error_t rc;
|
||||
|
||||
rc = cli_ac_chkmacro(root, acdata, lsid);
|
||||
if (rc != CL_SUCCESS)
|
||||
return rc;
|
||||
status = cli_ac_chkmacro(root, acdata, lsid);
|
||||
if (status != CL_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (cli_ac_chklsig(exp, exp_end, acdata->lsigcnt[lsid], &evalcnt, &evalids, 0) == 1) {
|
||||
if (ac_lsig->tdb.container && ac_lsig->tdb.container[0] != cli_get_container(ctx, -1))
|
||||
return CL_CLEAN;
|
||||
if (ac_lsig->tdb.container && ac_lsig->tdb.container[0] != cli_recursion_stack_get_type(ctx, -2))
|
||||
goto done;
|
||||
if (ac_lsig->tdb.intermediates && !intermediates_eval(ctx, ac_lsig))
|
||||
return CL_CLEAN;
|
||||
if (ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > map->len || ac_lsig->tdb.filesize[1] < map->len))
|
||||
return CL_CLEAN;
|
||||
goto done;
|
||||
if (ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > ctx->fmap->len || ac_lsig->tdb.filesize[1] < ctx->fmap->len))
|
||||
goto done;
|
||||
|
||||
if (ac_lsig->tdb.ep || ac_lsig->tdb.nos) {
|
||||
if (!target_info || target_info->status != 1)
|
||||
return CL_CLEAN;
|
||||
goto done;
|
||||
if (ac_lsig->tdb.ep && (ac_lsig->tdb.ep[0] > target_info->exeinfo.ep || ac_lsig->tdb.ep[1] < target_info->exeinfo.ep))
|
||||
return CL_CLEAN;
|
||||
goto done;
|
||||
if (ac_lsig->tdb.nos && (ac_lsig->tdb.nos[0] > target_info->exeinfo.nsections || ac_lsig->tdb.nos[1] < target_info->exeinfo.nsections))
|
||||
return CL_CLEAN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (hash && ac_lsig->tdb.handlertype) {
|
||||
if (0 != memcmp(ctx->handlertype_hash, hash, 16)) {
|
||||
ctx->recursion++;
|
||||
memcpy(ctx->handlertype_hash, hash, 16);
|
||||
if (cli_magic_scan(ctx, ac_lsig->tdb.handlertype[0]) == CL_VIRUS) {
|
||||
ctx->recursion--;
|
||||
return CL_VIRUS;
|
||||
/*
|
||||
* Create an fmap window into our current fmap using the original offset & length, and rescan as the new type
|
||||
*
|
||||
* TODO: Unsure if creating an fmap is the right move, or if we should rescan with the current fmap as-is,
|
||||
* since it's not really a container so much as it is type reassignment. This new fmap layer protect agains
|
||||
* a possible infinite loop by applying the scan recursion limit, but maybe there's a better way?
|
||||
* Testing with both HandlerType type reassignment sigs + Container/Intermediates sigs should indicate if
|
||||
* a change is needed.
|
||||
*/
|
||||
new_map = fmap_duplicate(ctx->fmap, 0, ctx->fmap->len, ctx->fmap->name);
|
||||
if (NULL == new_map) {
|
||||
status = CL_EMEM;
|
||||
cli_dbgmsg("Failed to duplicate the current fmap for a re-scan as a different type.\n");
|
||||
goto done;
|
||||
}
|
||||
ctx->recursion--;
|
||||
return CL_CLEAN;
|
||||
|
||||
memcpy(ctx->handlertype_hash, hash, 16);
|
||||
|
||||
status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true); /* Perform scan with child fmap */
|
||||
if (CL_SUCCESS != status) {
|
||||
cli_dbgmsg("Failed to re-scan fmap as a new type.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cli_magic_scan(ctx, ac_lsig->tdb.handlertype[0]);
|
||||
|
||||
(void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
|
||||
|
||||
if (CL_VIRUS == status) {
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (ac_lsig->tdb.icongrp1 || ac_lsig->tdb.icongrp2) {
|
||||
if (!target_info || target_info->status != 1)
|
||||
return CL_CLEAN;
|
||||
if (matchicon(ctx, &target_info->exeinfo, ac_lsig->tdb.icongrp1, ac_lsig->tdb.icongrp2) == CL_VIRUS) {
|
||||
if (!target_info || target_info->status != 1) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (CL_VIRUS == matchicon(ctx, &target_info->exeinfo, ac_lsig->tdb.icongrp1, ac_lsig->tdb.icongrp2)) {
|
||||
if (!ac_lsig->bc_idx) {
|
||||
rc = cli_append_virus(ctx, ac_lsig->virname);
|
||||
if (rc != CL_CLEAN)
|
||||
return rc;
|
||||
} else if (cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], map) == CL_VIRUS) {
|
||||
return CL_VIRUS;
|
||||
status = cli_append_virus(ctx, ac_lsig->virname);
|
||||
if (status != CL_CLEAN) {
|
||||
goto done;
|
||||
}
|
||||
} else if (CL_VIRUS == cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], ctx->fmap)) {
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
return CL_CLEAN;
|
||||
goto done;
|
||||
}
|
||||
if (!ac_lsig->bc_idx) {
|
||||
rc = cli_append_virus(ctx, ac_lsig->virname);
|
||||
if (rc != CL_CLEAN)
|
||||
return rc;
|
||||
status = cli_append_virus(ctx, ac_lsig->virname);
|
||||
if (status != CL_CLEAN) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], map) == CL_VIRUS) {
|
||||
return CL_VIRUS;
|
||||
if (CL_VIRUS == cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], ctx->fmap)) {
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
return CL_CLEAN;
|
||||
done:
|
||||
if (NULL != new_map) {
|
||||
free_duplicate_fmap(new_map);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef HAVE_YARA
|
||||
|
@ -890,8 +931,8 @@ static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
|||
(void)hash;
|
||||
|
||||
memset(&context, 0, sizeof(YR_SCAN_CONTEXT));
|
||||
context.fmap = *ctx->fmap;
|
||||
context.file_size = (*ctx->fmap)->len;
|
||||
context.fmap = ctx->fmap;
|
||||
context.file_size = ctx->fmap->len;
|
||||
if (target_info != NULL) {
|
||||
if (target_info->status == 1)
|
||||
context.entry_point = target_info->exeinfo.ep;
|
||||
|
@ -948,14 +989,13 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
|
||||
struct cli_matcher *groot = NULL, *troot = NULL;
|
||||
struct cli_target_info info;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
struct cli_matcher *hdb, *fp;
|
||||
const char *virname;
|
||||
uint32_t viruses_found = 0;
|
||||
void *md5ctx, *sha1ctx, *sha256ctx;
|
||||
|
||||
if (!ctx->engine) {
|
||||
cli_errmsg("cli_scan_desc: engine == NULL\n");
|
||||
cli_errmsg("cli_scan_fmap: engine == NULL\n");
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
|
@ -1008,7 +1048,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
}
|
||||
|
||||
cli_targetinfo_init(&info);
|
||||
cli_targetinfo(&info, i, map);
|
||||
cli_targetinfo(&info, i, ctx);
|
||||
|
||||
if (-1 == info.status) {
|
||||
cli_dbgmsg("cli_scan_fmap: Failed to successfully parse the executable header. "
|
||||
|
@ -1085,7 +1125,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
return ret;
|
||||
}
|
||||
if (troot->bm_offmode) {
|
||||
if (map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
|
||||
if (ctx->fmap->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
|
||||
if ((ret = cli_bm_initoff(troot, &toff, &info))) {
|
||||
if (!ftonly) {
|
||||
cli_ac_freedata(&gdata);
|
||||
|
@ -1125,8 +1165,8 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
|
||||
if (!ftonly && hdb) {
|
||||
if (!refhash) {
|
||||
if (cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_MD5, map->len) ||
|
||||
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] = 1;
|
||||
|
@ -1138,18 +1178,18 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
memcpy(digest[CLI_HASH_MD5], refhash, 16);
|
||||
}
|
||||
|
||||
if (cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) ||
|
||||
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, map->len) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_SHA1)) {
|
||||
compute_hash[CLI_HASH_SHA1] = 1;
|
||||
} else {
|
||||
compute_hash[CLI_HASH_SHA1] = 0;
|
||||
}
|
||||
|
||||
if (cli_hm_have_size(hdb, CLI_HASH_SHA256, map->len) ||
|
||||
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, map->len) ||
|
||||
cli_hm_have_size(fp, CLI_HASH_SHA256, ctx->fmap->len) ||
|
||||
cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
|
||||
compute_hash[CLI_HASH_SHA256] = 1;
|
||||
} else {
|
||||
|
@ -1157,16 +1197,16 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
}
|
||||
}
|
||||
|
||||
while (offset < map->len) {
|
||||
bytes = MIN(map->len - offset, SCANBUFF);
|
||||
if (!(buff = fmap_need_off_once(map, offset, bytes)))
|
||||
while (offset < ctx->fmap->len) {
|
||||
bytes = MIN(ctx->fmap->len - offset, SCANBUFF);
|
||||
if (!(buff = fmap_need_off_once(ctx->fmap, offset, bytes)))
|
||||
break;
|
||||
if (ctx->scanned)
|
||||
*ctx->scanned += bytes / CL_COUNT_PRECISION;
|
||||
|
||||
if (troot) {
|
||||
virname = NULL;
|
||||
ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, map, bm_offmode ? &toff : NULL, &tpoff, ctx);
|
||||
ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, ctx->fmap, bm_offmode ? &toff : NULL, &tpoff, ctx);
|
||||
|
||||
if (virname) {
|
||||
/* virname already appended by matcher_run */
|
||||
|
@ -1193,7 +1233,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
|
||||
if (!ftonly) {
|
||||
virname = NULL;
|
||||
ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, map, NULL, &gpoff, ctx);
|
||||
ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, ctx->fmap, NULL, &gpoff, ctx);
|
||||
|
||||
if (virname) {
|
||||
/* virname already appended by matcher_run */
|
||||
|
@ -1268,7 +1308,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
continue;
|
||||
|
||||
/* Do hash scan */
|
||||
if ((ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
|
||||
if ((ret = cli_hm_scan(digest[hashtype], ctx->fmap->len, &virname, hdb, hashtype)) == CL_VIRUS) {
|
||||
found += 1;
|
||||
}
|
||||
if (!found || SCAN_ALLMATCHES) {
|
||||
|
@ -1281,7 +1321,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct
|
|||
for (hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) {
|
||||
if (!compute_hash[hashtype2])
|
||||
continue;
|
||||
if (cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) {
|
||||
if (cli_hm_scan(digest[hashtype2], ctx->fmap->len, NULL, fp, hashtype2) == CL_VIRUS) {
|
||||
found = 0;
|
||||
ret = CL_CLEAN;
|
||||
break;
|
||||
|
@ -1353,11 +1393,11 @@ cl_error_t cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t
|
|||
cl_error_t ret = CL_CLEAN;
|
||||
|
||||
cli_dbgmsg("CDBNAME:%s:%llu:%s:%llu:%llu:%d:%u:%u:%p\n",
|
||||
cli_ftname(cli_get_container(ctx, -1)), (long long unsigned)fsizec, fname, (long long unsigned)fsizec, (long long unsigned)fsizer,
|
||||
cli_ftname(cli_recursion_stack_get_type(ctx, -1)), (long long unsigned)fsizec, fname, (long long unsigned)fsizec, (long long unsigned)fsizer,
|
||||
encrypted, filepos, res1, res2);
|
||||
|
||||
if (ctx->engine && ctx->engine->cb_meta)
|
||||
if (ctx->engine->cb_meta(cli_ftname(cli_get_container(ctx, -1)), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
|
||||
if (ctx->engine->cb_meta(cli_ftname(cli_recursion_stack_get_type(ctx, -1)), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
|
||||
cli_dbgmsg("inner file blocked by callback: %s\n", fname);
|
||||
|
||||
ret = cli_append_virus(ctx, "Detected.By.Callback");
|
||||
|
@ -1370,7 +1410,7 @@ cl_error_t cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t
|
|||
return CL_CLEAN;
|
||||
|
||||
do {
|
||||
if (cdb->ctype != CL_TYPE_ANY && cdb->ctype != cli_get_container(ctx, -1))
|
||||
if (cdb->ctype != CL_TYPE_ANY && cdb->ctype != cli_recursion_stack_get_type(ctx, -1))
|
||||
continue;
|
||||
|
||||
if (cdb->encrypted != 2 && cdb->encrypted != encrypted)
|
||||
|
@ -1388,7 +1428,7 @@ cl_error_t cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t
|
|||
continue; \
|
||||
}
|
||||
|
||||
CDBRANGE(cdb->csize, cli_get_container_size(ctx, -1));
|
||||
CDBRANGE(cdb->csize, cli_recursion_stack_get_size(ctx, -1));
|
||||
CDBRANGE(cdb->fsizec, fsizec);
|
||||
CDBRANGE(cdb->fsizer, fsizer);
|
||||
CDBRANGE(cdb->filepos, filepos);
|
||||
|
|
|
@ -35,7 +35,21 @@ struct cli_target_info {
|
|||
int status; /* 0 == not initialised, 1 == initialised OK, -1 == error */
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a struct cli_target_info so that it's ready to have its exeinfo
|
||||
* populated by the call to cli_targetinfo and/or destroyed by
|
||||
* cli_targetinfo_destroy.
|
||||
*
|
||||
* @param info a pointer to the struct cli_target_info to initialize
|
||||
*/
|
||||
void cli_targetinfo_init(struct cli_target_info *info);
|
||||
|
||||
/**
|
||||
* Free resources associated with a struct cli_target_info initialized
|
||||
* via cli_targetinfo_init
|
||||
*
|
||||
* @param info a pointer to the struct cli_target_info to destroy
|
||||
*/
|
||||
void cli_targetinfo_destroy(struct cli_target_info *info);
|
||||
|
||||
#include "matcher-ac.h"
|
||||
|
@ -290,11 +304,34 @@ cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_da
|
|||
|
||||
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);
|
||||
|
||||
cl_error_t cli_checkfp(cli_ctx *ctx);
|
||||
cl_error_t cli_checkfp_virus(cli_ctx *ctx, const char *vname, uint32_t recursion_cnt);
|
||||
/**
|
||||
* @brief Determine if an alert is a known false positive, using each fmap in the the ctx->container stack to check MD5, SHA1, and SHA256 hashes.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param vname (Optional) The name of the signature alert.
|
||||
* @return cl_error_t CL_CLEAN If an allow-list hash matches with one of the fmap hashes in the scan recursion stack.
|
||||
* CL_VIRUS If no allow-list hash matches.
|
||||
*/
|
||||
cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname);
|
||||
|
||||
cl_error_t cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, unsigned int filepos, int res1, void *res2);
|
||||
|
||||
void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map);
|
||||
/** Parse the executable headers and, if successful, populate exeinfo
|
||||
*
|
||||
* If target refers to a supported executable file type, the exe header
|
||||
* will be parsed and, if successful, info->status will be set to 1.
|
||||
* If parsing the exe header fails, info->status will be set to -1.
|
||||
* The caller MUST destroy info via a call to cli_targetinfo_destroy
|
||||
* regardless of what info->status is set to.
|
||||
*
|
||||
* @param info A structure to populate with info from the exe header. This
|
||||
* MUST be initialized via cli_targetinfo_init prior to calling
|
||||
* @param target the target executable file type. Possible values are:
|
||||
* - 1 - PE32 / PE32+
|
||||
* - 6 - ELF
|
||||
* - 9 - MachO
|
||||
* @param ctx The current scan context
|
||||
*/
|
||||
void cli_targetinfo(struct cli_target_info *info, unsigned int target, cli_ctx *ctx);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -367,7 +367,7 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
|
|||
char buffer[RFC2821LENGTH + 1];
|
||||
mbox_ctx mctx;
|
||||
size_t at = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
cli_dbgmsg("in mbox()\n");
|
||||
|
||||
|
@ -576,9 +576,15 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
|
|||
break;
|
||||
case MAXREC:
|
||||
retcode = CL_EMAXREC;
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxRecursion"); // Doing this now because it's actually tracking email recursion,-
|
||||
// not fmap recursion, but it still is aborting with stuff not scanned.
|
||||
// Also, we didn't have access to the ctx when this happened earlier.
|
||||
break;
|
||||
case MAXFILES:
|
||||
retcode = CL_EMAXFILES;
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles"); // Doing this now because it's actually tracking email parts,-
|
||||
// not actual files, but it still is aborting with stuff not scanned.
|
||||
// Also, we didn't have access to the ctx when this happened earlier.
|
||||
break;
|
||||
case VIRUS:
|
||||
retcode = CL_VIRUS;
|
||||
|
@ -605,7 +611,6 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
|
|||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
#define READ_STRUCT_BUFFER_LEN 1024
|
||||
typedef struct _ReadStruct {
|
||||
char buffer[READ_STRUCT_BUFFER_LEN + 1];
|
||||
|
@ -1655,12 +1660,13 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re
|
|||
mctx->files);
|
||||
|
||||
/* FIXMELIMITS: this should be better integrated */
|
||||
if (engine->maxreclevel)
|
||||
if (engine->max_recursion_level)
|
||||
/*
|
||||
* This is approximate
|
||||
*/
|
||||
if (recursion_level > engine->maxreclevel) {
|
||||
|
||||
if (recursion_level > engine->max_recursion_level) {
|
||||
// Note: engine->max_recursion_level is re-purposed here out of convenience.
|
||||
// ole2 recursion does not leverage the ctx->recursion_stack stack.
|
||||
cli_dbgmsg("parseEmailBody: hit maximum recursion level (%u)\n", recursion_level);
|
||||
return MAXREC;
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ int cli_mbr_check2(cli_ctx *ctx, size_t sectorsize)
|
|||
mbr_base = sectorsize - sizeof(struct mbr_boot_record);
|
||||
|
||||
/* size of total file must be a multiple of the sector size */
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
if ((maplen % sectorsize) != 0) {
|
||||
cli_dbgmsg("cli_scanmbr: File sized %lu is not a multiple of sector size %lu\n",
|
||||
(unsigned long)maplen, (unsigned long)sectorsize);
|
||||
|
@ -120,7 +120,7 @@ int cli_mbr_check2(cli_ctx *ctx, size_t sectorsize)
|
|||
pos = (MBR_SECTOR * sectorsize) + mbr_base;
|
||||
|
||||
/* read the master boot record */
|
||||
if (fmap_readn(*ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
|
||||
if (fmap_readn(ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
|
||||
cli_dbgmsg("cli_scanmbr: Invalid master boot record\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
|
|||
mbr_base = sectorsize - sizeof(struct mbr_boot_record);
|
||||
|
||||
/* size of total file must be a multiple of the sector size */
|
||||
maplen = (*ctx->fmap)->real_len;
|
||||
maplen = ctx->fmap->len;
|
||||
if ((maplen % sectorsize) != 0) {
|
||||
cli_dbgmsg("cli_scanmbr: File sized %lu is not a multiple of sector size %lu\n",
|
||||
(unsigned long)maplen, (unsigned long)sectorsize);
|
||||
|
@ -169,7 +169,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
|
|||
pos = (MBR_SECTOR * sectorsize) + mbr_base;
|
||||
|
||||
/* read the master boot record */
|
||||
if (fmap_readn(*ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
|
||||
if (fmap_readn(ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
|
||||
cli_dbgmsg("cli_scanmbr: Invalid master boot record\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
|
|||
}
|
||||
|
||||
/* MBR is valid, examine bootstrap code */
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, 0, sectorsize, ctx, CL_TYPE_ANY, NULL);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, 0, sectorsize, ctx, CL_TYPE_ANY, NULL);
|
||||
if (ret != CL_CLEAN) {
|
||||
if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
|
||||
detection = CL_VIRUS;
|
||||
|
@ -240,7 +240,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
|
|||
partoff = mbr.entries[i].firstLBA * sectorsize;
|
||||
partsize = mbr.entries[i].numLBA * sectorsize;
|
||||
mbr_parsemsg("cli_magic_scan_nested_fmap_type: [%u, +%u)\n", partoff, partsize);
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL);
|
||||
if (ret != CL_CLEAN) {
|
||||
if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
|
||||
detection = CL_VIRUS;
|
||||
|
@ -278,7 +278,7 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extlba, siz
|
|||
|
||||
/* read the extended boot record */
|
||||
pos += (logiclba * sectorsize) + mbr_base;
|
||||
if (fmap_readn(*ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
|
||||
if (fmap_readn(ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
|
||||
cli_dbgmsg("cli_scanebr: Invalid extended boot record\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extlba, siz
|
|||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
ret = cli_magic_scan_nested_fmap_type(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL);
|
||||
ret = cli_magic_scan_nested_fmap_type(ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL);
|
||||
if (ret != CL_CLEAN) {
|
||||
if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
|
||||
detection = CL_VIRUS;
|
||||
|
@ -560,7 +560,7 @@ static int mbr_extended_partition_intersection(cli_ctx *ctx, unsigned *prtncount
|
|||
|
||||
/* read the extended boot record */
|
||||
pos += (logiclba * sectorsize) + mbr_base;
|
||||
if (fmap_readn(*ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
|
||||
if (fmap_readn(ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
|
||||
cli_dbgmsg("cli_scanebr: Invalid extended boot record\n");
|
||||
partition_intersection_list_free(&prtncheck);
|
||||
return CL_EFORMAT;
|
||||
|
|
|
@ -101,7 +101,7 @@ cl_error_t cli_msexpand(cli_ctx *ctx, int ofd)
|
|||
const unsigned char *rbuff = NULL; // rbuff will be set to a real address by READBYTES
|
||||
// in the first iteration of the loop.
|
||||
unsigned int j = B_SIZE - 16, k, l, r = 0, w = 0, rbytes = 0, wbytes = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
off_t cur_off = sizeof(*hdr);
|
||||
unsigned int fsize;
|
||||
size_t ret;
|
||||
|
|
|
@ -238,7 +238,7 @@ cl_error_t cli_scanmsxml(cli_ctx *ctx)
|
|||
return CL_ENULLARG;
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
cbdata.map = *ctx->fmap;
|
||||
cbdata.map = ctx->fmap;
|
||||
|
||||
reader = xmlReaderForIO(msxml_read_cb, NULL, &cbdata, "msxml.xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS);
|
||||
if (!reader) {
|
||||
|
|
|
@ -656,7 +656,7 @@ int cli_msxml_parse_document(cli_ctx *ctx, xmlTextReaderPtr reader, const struct
|
|||
#endif
|
||||
|
||||
/* non-critical return suppression */
|
||||
if (ret == CL_ETIMEOUT || ret == CL_BREAK)
|
||||
if (ret == CL_BREAK)
|
||||
ret = CL_SUCCESS;
|
||||
|
||||
/* important but non-critical suppression */
|
||||
|
|
|
@ -529,7 +529,7 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset)
|
|||
return CL_ETMPDIR;
|
||||
}
|
||||
|
||||
nsist.map = *ctx->fmap;
|
||||
nsist.map = ctx->fmap;
|
||||
if (ctx->engine->keeptmp) cli_dbgmsg("NSIS: Extracting files to %s\n", nsist.dir);
|
||||
|
||||
do {
|
||||
|
@ -557,7 +557,7 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset)
|
|||
}
|
||||
} while (ret == CL_SUCCESS);
|
||||
|
||||
if (ret == CL_BREAK || ret == CL_EMAXFILES)
|
||||
if (ret == CL_BREAK)
|
||||
ret = CL_CLEAN;
|
||||
|
||||
nsis_shutdown(&nsist);
|
||||
|
|
|
@ -181,11 +181,11 @@ ole2_list_size(ole2_list_t *list)
|
|||
|
||||
int ole2_list_push(ole2_list_t *list, uint32_t val)
|
||||
{
|
||||
ole2_list_node_t * new_node = NULL;
|
||||
int status = CL_EMEM;
|
||||
ole2_list_node_t *new_node = NULL;
|
||||
int status = CL_EMEM;
|
||||
|
||||
CLI_MALLOC(new_node, sizeof(ole2_list_node_t),
|
||||
cli_dbgmsg("OLE2: could not allocate new node for worklist!\n"));
|
||||
CLI_MALLOC(new_node, sizeof(ole2_list_node_t),
|
||||
cli_dbgmsg("OLE2: could not allocate new node for worklist!\n"));
|
||||
|
||||
new_node->Val = val;
|
||||
new_node->Next = list->Head;
|
||||
|
@ -239,13 +239,13 @@ char *
|
|||
cli_ole2_get_property_name2(const char *name, int size)
|
||||
{
|
||||
int i, j;
|
||||
char * newname = NULL;
|
||||
char *newname = NULL;
|
||||
|
||||
if ((name[0] == 0 && name[1] == 0) || size <= 0 || size > 128) {
|
||||
return NULL;
|
||||
}
|
||||
CLI_MALLOC(newname, size*7,
|
||||
cli_errmsg("OLE2 [cli_ole2_get_property_name2]: Unable to allocate memory for newname: %u\n", size * 7));
|
||||
CLI_MALLOC(newname, size * 7,
|
||||
cli_errmsg("OLE2 [cli_ole2_get_property_name2]: Unable to allocate memory for newname: %u\n", size * 7));
|
||||
|
||||
j = 0;
|
||||
/* size-2 to ignore trailing NULL */
|
||||
|
@ -284,16 +284,16 @@ get_property_name(char *name, int size)
|
|||
{
|
||||
const char *carray = "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz._";
|
||||
int csize = size >> 1;
|
||||
char * newname = NULL;
|
||||
char * cname = NULL;
|
||||
char *oname = name;
|
||||
char *newname = NULL;
|
||||
char *cname = NULL;
|
||||
char *oname = name;
|
||||
|
||||
if (csize <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CLI_MALLOC(newname, size,
|
||||
cli_errmsg("OLE2 [get_property_name]: Unable to allocate memory for newname %u\n", size));
|
||||
CLI_MALLOC(newname, size,
|
||||
cli_errmsg("OLE2 [get_property_name]: Unable to allocate memory for newname %u\n", size));
|
||||
cname = newname;
|
||||
|
||||
while (--csize) {
|
||||
|
@ -594,10 +594,15 @@ static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t
|
|||
if ((rec_level > 100) || (*file_count > 100000)) {
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
if (ctx && ctx->engine->maxreclevel && (rec_level > ctx->engine->maxreclevel)) {
|
||||
cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", ctx->engine->maxreclevel);
|
||||
return CL_SUCCESS;
|
||||
|
||||
if (ctx && ctx->engine->max_recursion_level && (rec_level > ctx->engine->max_recursion_level)) {
|
||||
// Note: engine->max_recursion_level is re-purposed here out of convenience.
|
||||
// ole2 recursion does not leverage the ctx->recursion_stack stack.
|
||||
cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", ctx->engine->max_recursion_level);
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxRecursion");
|
||||
return CL_EMAXREC;
|
||||
}
|
||||
|
||||
//push the 'root' node for the level onto the local list
|
||||
if ((ret = ole2_list_push(&node_list, prop_index)) != CL_SUCCESS) {
|
||||
ole2_list_delete(&node_list);
|
||||
|
@ -707,6 +712,7 @@ static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t
|
|||
ole2_listmsg("file node\n");
|
||||
if (ctx && ctx->engine->maxfiles && ((*file_count > ctx->engine->maxfiles) || (ctx->scannedfiles > ctx->engine->maxfiles - *file_count))) {
|
||||
cli_dbgmsg("OLE2: files limit reached (max: %u)\n", ctx->engine->maxfiles);
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles");
|
||||
ole2_list_delete(&node_list);
|
||||
return CL_EMAXFILES;
|
||||
}
|
||||
|
@ -828,14 +834,14 @@ static cl_error_t handler_writefile(ole2_header_t *hdr, property_t *prop, const
|
|||
{
|
||||
cl_error_t ret = CL_BREAK;
|
||||
char newname[1024];
|
||||
char* name = NULL;
|
||||
unsigned char * buff = NULL;
|
||||
char *name = NULL;
|
||||
unsigned char *buff = NULL;
|
||||
int32_t current_block = 0;
|
||||
size_t len = 0, offset = 0;
|
||||
int ofd = -1;
|
||||
char* hash = NULL;
|
||||
bitset_t* blk_bitset = NULL;
|
||||
uint32_t cnt = 0;
|
||||
int ofd = -1;
|
||||
char *hash = NULL;
|
||||
bitset_t *blk_bitset = NULL;
|
||||
uint32_t cnt = 0;
|
||||
|
||||
UNUSEDPARAM(ctx);
|
||||
|
||||
|
@ -879,9 +885,9 @@ static cl_error_t handler_writefile(ole2_header_t *hdr, property_t *prop, const
|
|||
current_block = prop->start_block;
|
||||
len = prop->size;
|
||||
|
||||
CLI_MALLOC(buff, 1 << hdr->log2_big_block_size,
|
||||
cli_errmsg("OLE2 [handler_writefile]: Unable to allocate memory for buff: %u\n", 1 << hdr->log2_big_block_size);
|
||||
ret = CL_EMEM);
|
||||
CLI_MALLOC(buff, 1 << hdr->log2_big_block_size,
|
||||
cli_errmsg("OLE2 [handler_writefile]: Unable to allocate memory for buff: %u\n", 1 << hdr->log2_big_block_size);
|
||||
ret = CL_EMEM);
|
||||
|
||||
blk_bitset = cli_bitset_init();
|
||||
if (!blk_bitset) {
|
||||
|
@ -1131,11 +1137,11 @@ static cl_error_t scan_biff_for_xlm_macros_and_images(
|
|||
*/
|
||||
static cl_error_t scan_for_xlm_macros_and_images(ole2_header_t *hdr, property_t *prop, cli_ctx *ctx, bool *found_macro, bool *found_image)
|
||||
{
|
||||
cl_error_t status = CL_EPARSE;
|
||||
unsigned char * buff = NULL;
|
||||
cl_error_t status = CL_EPARSE;
|
||||
unsigned char *buff = NULL;
|
||||
int32_t current_block = 0;
|
||||
size_t len = 0, offset = 0;
|
||||
bitset_t * blk_bitset = NULL;
|
||||
bitset_t *blk_bitset = NULL;
|
||||
struct biff_parser_state state = {0};
|
||||
|
||||
if (prop->type != 2) {
|
||||
|
@ -1148,9 +1154,9 @@ static cl_error_t scan_for_xlm_macros_and_images(ole2_header_t *hdr, property_t
|
|||
current_block = prop->start_block;
|
||||
len = prop->size;
|
||||
|
||||
CLI_MALLOC(buff, 1 << hdr->log2_big_block_size,
|
||||
cli_errmsg("OLE2 [scan_for_xlm_macros_and_images]: Unable to allocate memory for buff: %u\n", 1 << hdr->log2_big_block_size);
|
||||
status = CL_EMEM);
|
||||
CLI_MALLOC(buff, 1 << hdr->log2_big_block_size,
|
||||
cli_errmsg("OLE2 [scan_for_xlm_macros_and_images]: Unable to allocate memory for buff: %u\n", 1 << hdr->log2_big_block_size);
|
||||
status = CL_EMEM);
|
||||
|
||||
blk_bitset = cli_bitset_init();
|
||||
if (!blk_bitset) {
|
||||
|
@ -1206,7 +1212,6 @@ done:
|
|||
return status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief enum file Handler - checks for VBA presence
|
||||
*
|
||||
|
@ -1218,13 +1223,13 @@ done:
|
|||
*/
|
||||
static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
|
||||
{
|
||||
cl_error_t status = CL_EREAD;
|
||||
char* name = NULL;
|
||||
unsigned char * hwp_check = NULL;
|
||||
int32_t offset = 0;
|
||||
cl_error_t status = CL_EREAD;
|
||||
char *name = NULL;
|
||||
unsigned char *hwp_check = NULL;
|
||||
int32_t offset = 0;
|
||||
#if HAVE_JSON
|
||||
json_object* arrobj = NULL;
|
||||
json_object* strmobj = NULL;
|
||||
json_object *arrobj = NULL;
|
||||
json_object *strmobj = NULL;
|
||||
|
||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||
if (name) {
|
||||
|
@ -1319,7 +1324,6 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
|||
hdr->is_hwp = hwp_new;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1517,15 +1521,15 @@ mso_end:
|
|||
|
||||
static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
|
||||
{
|
||||
cl_error_t ret = CL_BREAK;
|
||||
char* tempfile = NULL;
|
||||
char * name = NULL;
|
||||
unsigned char * buff = NULL;
|
||||
cl_error_t ret = CL_BREAK;
|
||||
char *tempfile = NULL;
|
||||
char *name = NULL;
|
||||
unsigned char *buff = NULL;
|
||||
int32_t current_block = 0;
|
||||
size_t len = 0, offset = 0;
|
||||
int ofd = -1;
|
||||
int is_mso = 0;
|
||||
bitset_t * blk_bitset = NULL;
|
||||
int ofd = -1;
|
||||
int is_mso = 0;
|
||||
bitset_t *blk_bitset = NULL;
|
||||
|
||||
UNUSEDPARAM(dir);
|
||||
|
||||
|
@ -1804,10 +1808,10 @@ cl_error_t cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **fil
|
|||
sizeof(bool) - // has_image
|
||||
sizeof(hwp5_header_t *); // is_hwp
|
||||
|
||||
if ((size_t)((*ctx->fmap)->len) < (size_t)(hdr_size)) {
|
||||
if ((size_t)(ctx->fmap->len) < (size_t)(hdr_size)) {
|
||||
return CL_CLEAN;
|
||||
}
|
||||
hdr.map = *ctx->fmap;
|
||||
hdr.map = ctx->fmap;
|
||||
hdr.m_length = hdr.map->len;
|
||||
phdr = fmap_need_off_once(hdr.map, 0, hdr_size);
|
||||
if (phdr) {
|
||||
|
|
|
@ -437,7 +437,6 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
/* two files: version.xml and Contents/content.hpf */
|
||||
ret = unzip_search_single(ctx, "version.xml", 11, &loff);
|
||||
if (ret == CL_ETIMEOUT) {
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_TIMEOUT");
|
||||
return CL_ETIMEOUT;
|
||||
} else if (ret != CL_VIRUS) {
|
||||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||
|
@ -451,7 +450,6 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
if (ret == CL_SUCCESS) {
|
||||
ret = unzip_search_single(ctx, "Contents/content.hpf", 20, &loff);
|
||||
if (ret == CL_ETIMEOUT) {
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_TIMEOUT");
|
||||
return CL_ETIMEOUT;
|
||||
} else if (ret != CL_VIRUS) {
|
||||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||
|
@ -466,7 +464,6 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
/* find "[Content Types].xml" */
|
||||
ret = unzip_search_single(ctx, "[Content_Types].xml", 19, &loff);
|
||||
if (ret == CL_ETIMEOUT) {
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_TIMEOUT");
|
||||
return CL_ETIMEOUT;
|
||||
} else if (ret != CL_VIRUS) {
|
||||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||
|
@ -483,15 +480,6 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
|||
ret = unzip_single_internal(ctx, loff, ooxml_content_cb);
|
||||
}
|
||||
|
||||
if (ret == CL_ETIMEOUT)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_TIMEOUT");
|
||||
else if (ret == CL_EMEM)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_OUTOFMEM");
|
||||
else if (ret == CL_EMAXSIZE)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_EMAXSIZE");
|
||||
else if (ret == CL_EMAXFILES)
|
||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_EMAXFILES");
|
||||
|
||||
return ret;
|
||||
#else
|
||||
UNUSEDPARAM(ctx);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
@ -77,6 +78,7 @@
|
|||
#include "cache.h"
|
||||
#include "readdb.h"
|
||||
#include "stats.h"
|
||||
#include "json_api.h"
|
||||
|
||||
cl_unrar_error_t (*cli_unrar_open)(const char *filename, void **hArchive, char **comment, uint32_t *comment_size, uint8_t debug_flag);
|
||||
cl_unrar_error_t (*cli_unrar_peek_file_header)(void *hArchive, unrar_metadata_t *file_metadata);
|
||||
|
@ -280,10 +282,12 @@ static void *get_module_function(void *handle, const char *name)
|
|||
|
||||
static void rarload(void)
|
||||
{
|
||||
#ifndef UNRAR_LINKED
|
||||
#ifdef _WIN32
|
||||
HMODULE rhandle = NULL;
|
||||
#else
|
||||
void *rhandle = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (is_rar_inited) return;
|
||||
|
@ -384,16 +388,16 @@ const char *cl_strerror(int clerror)
|
|||
case CL_EMEM:
|
||||
return "Can't allocate memory";
|
||||
case CL_ETIMEOUT:
|
||||
return "CL_ETIMEOUT: Time limit reached";
|
||||
return "Exceeded time limit";
|
||||
/* internal (needed for debug messages) */
|
||||
case CL_EMAXREC:
|
||||
return "CL_EMAXREC";
|
||||
return "Exceeded time max recursion depth";
|
||||
case CL_EMAXSIZE:
|
||||
return "CL_EMAXSIZE";
|
||||
return "Exceeded max scan size";
|
||||
case CL_EMAXFILES:
|
||||
return "CL_EMAXFILES";
|
||||
return "Exceeded max scan files";
|
||||
case CL_EFORMAT:
|
||||
return "CL_EFORMAT: Bad format or broken data";
|
||||
return "Bad format or broken data";
|
||||
case CL_EBYTECODE:
|
||||
return "Error during bytecode execution";
|
||||
case CL_EBYTECODE_TESTFAIL:
|
||||
|
@ -448,13 +452,13 @@ struct cl_engine *cl_engine_new(void)
|
|||
}
|
||||
|
||||
/* Setup default limits */
|
||||
new->maxscantime = CLI_DEFAULT_TIMELIMIT;
|
||||
new->maxscansize = CLI_DEFAULT_MAXSCANSIZE;
|
||||
new->maxfilesize = CLI_DEFAULT_MAXFILESIZE;
|
||||
new->maxreclevel = CLI_DEFAULT_MAXRECLEVEL;
|
||||
new->maxfiles = CLI_DEFAULT_MAXFILES;
|
||||
new->min_cc_count = CLI_DEFAULT_MIN_CC_COUNT;
|
||||
new->min_ssn_count = CLI_DEFAULT_MIN_SSN_COUNT;
|
||||
new->maxscantime = CLI_DEFAULT_TIMELIMIT;
|
||||
new->maxscansize = CLI_DEFAULT_MAXSCANSIZE;
|
||||
new->maxfilesize = CLI_DEFAULT_MAXFILESIZE;
|
||||
new->max_recursion_level = CLI_DEFAULT_MAXRECLEVEL;
|
||||
new->maxfiles = CLI_DEFAULT_MAXFILES;
|
||||
new->min_cc_count = CLI_DEFAULT_MIN_CC_COUNT;
|
||||
new->min_ssn_count = CLI_DEFAULT_MIN_SSN_COUNT;
|
||||
/* Engine Max sizes */
|
||||
new->maxembeddedpe = CLI_DEFAULT_MAXEMBEDDEDPE;
|
||||
new->maxhtmlnormalize = CLI_DEFAULT_MAXHTMLNORMALIZE;
|
||||
|
@ -615,9 +619,9 @@ cl_error_t cl_engine_set_num(struct cl_engine *engine, enum cl_engine_field fiel
|
|||
case CL_ENGINE_MAX_RECURSION:
|
||||
if (!num) {
|
||||
cli_warnmsg("MaxRecursion: the value of 0 is not allowed, using default: %u\n", CLI_DEFAULT_MAXRECLEVEL);
|
||||
engine->maxreclevel = CLI_DEFAULT_MAXRECLEVEL;
|
||||
engine->max_recursion_level = CLI_DEFAULT_MAXRECLEVEL;
|
||||
} else
|
||||
engine->maxreclevel = num;
|
||||
engine->max_recursion_level = num;
|
||||
break;
|
||||
case CL_ENGINE_MAX_FILES:
|
||||
engine->maxfiles = num;
|
||||
|
@ -795,7 +799,7 @@ long long cl_engine_get_num(const struct cl_engine *engine, enum cl_engine_field
|
|||
case CL_ENGINE_MAX_FILESIZE:
|
||||
return engine->maxfilesize;
|
||||
case CL_ENGINE_MAX_RECURSION:
|
||||
return engine->maxreclevel;
|
||||
return engine->max_recursion_level;
|
||||
case CL_ENGINE_MAX_FILES:
|
||||
return engine->maxfiles;
|
||||
case CL_ENGINE_MAX_EMBEDDEDPE:
|
||||
|
@ -926,27 +930,27 @@ struct cl_settings *cl_engine_settings_copy(const struct cl_engine *engine)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
settings->ac_only = engine->ac_only;
|
||||
settings->ac_mindepth = engine->ac_mindepth;
|
||||
settings->ac_maxdepth = engine->ac_maxdepth;
|
||||
settings->tmpdir = engine->tmpdir ? strdup(engine->tmpdir) : NULL;
|
||||
settings->keeptmp = engine->keeptmp;
|
||||
settings->maxscantime = engine->maxscantime;
|
||||
settings->maxscansize = engine->maxscansize;
|
||||
settings->maxfilesize = engine->maxfilesize;
|
||||
settings->maxreclevel = engine->maxreclevel;
|
||||
settings->maxfiles = engine->maxfiles;
|
||||
settings->maxembeddedpe = engine->maxembeddedpe;
|
||||
settings->maxhtmlnormalize = engine->maxhtmlnormalize;
|
||||
settings->maxhtmlnotags = engine->maxhtmlnotags;
|
||||
settings->maxscriptnormalize = engine->maxscriptnormalize;
|
||||
settings->maxziptypercg = engine->maxziptypercg;
|
||||
settings->min_cc_count = engine->min_cc_count;
|
||||
settings->min_ssn_count = engine->min_ssn_count;
|
||||
settings->bytecode_security = engine->bytecode_security;
|
||||
settings->bytecode_timeout = engine->bytecode_timeout;
|
||||
settings->bytecode_mode = engine->bytecode_mode;
|
||||
settings->pua_cats = engine->pua_cats ? strdup(engine->pua_cats) : NULL;
|
||||
settings->ac_only = engine->ac_only;
|
||||
settings->ac_mindepth = engine->ac_mindepth;
|
||||
settings->ac_maxdepth = engine->ac_maxdepth;
|
||||
settings->tmpdir = engine->tmpdir ? strdup(engine->tmpdir) : NULL;
|
||||
settings->keeptmp = engine->keeptmp;
|
||||
settings->maxscantime = engine->maxscantime;
|
||||
settings->maxscansize = engine->maxscansize;
|
||||
settings->maxfilesize = engine->maxfilesize;
|
||||
settings->max_recursion_level = engine->max_recursion_level;
|
||||
settings->maxfiles = engine->maxfiles;
|
||||
settings->maxembeddedpe = engine->maxembeddedpe;
|
||||
settings->maxhtmlnormalize = engine->maxhtmlnormalize;
|
||||
settings->maxhtmlnotags = engine->maxhtmlnotags;
|
||||
settings->maxscriptnormalize = engine->maxscriptnormalize;
|
||||
settings->maxziptypercg = engine->maxziptypercg;
|
||||
settings->min_cc_count = engine->min_cc_count;
|
||||
settings->min_ssn_count = engine->min_ssn_count;
|
||||
settings->bytecode_security = engine->bytecode_security;
|
||||
settings->bytecode_timeout = engine->bytecode_timeout;
|
||||
settings->bytecode_mode = engine->bytecode_mode;
|
||||
settings->pua_cats = engine->pua_cats ? strdup(engine->pua_cats) : NULL;
|
||||
|
||||
settings->cb_pre_cache = engine->cb_pre_cache;
|
||||
settings->cb_pre_scan = engine->cb_pre_scan;
|
||||
|
@ -988,26 +992,26 @@ struct cl_settings *cl_engine_settings_copy(const struct cl_engine *engine)
|
|||
|
||||
cl_error_t cl_engine_settings_apply(struct cl_engine *engine, const struct cl_settings *settings)
|
||||
{
|
||||
engine->ac_only = settings->ac_only;
|
||||
engine->ac_mindepth = settings->ac_mindepth;
|
||||
engine->ac_maxdepth = settings->ac_maxdepth;
|
||||
engine->keeptmp = settings->keeptmp;
|
||||
engine->maxscantime = settings->maxscantime;
|
||||
engine->maxscansize = settings->maxscansize;
|
||||
engine->maxfilesize = settings->maxfilesize;
|
||||
engine->maxreclevel = settings->maxreclevel;
|
||||
engine->maxfiles = settings->maxfiles;
|
||||
engine->maxembeddedpe = settings->maxembeddedpe;
|
||||
engine->maxhtmlnormalize = settings->maxhtmlnormalize;
|
||||
engine->maxhtmlnotags = settings->maxhtmlnotags;
|
||||
engine->maxscriptnormalize = settings->maxscriptnormalize;
|
||||
engine->maxziptypercg = settings->maxziptypercg;
|
||||
engine->min_cc_count = settings->min_cc_count;
|
||||
engine->min_ssn_count = settings->min_ssn_count;
|
||||
engine->bytecode_security = settings->bytecode_security;
|
||||
engine->bytecode_timeout = settings->bytecode_timeout;
|
||||
engine->bytecode_mode = settings->bytecode_mode;
|
||||
engine->engine_options = settings->engine_options;
|
||||
engine->ac_only = settings->ac_only;
|
||||
engine->ac_mindepth = settings->ac_mindepth;
|
||||
engine->ac_maxdepth = settings->ac_maxdepth;
|
||||
engine->keeptmp = settings->keeptmp;
|
||||
engine->maxscantime = settings->maxscantime;
|
||||
engine->maxscansize = settings->maxscansize;
|
||||
engine->maxfilesize = settings->maxfilesize;
|
||||
engine->max_recursion_level = settings->max_recursion_level;
|
||||
engine->maxfiles = settings->maxfiles;
|
||||
engine->maxembeddedpe = settings->maxembeddedpe;
|
||||
engine->maxhtmlnormalize = settings->maxhtmlnormalize;
|
||||
engine->maxhtmlnotags = settings->maxhtmlnotags;
|
||||
engine->maxscriptnormalize = settings->maxscriptnormalize;
|
||||
engine->maxziptypercg = settings->maxziptypercg;
|
||||
engine->min_cc_count = settings->min_cc_count;
|
||||
engine->min_ssn_count = settings->min_ssn_count;
|
||||
engine->bytecode_security = settings->bytecode_security;
|
||||
engine->bytecode_timeout = settings->bytecode_timeout;
|
||||
engine->bytecode_mode = settings->bytecode_mode;
|
||||
engine->engine_options = settings->engine_options;
|
||||
|
||||
if (engine->tmpdir)
|
||||
MPOOL_FREE(engine->mempool, engine->tmpdir);
|
||||
|
@ -1077,13 +1081,23 @@ cl_error_t cl_engine_settings_free(struct cl_settings *settings)
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
void cli_check_blockmax(cli_ctx *ctx, int rc)
|
||||
void cli_append_virus_if_heur_exceedsmax(cli_ctx *ctx, char *vname)
|
||||
{
|
||||
if (SCAN_HEURISTIC_EXCEEDS_MAX && !ctx->limit_exceeded) {
|
||||
cli_append_virus(ctx, "Heuristics.Limits.Exceeded");
|
||||
ctx->limit_exceeded = 1;
|
||||
cli_dbgmsg("Limit %s Exceeded: scanning may be incomplete and additional analysis needed for this file.\n",
|
||||
cl_strerror(rc));
|
||||
if (!ctx->limit_exceeded) {
|
||||
ctx->limit_exceeded = true; // guard against adding an alert (or metadata) a million times for non-fatal exceeds-max conditions
|
||||
// TODO: consider changing this from a bool to a threshold so we could at least see more than 1 limits exceeded
|
||||
|
||||
if (SCAN_HEURISTIC_EXCEEDS_MAX) {
|
||||
cli_append_possibly_unwanted(ctx, vname);
|
||||
cli_dbgmsg("%s: scanning may be incomplete and additional analysis needed for this file.\n", vname);
|
||||
}
|
||||
|
||||
#if HAVE_JSON
|
||||
/* Also record the event in the scan metadata, under "ParseErrors" */
|
||||
if (SCAN_COLLECT_METADATA && ctx->wrkproperty) {
|
||||
cli_json_parse_error(ctx->wrkproperty, vname);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1093,52 +1107,62 @@ cl_error_t cli_checklimits(const char *who, cli_ctx *ctx, unsigned long need1, u
|
|||
unsigned long needed;
|
||||
|
||||
/* if called without limits, go on, unpack, scan */
|
||||
if (!ctx) return CL_CLEAN;
|
||||
if (!ctx) return ret;
|
||||
|
||||
needed = (need1 > need2) ? need1 : need2;
|
||||
needed = (needed > need3) ? needed : need3;
|
||||
|
||||
/* Enforce timelimit */
|
||||
ret = cli_checktimelimit(ctx);
|
||||
if (CL_ETIMEOUT == (ret = cli_checktimelimit(ctx))) {
|
||||
/* Abort the scan ... */
|
||||
ret = CL_ETIMEOUT;
|
||||
}
|
||||
|
||||
/* if we have global scan limits */
|
||||
/* Enforce global scan-size limit */
|
||||
if (needed && ctx->engine->maxscansize) {
|
||||
/* if the remaining scansize is too small... */
|
||||
if (ctx->engine->maxscansize - ctx->scansize < needed) {
|
||||
/* ... we tell the caller to skip this file */
|
||||
/* Skip this file */
|
||||
cli_dbgmsg("%s: scansize exceeded (initial: %lu, consumed: %lu, needed: %lu)\n", who, (unsigned long int)ctx->engine->maxscansize, (unsigned long int)ctx->scansize, needed);
|
||||
ret = CL_EMAXSIZE;
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxScanSize");
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have per-file size limits, and we are overlimit... */
|
||||
/* Enforce per-file file-size limit */
|
||||
if (needed && ctx->engine->maxfilesize && ctx->engine->maxfilesize < needed) {
|
||||
/* ... we tell the caller to skip this file */
|
||||
/* Skip this file */
|
||||
cli_dbgmsg("%s: filesize exceeded (allowed: %lu, needed: %lu)\n", who, (unsigned long int)ctx->engine->maxfilesize, needed);
|
||||
ret = CL_EMAXSIZE;
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFileSize");
|
||||
}
|
||||
|
||||
/* Enforce limit on number of embedded files */
|
||||
if (ctx->engine->maxfiles && ctx->scannedfiles >= ctx->engine->maxfiles) {
|
||||
/* Abort the scan ... */
|
||||
cli_dbgmsg("%s: files limit reached (max: %u)\n", who, ctx->engine->maxfiles);
|
||||
ret = CL_EMAXFILES;
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles");
|
||||
ctx->abort_scan = true;
|
||||
}
|
||||
|
||||
if (ret != CL_SUCCESS)
|
||||
cli_check_blockmax(ctx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
cl_error_t cli_updatelimits(cli_ctx *ctx, unsigned long needed)
|
||||
cl_error_t cli_updatelimits(cli_ctx *ctx, size_t needed)
|
||||
{
|
||||
cl_error_t ret = cli_checklimits("cli_updatelimits", ctx, needed, 0, 0);
|
||||
|
||||
if (ret != CL_CLEAN) return ret;
|
||||
if (ret != CL_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->scannedfiles++;
|
||||
ctx->scansize += needed;
|
||||
if (ctx->scansize > ctx->engine->maxscansize)
|
||||
ctx->scansize = ctx->engine->maxscansize;
|
||||
return CL_CLEAN;
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1159,13 +1183,20 @@ cl_error_t cli_checktimelimit(cli_ctx *ctx)
|
|||
if (ctx->time_limit.tv_sec != 0) {
|
||||
struct timeval now;
|
||||
if (gettimeofday(&now, NULL) == 0) {
|
||||
if (now.tv_sec > ctx->time_limit.tv_sec)
|
||||
ret = CL_ETIMEOUT;
|
||||
else if (now.tv_sec == ctx->time_limit.tv_sec && now.tv_usec > ctx->time_limit.tv_usec)
|
||||
ret = CL_ETIMEOUT;
|
||||
if (now.tv_sec > ctx->time_limit.tv_sec) {
|
||||
ctx->abort_scan = true;
|
||||
ret = CL_ETIMEOUT;
|
||||
} else if (now.tv_sec == ctx->time_limit.tv_sec && now.tv_usec > ctx->time_limit.tv_usec) {
|
||||
ctx->abort_scan = true;
|
||||
ret = CL_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CL_ETIMEOUT == ret) {
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxScanTime");
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1268,7 +1299,7 @@ int cli_unlink(const char *pathname)
|
|||
void cli_virus_found_cb(cli_ctx *ctx)
|
||||
{
|
||||
if (ctx->engine->cb_virus_found)
|
||||
ctx->engine->cb_virus_found(fmap_fd(*ctx->fmap), (const char *)*ctx->virname, ctx->cb_ctx);
|
||||
ctx->engine->cb_virus_found(fmap_fd(ctx->fmap), (const char *)*ctx->virname, ctx->cb_ctx);
|
||||
}
|
||||
|
||||
cl_error_t cli_append_possibly_unwanted(cli_ctx *ctx, const char *virname)
|
||||
|
@ -1291,8 +1322,8 @@ cl_error_t cli_append_virus(cli_ctx *ctx, const char *virname)
|
|||
return CL_CLEAN;
|
||||
}
|
||||
if ((ctx->fmap != NULL) &&
|
||||
((*ctx->fmap) != NULL) &&
|
||||
(CL_VIRUS != cli_checkfp_virus(ctx, virname, 0))) {
|
||||
(ctx->recursion_stack != NULL) &&
|
||||
(CL_VIRUS != cli_check_fp(ctx, virname))) {
|
||||
return CL_CLEAN;
|
||||
}
|
||||
if (!SCAN_ALLMATCHES && ctx->num_viruses != 0) {
|
||||
|
@ -1300,11 +1331,11 @@ cl_error_t cli_append_virus(cli_ctx *ctx, const char *virname)
|
|||
return CL_CLEAN;
|
||||
}
|
||||
}
|
||||
if (ctx->limit_exceeded == 0 || SCAN_ALLMATCHES) {
|
||||
ctx->num_viruses++;
|
||||
*ctx->virname = virname;
|
||||
cli_virus_found_cb(ctx);
|
||||
}
|
||||
|
||||
ctx->num_viruses++;
|
||||
*ctx->virname = virname;
|
||||
cli_virus_found_cb(ctx);
|
||||
|
||||
#if HAVE_JSON
|
||||
if (SCAN_COLLECT_METADATA && ctx->wrkproperty) {
|
||||
json_object *arrobj, *virobj;
|
||||
|
@ -1342,47 +1373,171 @@ const char *cli_get_last_virus_str(const cli_ctx *ctx)
|
|||
return "";
|
||||
}
|
||||
|
||||
void cli_set_container(cli_ctx *ctx, cli_file_t type, size_t size)
|
||||
cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t type, bool is_new_buffer)
|
||||
{
|
||||
ctx->containers[ctx->recursion].type = type;
|
||||
ctx->containers[ctx->recursion].size = size;
|
||||
if (type >= CL_TYPE_MSEXE && type != CL_TYPE_HTML && type != CL_TYPE_OTHER && type != CL_TYPE_IGNORED)
|
||||
ctx->containers[ctx->recursion].flag = CONTAINER_FLAG_VALID;
|
||||
else
|
||||
ctx->containers[ctx->recursion].flag = 0;
|
||||
}
|
||||
cl_error_t status = CL_SUCCESS;
|
||||
|
||||
cli_file_t cli_get_container(cli_ctx *ctx, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = ctx->recursion + index + 1;
|
||||
while (index >= 0 && index <= (int)ctx->recursion) {
|
||||
if (ctx->containers[index].flag & CONTAINER_FLAG_VALID)
|
||||
return ctx->containers[index].type;
|
||||
index--;
|
||||
recursion_level_t *current_container = NULL;
|
||||
recursion_level_t *new_container = NULL;
|
||||
|
||||
// Check the regular limits
|
||||
if (CL_SUCCESS != (status = cli_checklimits("cli_updatelimits", ctx, map->len, 0, 0))) {
|
||||
cli_dbgmsg("cli_recursion_stack_push: Some content was skipped. The scan result will not be cached.\n");
|
||||
emax_reached(ctx); // Disable caching for all recursion layers.
|
||||
goto done;
|
||||
}
|
||||
return CL_TYPE_ANY;
|
||||
}
|
||||
|
||||
cli_file_t cli_get_container_intermediate(cli_ctx *ctx, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = ctx->recursion + index + 1;
|
||||
if (index >= 0 && index <= (int)ctx->recursion)
|
||||
return ctx->containers[index].type;
|
||||
return CL_TYPE_ANY;
|
||||
}
|
||||
|
||||
size_t cli_get_container_size(cli_ctx *ctx, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = ctx->recursion + index + 1;
|
||||
while (index >= 0 && index <= (int)ctx->recursion) {
|
||||
if (ctx->containers[index].flag & CONTAINER_FLAG_VALID)
|
||||
return ctx->containers[index].size;
|
||||
index--;
|
||||
// Check the recursion limit
|
||||
if (ctx->recursion_level == ctx->recursion_stack_size - 1) {
|
||||
cli_dbgmsg("cli_recursion_stack_push: Archive recursion limit exceeded (%u, max: %u)\n", ctx->recursion_level, ctx->engine->max_recursion_level);
|
||||
cli_dbgmsg("cli_recursion_stack_push: Some content was skipped. The scan result will not be cached.\n");
|
||||
emax_reached(ctx); // Disable caching for all recursion layers.
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxRecursion");
|
||||
status = CL_EMAXREC;
|
||||
goto done;
|
||||
}
|
||||
return ctx->containers[0].size;
|
||||
|
||||
current_container = &ctx->recursion_stack[ctx->recursion_level];
|
||||
ctx->recursion_level++;
|
||||
new_container = &ctx->recursion_stack[ctx->recursion_level];
|
||||
|
||||
memset(new_container, 0, sizeof(recursion_level_t));
|
||||
|
||||
new_container->fmap = map;
|
||||
new_container->type = type;
|
||||
new_container->size = map->len - map->nested_offset;
|
||||
|
||||
if (is_new_buffer) {
|
||||
new_container->recursion_level_buffer = current_container->recursion_level_buffer + 1;
|
||||
new_container->recursion_level_buffer_fmap = 0;
|
||||
} else {
|
||||
new_container->recursion_level_buffer_fmap = current_container->recursion_level_buffer_fmap + 1;
|
||||
}
|
||||
|
||||
if (ctx->next_layer_is_normalized) {
|
||||
// Normalized layers should be ignored when using the get_type() and get_intermediate_type()
|
||||
// functions so that signatures that specify the container or intermediates need not account
|
||||
// for normalized layers "contained in" HTML / Javascript / etc.
|
||||
new_container->is_normalized_layer = true;
|
||||
ctx->next_layer_is_normalized = false;
|
||||
}
|
||||
|
||||
ctx->fmap = new_container->fmap;
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
cl_fmap_t *cli_recursion_stack_pop(cli_ctx *ctx)
|
||||
{
|
||||
cl_fmap_t *popped_map = NULL;
|
||||
|
||||
if (0 == ctx->recursion_level) {
|
||||
cli_dbgmsg("cli_recursion_stack_pop: recursion_level == 0, cannot pop off more layers!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* save off the fmap to return it to the caller, in case they need it */
|
||||
popped_map = ctx->recursion_stack[ctx->recursion_level].fmap;
|
||||
|
||||
/* We're done with this layer, clear it */
|
||||
memset(&ctx->recursion_stack[ctx->recursion_level], 0, sizeof(recursion_level_t));
|
||||
ctx->recursion_level--;
|
||||
|
||||
/* Set the ctx->fmap convenience pointer to the current layer's fmap */
|
||||
ctx->fmap = ctx->recursion_stack[ctx->recursion_level].fmap;
|
||||
|
||||
done:
|
||||
return popped_map;
|
||||
}
|
||||
|
||||
void cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type)
|
||||
{
|
||||
ctx->recursion_stack[ctx->recursion_level].type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert the desired index into the recursion stack to an actual index, excluding normalized layers.
|
||||
*
|
||||
* Accepts negative indexes, which is in fact the primary use case.
|
||||
*
|
||||
* For index:
|
||||
* 0 == the outermost (bottom) layer of the stack.
|
||||
* 1 == the first layer (probably never explicitly used).
|
||||
* -1 == the present innermost (top) layer of the stack.
|
||||
* -2 == the parent layer (or "container"). That is, the second from the top of the stack.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param index The index (probably negative) of the layer we think we want.
|
||||
* @return int -1 if layer doesn't exist, else the index of the desired layer in the recursion_stack
|
||||
*/
|
||||
static int recursion_stack_get(cli_ctx *ctx, int index)
|
||||
{
|
||||
int desired_layer;
|
||||
int current_layer = (int)ctx->recursion_level;
|
||||
|
||||
if (index < 0) {
|
||||
desired_layer = ctx->recursion_level + index + 1; // The +1 is so that -1 == the current layer
|
||||
// and -2 == the parent layer (the container)
|
||||
} else {
|
||||
desired_layer = index;
|
||||
}
|
||||
|
||||
if (desired_layer > current_layer) {
|
||||
desired_layer = ctx->recursion_level + 1; // layer doesn't exist
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (current_layer >= desired_layer && current_layer > 0) {
|
||||
if (ctx->recursion_stack[current_layer].is_normalized_layer) {
|
||||
// The current layer is normalized, so we should step back an extra layer
|
||||
// It's okay if desired_layer goes negative.
|
||||
desired_layer--;
|
||||
}
|
||||
|
||||
current_layer--;
|
||||
}
|
||||
|
||||
done:
|
||||
return desired_layer;
|
||||
}
|
||||
|
||||
cli_file_t cli_recursion_stack_get_type(cli_ctx *ctx, int index)
|
||||
{
|
||||
int index_ignoring_normalized_layers;
|
||||
|
||||
// translate requested index into index of non-normalized layer
|
||||
index_ignoring_normalized_layers = recursion_stack_get(ctx, index);
|
||||
|
||||
if (0 > index_ignoring_normalized_layers) {
|
||||
// Layer too low, does not exist.
|
||||
// Most likely we're at the top layer and there is no container. That's okay.
|
||||
return CL_TYPE_ANY;
|
||||
} else if (ctx->recursion_level < (uint32_t)index_ignoring_normalized_layers) {
|
||||
// layer too high, does not exist. This should never happen!
|
||||
return CL_TYPE_IGNORED;
|
||||
}
|
||||
|
||||
return ctx->recursion_stack[index_ignoring_normalized_layers].type;
|
||||
}
|
||||
|
||||
size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index)
|
||||
{
|
||||
int index_ignoring_normalized_layers;
|
||||
|
||||
// translate requested index into index of non-normalized layer
|
||||
index_ignoring_normalized_layers = recursion_stack_get(ctx, index);
|
||||
|
||||
if (0 > index_ignoring_normalized_layers) {
|
||||
// Layer too low, does not exist.
|
||||
// Most likely we're at the top layer and there is no container. That's okay.
|
||||
return ctx->recursion_stack[0].size;
|
||||
} else {
|
||||
// layer too high, does not exist. This should never happen!
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctx->recursion_stack[index_ignoring_normalized_layers].size;
|
||||
}
|
||||
|
||||
#ifdef C_WINDOWS
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
#include <json.h>
|
||||
|
@ -140,16 +141,19 @@ typedef struct bitset_tag {
|
|||
unsigned long length;
|
||||
} bitset_t;
|
||||
|
||||
typedef struct cli_ctx_container_tag {
|
||||
typedef struct recursion_level_tag {
|
||||
cli_file_t type;
|
||||
size_t size;
|
||||
unsigned char flag;
|
||||
} cli_ctx_container;
|
||||
#define CONTAINER_FLAG_VALID 0x01
|
||||
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. */
|
||||
bool is_normalized_layer; /* Indicates that the layer should be skipped when checking container and intermediate types. */
|
||||
} recursion_level_t;
|
||||
// #define CONTAINER_FLAG_VALID 0x01
|
||||
|
||||
/* internal clamav context */
|
||||
typedef struct cli_ctx_tag {
|
||||
char *target_filepath; /**< (optional) The filepath of the original scan target */
|
||||
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. */
|
||||
const char **virname;
|
||||
|
@ -159,15 +163,17 @@ typedef struct cli_ctx_tag {
|
|||
const struct cl_engine *engine;
|
||||
unsigned long scansize;
|
||||
struct cl_scan_options *options;
|
||||
unsigned int recursion;
|
||||
unsigned int scannedfiles;
|
||||
unsigned int found_possibly_unwanted;
|
||||
unsigned int corrupted_input;
|
||||
unsigned int img_validate;
|
||||
cli_ctx_container *containers; /* set container type after recurse */
|
||||
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. */
|
||||
bool next_layer_is_normalized; /* Indicate that the next fmap pushed to the stack is normalized and should be ignored when checking container/intermediate types */
|
||||
unsigned char handlertype_hash[16];
|
||||
struct cli_dconf *dconf;
|
||||
fmap_t **fmap; /* pointer to current fmap in an allocated array, incremented with recursion depth */
|
||||
bitset_t *hook_lsig_matches;
|
||||
void *cb_ctx;
|
||||
cli_events_t *perf;
|
||||
|
@ -179,7 +185,8 @@ typedef struct cli_ctx_tag {
|
|||
struct json_object *wrkproperty;
|
||||
#endif
|
||||
struct timeval time_limit;
|
||||
int limit_exceeded;
|
||||
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. */
|
||||
} cli_ctx;
|
||||
|
||||
#define STATS_ANON_UUID "5b585e8f-3be5-11e3-bf0b-18037319526c"
|
||||
|
@ -285,15 +292,15 @@ struct cl_engine {
|
|||
uint64_t engine_options;
|
||||
|
||||
/* Limits */
|
||||
uint32_t maxscantime; /* Time limit (in milliseconds) */
|
||||
uint64_t maxscansize; /* during the scanning of archives this size
|
||||
uint32_t maxscantime; /* Time limit (in milliseconds) */
|
||||
uint64_t maxscansize; /* during the scanning of archives this size
|
||||
* will never be exceeded
|
||||
*/
|
||||
uint64_t maxfilesize; /* compressed files will only be decompressed
|
||||
uint64_t maxfilesize; /* compressed files will only be decompressed
|
||||
* and scanned up to this size
|
||||
*/
|
||||
uint32_t maxreclevel; /* maximum recursion level for archives */
|
||||
uint32_t maxfiles; /* maximum number of files to be scanned
|
||||
uint32_t max_recursion_level; /* maximum recursion level for archives */
|
||||
uint32_t maxfiles; /* maximum number of files to be scanned
|
||||
* within a single archive
|
||||
*/
|
||||
/* This is for structured data detection. You can set the minimum
|
||||
|
@ -437,7 +444,7 @@ struct cl_settings {
|
|||
uint32_t maxscantime;
|
||||
uint64_t maxscansize;
|
||||
uint64_t maxfilesize;
|
||||
uint32_t maxreclevel;
|
||||
uint32_t max_recursion_level;
|
||||
uint32_t maxfiles;
|
||||
uint32_t min_cc_count;
|
||||
uint32_t min_ssn_count;
|
||||
|
@ -691,10 +698,74 @@ 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);
|
||||
|
||||
void cli_set_container(cli_ctx *ctx, cli_file_t type, size_t size);
|
||||
cli_file_t cli_get_container(cli_ctx *ctx, int index);
|
||||
size_t cli_get_container_size(cli_ctx *ctx, int index);
|
||||
cli_file_t cli_get_container_intermediate(cli_ctx *ctx, int index);
|
||||
/**
|
||||
* @brief Push a new fmap onto our scan recursion stack.
|
||||
*
|
||||
* May fail if we exceed max recursion depth.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param map The fmap for the new layer.
|
||||
* @param type The file type. May be CL_TYPE_ANY if unknown. Can change it later with cli_recursion_stack_change_type().
|
||||
* @param is_new_buffer true if the fmap represents a new buffer/file, and not some window into an existing fmap.
|
||||
* @return cl_error_t CL_SUCCESS if successful, else CL_EMAXREC if exceeding the max recursion depth.
|
||||
*/
|
||||
cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t type, bool is_new_buffer);
|
||||
|
||||
/**
|
||||
* @brief Pop off a layer of our scan recursion stack.
|
||||
*
|
||||
* Returns the fmap for the popped layer. Does NOT funmap() 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type);
|
||||
|
||||
/**
|
||||
* @brief Get the type of a specific layer.
|
||||
*
|
||||
* Ignores normalized layers internally.
|
||||
*
|
||||
* For index:
|
||||
* 0 == the outermost (bottom) layer of the stack.
|
||||
* 1 == the first layer (probably never explicitly used).
|
||||
* -1 == the present innermost (top) layer of the stack.
|
||||
* -2 == the parent layer (or "container"). That is, the second from the top of the stack.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param index Desired index, will be converted internally as though the normalized layers were stripped out. Don't think too had about it. Or do. ¯\_(ツ)_/¯
|
||||
* @return cli_file_t The type of the requested layer,
|
||||
* or returns CL_TYPE_ANY if a negative layer is requested,
|
||||
* or returns CL_TYPE_IGNORED if requested layer too high.
|
||||
*/
|
||||
cli_file_t cli_recursion_stack_get_type(cli_ctx *ctx, int index);
|
||||
|
||||
/**
|
||||
* @brief Get the size of a specific layer.
|
||||
*
|
||||
* Ignores normalized layers internally.
|
||||
*
|
||||
* For index:
|
||||
* 0 == the outermost (bottom) layer of the stack.
|
||||
* 1 == the first layer (probably never explicitly used).
|
||||
* -1 == the present innermost (top) layer of the stack.
|
||||
* -2 == the parent layer (or "container"). That is, the second from the top of the stack.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param index Desired index, will be converted internally as though the normalized layers were stripped out. Don't think too had about it. Or do. ¯\_(ツ)_/¯
|
||||
* @return cli_file_t The size of the requested layer,
|
||||
* or returns the size of the whole file if a negative layer is requested,
|
||||
* or returns 0 if requested layer too high.
|
||||
*/
|
||||
size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index);
|
||||
|
||||
/* used by: spin, yc (C) aCaB */
|
||||
#define __SHIFTBITS(a) (sizeof(a) << 3)
|
||||
|
@ -902,9 +973,21 @@ void cli_bitset_free(bitset_t *bs);
|
|||
int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
|
||||
int cli_bitset_test(bitset_t *bs, unsigned long bit_offset);
|
||||
const char *cli_ctime(const time_t *timep, char *buf, const size_t bufsize);
|
||||
void cli_check_blockmax(cli_ctx *, int);
|
||||
void cli_append_virus_if_heur_exceedsmax(cli_ctx *, char *);
|
||||
cl_error_t cli_checklimits(const char *, cli_ctx *, unsigned long, unsigned long, unsigned long);
|
||||
cl_error_t cli_updatelimits(cli_ctx *, unsigned long);
|
||||
|
||||
/**
|
||||
* @brief Call before scanning a file to determine if we should scan it, skip it, or abort the entire scanning process.
|
||||
*
|
||||
* If the verdict is CL_SUCCESS, then this function increments the # of scanned files, and increments the amount of scanned data.
|
||||
* If the verdict is that a limit has been exceeded, then ctx->
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
* @param needed The size of the file we're considering scanning.
|
||||
* @return cl_error_t CL_SUCCESS if we're good to keep scanning else an error status.
|
||||
*/
|
||||
cl_error_t cli_updatelimits(cli_ctx *ctx, size_t needed);
|
||||
|
||||
unsigned long cli_getsizelimit(cli_ctx *, unsigned long);
|
||||
int cli_matchregex(const char *str, const char *regex);
|
||||
void cli_qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
|
||||
|
@ -1050,91 +1133,90 @@ uint8_t cli_get_debug_flag();
|
|||
*/
|
||||
uint8_t cli_set_debug_flag(uint8_t debug_flag);
|
||||
|
||||
|
||||
#ifndef STRDUP
|
||||
#define STRDUP(buf, var, ...) \
|
||||
do { \
|
||||
var = strdup(buf); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
#define STRDUP(buf, var, ...) \
|
||||
do { \
|
||||
var = strdup(buf); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef FREE
|
||||
#define FREE(var) \
|
||||
do { \
|
||||
if (NULL != var) { \
|
||||
free(var); \
|
||||
var = NULL; \
|
||||
} \
|
||||
#define FREE(var) \
|
||||
do { \
|
||||
if (NULL != var) { \
|
||||
free(var); \
|
||||
var = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef MALLOC
|
||||
#define MALLOC(var, size, ...) \
|
||||
do { \
|
||||
var = malloc(size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
#define MALLOC(var, size, ...) \
|
||||
do { \
|
||||
var = malloc(size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CLI_MALLOC
|
||||
#define CLI_MALLOC(var, size, ...) \
|
||||
do { \
|
||||
var = cli_malloc(size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
#define CLI_MALLOC(var, size, ...) \
|
||||
do { \
|
||||
var = cli_malloc(size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CALLOC
|
||||
#define CALLOC(var, nmemb, size, ...) \
|
||||
do { \
|
||||
(var) = calloc(nmemb, size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
#define CALLOC(var, nmemb, size, ...) \
|
||||
do { \
|
||||
(var) = calloc(nmemb, size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CLI_CALLOC
|
||||
#define CLI_CALLOC(var, nmemb, size, ...) \
|
||||
do { \
|
||||
(var) = cli_calloc(nmemb, size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
#define CLI_CALLOC(var, nmemb, size, ...) \
|
||||
do { \
|
||||
(var) = cli_calloc(nmemb, size); \
|
||||
if (NULL == var) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef VERIFY_POINTER
|
||||
#define VERIFY_POINTER(ptr, ...) \
|
||||
do { \
|
||||
if (NULL == ptr) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
#define VERIFY_POINTER(ptr, ...) \
|
||||
do { \
|
||||
if (NULL == ptr) { \
|
||||
do { \
|
||||
__VA_ARGS__; \
|
||||
} while (0); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1060,12 +1060,12 @@ static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd, i
|
|||
return CL_EMEM;
|
||||
}
|
||||
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
if (fd != -1) {
|
||||
map = fmap(fd, 0, 0, NULL);
|
||||
if (!map) {
|
||||
cli_dbgmsg("run_pdf_hooks: can't mmap pdf extracted obj\n");
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
@ -1812,8 +1812,6 @@ done:
|
|||
if (flags & PDF_EXTRACT_OBJ_SCAN && sum) {
|
||||
int rc2;
|
||||
|
||||
cli_updatelimits(pdf->ctx, sum);
|
||||
|
||||
/* TODO: invoke bytecode on this pdf obj with metainformation associated */
|
||||
lseek(fout, 0, SEEK_SET);
|
||||
rc2 = cli_magic_scan_desc(fout, fullname, pdf->ctx, NULL);
|
||||
|
@ -3102,7 +3100,7 @@ void pdf_handle_enc(struct pdf_struct *pdf)
|
|||
|
||||
len = obj->size;
|
||||
q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
|
||||
: (const char *)(obj->start + pdf->map);
|
||||
: (const char *)(obj->start + pdf->map);
|
||||
|
||||
O = U = UE = StmF = StrF = EFF = NULL;
|
||||
do {
|
||||
|
@ -3472,7 +3470,7 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
|||
{
|
||||
cl_error_t rc = CL_SUCCESS;
|
||||
struct pdf_struct pdf;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
size_t size = map->len - offset;
|
||||
off_t versize = size > 1032 ? 1032 : size;
|
||||
off_t map_off, bytesleft;
|
||||
|
|
|
@ -585,7 +585,7 @@ static int scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
|||
}
|
||||
|
||||
/* Generate hashes */
|
||||
cli_hashsect(*ctx->fmap, exe_section, hashset, foundsize, foundwild);
|
||||
cli_hashsect(ctx->fmap, exe_section, hashset, foundsize, foundwild);
|
||||
|
||||
/* Print hash */
|
||||
if (cli_debug_flag) {
|
||||
|
@ -595,7 +595,7 @@ static int scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
|||
exe_section->rsz, 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]);
|
||||
} else if (cli_always_gen_section_hash) {
|
||||
const void *hashme = fmap_need_off_once(*ctx->fmap, exe_section->raw, exe_section->rsz);
|
||||
const void *hashme = fmap_need_off_once(ctx->fmap, exe_section->raw, exe_section->rsz);
|
||||
if (!(hashme)) {
|
||||
cli_errmsg("scan_pe_mdb: unable to read section data\n");
|
||||
ret = CL_EREAD;
|
||||
|
@ -2247,7 +2247,7 @@ static int validate_impname(const char *name, uint32_t length, int dll)
|
|||
static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, struct pe_image_import_descriptor *image, const char *dllname, struct cli_exe_info *peinfo, int *first)
|
||||
{
|
||||
uint32_t thuoff = 0, offset;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
size_t dlllen = 0, fsize = map->len;
|
||||
unsigned int err = 0;
|
||||
int num_fns = 0, ret = CL_SUCCESS;
|
||||
|
@ -2409,16 +2409,17 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str
|
|||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
static unsigned int 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, unsigned char **digest, uint32_t *impsz, int *genhash, struct cli_exe_info *peinfo)
|
||||
{
|
||||
struct pe_image_import_descriptor *image;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
size_t left, fsize = map->len;
|
||||
uint32_t impoff, offset;
|
||||
const char *impdes, *buffer;
|
||||
void *hashctx[CLI_HASH_AVAIL_TYPES];
|
||||
enum CLI_HASH_TYPE type;
|
||||
int nimps = 0, ret = CL_SUCCESS;
|
||||
int nimps = 0;
|
||||
cl_error_t ret = CL_SUCCESS;
|
||||
unsigned int err;
|
||||
int first = 1;
|
||||
|
||||
|
@ -2776,7 +2777,7 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
pe_json = get_pe_property(ctx);
|
||||
}
|
||||
#endif
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
fsize = map->len;
|
||||
|
||||
struct cli_exe_info _peinfo;
|
||||
|
@ -4451,9 +4452,9 @@ int cli_scanpe(cli_ctx *ctx)
|
|||
return CL_CLEAN;
|
||||
}
|
||||
|
||||
int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo)
|
||||
int cli_pe_targetinfo(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||
{
|
||||
return cli_peheader(map, peinfo, CLI_PEHEADER_OPT_EXTRACT_VINFO, NULL);
|
||||
return cli_peheader(ctx->fmap, peinfo, CLI_PEHEADER_OPT_EXTRACT_VINFO, NULL);
|
||||
}
|
||||
|
||||
/** Parse the PE header and, if successful, populate peinfo
|
||||
|
@ -5546,7 +5547,7 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
size_t at;
|
||||
unsigned int i, j, hlen;
|
||||
size_t fsize;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
void *hashctx = NULL;
|
||||
struct pe_certificate_hdr cert_hdr;
|
||||
struct cli_mapped_region *regions = NULL;
|
||||
|
@ -5571,7 +5572,7 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
|||
peinfo = &_peinfo;
|
||||
cli_exe_info_init(peinfo, 0);
|
||||
|
||||
if (cli_peheader(*ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) {
|
||||
if (cli_peheader(ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) {
|
||||
cli_exe_info_destroy(peinfo);
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -5799,7 +5800,7 @@ 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.
|
||||
*/
|
||||
int 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, int type, stats_section_t *hashes)
|
||||
{
|
||||
unsigned int i;
|
||||
struct cli_exe_info _peinfo;
|
||||
|
@ -5825,7 +5826,7 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *
|
|||
// if so, use that to avoid having to re-parse the header
|
||||
cli_exe_info_init(peinfo, 0);
|
||||
|
||||
if (cli_peheader(*ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) {
|
||||
if (cli_peheader(ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) {
|
||||
cli_exe_info_destroy(peinfo);
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -5875,7 +5876,7 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *
|
|||
|
||||
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) == 1) {
|
||||
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)");
|
||||
|
@ -5896,7 +5897,7 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *
|
|||
} else if (class == CL_GENHASH_PE_CLASS_IMPTBL) {
|
||||
char *dstr;
|
||||
uint32_t impsz = 0;
|
||||
int ret;
|
||||
cl_error_t ret;
|
||||
|
||||
/* Generate hash */
|
||||
ret = hash_imptbl(ctx, hashset, &impsz, genhash, peinfo);
|
||||
|
|
|
@ -92,11 +92,11 @@ enum {
|
|||
#define CLI_PEHEADER_RET_BROKEN_PE -2
|
||||
#define CLI_PEHEADER_RET_JSON_TIMEOUT -3
|
||||
|
||||
int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo);
|
||||
int cli_pe_targetinfo(cli_ctx *ctx, struct cli_exe_info *peinfo);
|
||||
int 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);
|
||||
int 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, int 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 *);
|
||||
|
|
|
@ -110,7 +110,7 @@ static int icon_scan_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang,
|
|||
int cli_scanicon(icon_groupset *set, cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||
{
|
||||
struct ICON_ENV icon_env;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
uint32_t err_total = 0;
|
||||
|
||||
icon_env.ctx = ctx;
|
||||
|
@ -171,7 +171,7 @@ int cli_groupiconscan(struct ICON_ENV *icon_env, uint32_t rva)
|
|||
struct cli_exe_info *peinfo = icon_env->peinfo;
|
||||
|
||||
int err = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(rva, peinfo->sections, peinfo->nsections, (unsigned int *)(&err), map->len, peinfo->hdr_size), 16);
|
||||
|
||||
if (grp && !err) {
|
||||
|
@ -1368,7 +1368,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;
|
||||
map = ctx->fmap;
|
||||
tempd = (cli_debug_flag && ctx->engine->keeptmp) ? (ctx->sub_tmpdir ? ctx->sub_tmpdir : cli_gettmpdir()) : NULL;
|
||||
icoff = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size);
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ cl_error_t cli_parsepng(cli_ctx *ctx)
|
|||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
|
||||
while (fmap_readn(map, (void *)&chunk_data_length_u32, offset, PNG_CHUNK_LENGTH_SIZE) == PNG_CHUNK_LENGTH_SIZE) {
|
||||
chunk_data_length = be32_to_host(chunk_data_length_u32);
|
||||
|
|
|
@ -551,7 +551,7 @@ int cli_scanrtf(cli_ctx* ctx)
|
|||
|
||||
init_rtf_state(&state);
|
||||
|
||||
for (offset = 0; (ptr = fmap_need_off_once_len(*ctx->fmap, offset, BUFF_SIZE, &bread)) && bread; offset += bread) {
|
||||
for (offset = 0; (ptr = fmap_need_off_once_len(ctx->fmap, offset, BUFF_SIZE, &bread)) && bread; offset += bread) {
|
||||
ptr_end = ptr + bread;
|
||||
while (ptr < ptr_end) {
|
||||
switch (state.parse_state) {
|
||||
|
|
1628
libclamav/scanners.c
1628
libclamav/scanners.c
File diff suppressed because it is too large
Load diff
|
@ -54,6 +54,8 @@ cl_error_t cli_magic_scan_desc(int desc, const char *filepath, cli_ctx *ctx, con
|
|||
/**
|
||||
* @brief Perform a magic scan on the current ctx.
|
||||
*
|
||||
* Calls to cli_magic_scan() should be wrapped with a cli_recursion_stack_push/pop, except in scan_common()
|
||||
*
|
||||
* @param ctx Scanning context structure.
|
||||
* @param type CL_TYPE of data to be scanned.
|
||||
* @return int CL_SUCCESS, or an error code.
|
||||
|
@ -117,4 +119,13 @@ cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, const char *o
|
|||
*/
|
||||
cl_error_t cli_magic_scan_dir(const char *dirname, cli_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Mark all scan recursion fmap layers as non-cacheable.
|
||||
*
|
||||
* This is to prevent libclamav from regurgitating the scan result for something that wasn't fully scanned.
|
||||
*
|
||||
* @param ctx The scanning context.
|
||||
*/
|
||||
void emax_reached(cli_ctx *ctx);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ cl_error_t cli_scansis(cli_ctx *ctx)
|
|||
char *tmpd;
|
||||
unsigned int i;
|
||||
uint32_t uid[4];
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
cli_dbgmsg("in scansis()\n");
|
||||
|
||||
|
@ -265,7 +265,7 @@ static cl_error_t real_scansis(cli_ctx *ctx, const char *tmpd)
|
|||
uint32_t sleft = 0, smax = 0;
|
||||
uint8_t compd, buff[BUFSIZ];
|
||||
size_t pos;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
uint32_t *ptrs = NULL;
|
||||
void *decomp = NULL;
|
||||
int fd = -1;
|
||||
|
@ -718,7 +718,7 @@ static cl_error_t real_scansis9x(cli_ctx *ctx, const char *tmpd)
|
|||
uint32_t field, optst[] = {T_CONTROLLERCHECKSUM, T_DATACHECKSUM, T_COMPRESSED};
|
||||
unsigned int i;
|
||||
|
||||
s->map = *ctx->fmap;
|
||||
s->map = ctx->fmap;
|
||||
s->pos = 0;
|
||||
s->smax = 0;
|
||||
s->sleft = 0;
|
||||
|
|
|
@ -50,7 +50,7 @@ int cli_check_mydoom_log(cli_ctx *ctx)
|
|||
{
|
||||
const uint32_t *record;
|
||||
uint32_t check, key;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
unsigned int blocks = map->len / (8 * 4);
|
||||
|
||||
cli_dbgmsg("in cli_check_mydoom_log()\n");
|
||||
|
@ -160,7 +160,7 @@ int cli_check_riff_exploit(cli_ctx *ctx)
|
|||
const uint32_t *buf;
|
||||
int big_endian, retval;
|
||||
off_t offset;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
cli_dbgmsg("in cli_check_riff_exploit()\n");
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ static int scanzws(cli_ctx *ctx, struct swf_file_hdr *hdr)
|
|||
{
|
||||
struct CLI_LZMA lz;
|
||||
unsigned char inbuff[FILEBUFF], outbuff[FILEBUFF];
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
/* strip off header */
|
||||
off_t offset = 8;
|
||||
uint32_t d_insize;
|
||||
|
@ -303,7 +303,7 @@ static int scancws(cli_ctx *ctx, struct swf_file_hdr *hdr)
|
|||
{
|
||||
z_stream stream;
|
||||
char inbuff[FILEBUFF], outbuff[FILEBUFF];
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
int offset = 8, ret, zret, zend;
|
||||
size_t outsize = 8;
|
||||
size_t count;
|
||||
|
@ -445,7 +445,7 @@ static const char *tagname(tag_id id)
|
|||
int cli_scanswf(cli_ctx *ctx)
|
||||
{
|
||||
struct swf_file_hdr file_hdr;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
unsigned int bitpos, bitbuf, getbits_n, nbits, getword_1, getword_2, getdword_1, getdword_2;
|
||||
const char *pt;
|
||||
unsigned char get_c;
|
||||
|
|
|
@ -54,7 +54,7 @@ cl_error_t cli_parsetiff(cli_ctx *ctx)
|
|||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
map = *ctx->fmap;
|
||||
map = ctx->fmap;
|
||||
|
||||
/* check the magic */
|
||||
if (fmap_readn(map, magic, offset, 4) != 4) {
|
||||
|
|
|
@ -69,14 +69,14 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
int ret, alldone;
|
||||
off_t fsize, pos = 0;
|
||||
|
||||
fsize = ctx->fmap[0]->len;
|
||||
fsize = ctx->fmap->len;
|
||||
|
||||
if (fsize < (off_t)MIN_SIZE) {
|
||||
cli_dbgmsg("cli_tngs: file too small, ignoring\n");
|
||||
return CL_CLEAN;
|
||||
}
|
||||
|
||||
if (fmap_readn(*ctx->fmap, &i32, pos, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
||||
if (fmap_readn(ctx->fmap, &i32, pos, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
||||
/* The file is at least MIN_SIZE bytes, so it "can't" fail */
|
||||
return CL_EREAD;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
if (fmap_readn(*ctx->fmap, &i16, pos, sizeof(uint16_t)) != sizeof(uint16_t)) {
|
||||
if (fmap_readn(ctx->fmap, &i16, pos, sizeof(uint16_t)) != sizeof(uint16_t)) {
|
||||
/* The file is at least MIN_SIZE bytes, so it "can't" fail */
|
||||
return CL_EREAD;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
uint16_t type = 0, tag = 0;
|
||||
int32_t length = 0;
|
||||
|
||||
switch (tnef_header(*ctx->fmap, &pos, &part, &type, &tag, &length)) {
|
||||
switch (tnef_header(ctx->fmap, &pos, &part, &type, &tag, &length)) {
|
||||
case 0:
|
||||
alldone = 1;
|
||||
break;
|
||||
|
@ -134,7 +134,7 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
fb = NULL;
|
||||
}
|
||||
fb = fileblobCreate();
|
||||
if (tnef_message(*ctx->fmap, &pos, type, tag, length, fsize) != 0) {
|
||||
if (tnef_message(ctx->fmap, &pos, type, tag, length, fsize) != 0) {
|
||||
cli_dbgmsg("TNEF: Error reading TNEF message\n");
|
||||
ret = CL_EFORMAT;
|
||||
alldone = 1;
|
||||
|
@ -142,7 +142,7 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
break;
|
||||
case LVL_ATTACHMENT:
|
||||
cli_dbgmsg("TNEF - found attachment\n");
|
||||
if (tnef_attachment(*ctx->fmap, &pos, type, tag, length, dir, &fb, fsize) != 0) {
|
||||
if (tnef_attachment(ctx->fmap, &pos, type, tag, length, dir, &fb, fsize) != 0) {
|
||||
cli_dbgmsg("TNEF: Error reading TNEF attachment\n");
|
||||
ret = CL_EFORMAT;
|
||||
alldone = 1;
|
||||
|
@ -171,7 +171,7 @@ int cli_tnef(const char *dir, cli_ctx *ctx)
|
|||
cli_warnmsg("Saving dump to %s: refer to https://docs.clamav.net/manual/Installing.html\n", filename);
|
||||
|
||||
pos = 0;
|
||||
while ((count = fmap_readn(*ctx->fmap, buffer, pos, sizeof(buffer))) != (size_t)-1) {
|
||||
while ((count = fmap_readn(ctx->fmap, buffer, pos, sizeof(buffer))) != (size_t)-1) {
|
||||
pos += count;
|
||||
cli_writen(fout, buffer, count);
|
||||
}
|
||||
|
@ -206,6 +206,8 @@ tnef_message(fmap_t *map, off_t *pos, uint16_t type, uint16_t tag, int32_t lengt
|
|||
#ifdef CL_DEBUG
|
||||
uint32_t i32;
|
||||
char *string;
|
||||
#else
|
||||
UNUSEDPARAM(map);
|
||||
#endif
|
||||
|
||||
cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n", tag, type,
|
||||
|
|
|
@ -863,7 +863,7 @@ static int arj_read_main_header(arj_metadata_t *metadata)
|
|||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
if ((header_size + sizeof(header_size)) > (metadata->map->real_len - metadata->offset)) {
|
||||
if ((header_size + sizeof(header_size)) > (metadata->map->len - metadata->offset)) {
|
||||
cli_dbgmsg("arj_read_header: invalid header_size: %u, exceeds length of file.\n", header_size);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
|
@ -1001,7 +1001,7 @@ static cl_error_t arj_read_file_header(arj_metadata_t *metadata)
|
|||
ret = CL_EFORMAT;
|
||||
goto done;
|
||||
}
|
||||
if ((header_size + sizeof(header_size)) > (metadata->map->real_len - metadata->offset)) {
|
||||
if ((header_size + sizeof(header_size)) > (metadata->map->len - metadata->offset)) {
|
||||
cli_dbgmsg("arj_read_file_header: invalid header_size: %u, exceeds length of file.\n", header_size);
|
||||
ret = CL_EFORMAT;
|
||||
goto done;
|
||||
|
@ -1139,12 +1139,12 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
cl_error_t cli_unarj_open(fmap_t *map, const char *dirname, arj_metadata_t *metadata, size_t off)
|
||||
cl_error_t cli_unarj_open(fmap_t *map, const char *dirname, arj_metadata_t *metadata)
|
||||
{
|
||||
UNUSEDPARAM(dirname);
|
||||
cli_dbgmsg("in cli_unarj_open\n");
|
||||
metadata->map = map;
|
||||
metadata->offset = off;
|
||||
metadata->offset = 0;
|
||||
if (!is_arj_archive(metadata)) {
|
||||
cli_dbgmsg("Not in ARJ format\n");
|
||||
return CL_EFORMAT;
|
||||
|
|
|
@ -36,7 +36,7 @@ typedef struct arj_metadata_tag {
|
|||
size_t offset;
|
||||
} arj_metadata_t;
|
||||
|
||||
cl_error_t cli_unarj_open(fmap_t *map, const char *dirname, arj_metadata_t *metadata, size_t off);
|
||||
cl_error_t cli_unarj_open(fmap_t *map, const char *dirname, arj_metadata_t *metadata);
|
||||
cl_error_t cli_unarj_prepare_file(const char *dirname, arj_metadata_t *metadata);
|
||||
cl_error_t cli_unarj_extract_file(const char *dirname, arj_metadata_t *metadata);
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ cl_error_t cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
|
|||
const char *block;
|
||||
size_t nread;
|
||||
|
||||
block = fmap_need_off_once_len(*ctx->fmap, pos, BLOCKSIZE, &nread);
|
||||
block = fmap_need_off_once_len(ctx->fmap, pos, BLOCKSIZE, &nread);
|
||||
cli_dbgmsg("cli_untar: pos = %lu\n", (unsigned long)pos);
|
||||
|
||||
if (!in_block && !nread)
|
||||
|
@ -224,6 +224,7 @@ cl_error_t cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
|
|||
switch (type) {
|
||||
default:
|
||||
cli_dbgmsg("cli_untar: unknown type flag %c\n", type);
|
||||
/* fall-through */
|
||||
case '0': /* plain file */
|
||||
case '\0': /* plain file */
|
||||
case '7': /* contiguous file */
|
||||
|
|
|
@ -480,11 +480,11 @@ static inline cl_error_t zdecrypt(
|
|||
|
||||
if (LOCAL_HEADER_flags & F_USEDD) {
|
||||
cli_dbgmsg("cli_unzip: decrypt - (v%u) >> 0x0000%02x%02x 0x%x (moddate)\n", LOCAL_HEADER_version, a, b, LOCAL_HEADER_mtime);
|
||||
if ((b | (a << 8)) == (LOCAL_HEADER_mtime & 0xffff))
|
||||
if ((uint32_t)(b | (a << 8)) == (LOCAL_HEADER_mtime & 0xffff))
|
||||
v = 1;
|
||||
} else {
|
||||
cli_dbgmsg("cli_unzip: decrypt - (v%u) >> 0x0000%02x%02x 0x%x (crc32)\n", LOCAL_HEADER_version, encryption_header[SIZEOF_ENCRYPTION_HEADER - 1], encryption_header[SIZEOF_ENCRYPTION_HEADER - 2], LOCAL_HEADER_crc32);
|
||||
if ((b | (a << 8)) == ((LOCAL_HEADER_crc32 >> 16) & 0xffff))
|
||||
if ((uint32_t)(b | (a << 8)) == ((LOCAL_HEADER_crc32 >> 16) & 0xffff))
|
||||
v = 1;
|
||||
}
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ static unsigned int parse_local_file_header(
|
|||
zsize -= LOCAL_HEADER_flen;
|
||||
|
||||
cli_dbgmsg("cli_unzip: local header - ZMDNAME:%d:%s:%u:%u:%x:%u:%u:%u\n",
|
||||
((LOCAL_HEADER_flags & F_ENCR) != 0), name, LOCAL_HEADER_usize, LOCAL_HEADER_csize, LOCAL_HEADER_crc32, LOCAL_HEADER_method, file_count, ctx->recursion);
|
||||
((LOCAL_HEADER_flags & F_ENCR) != 0), name, LOCAL_HEADER_usize, LOCAL_HEADER_csize, LOCAL_HEADER_crc32, LOCAL_HEADER_method, file_count, ctx->recursion_level);
|
||||
/* ZMDfmt virname:encrypted(0-1):filename(exact|*):usize(exact|*):csize(exact|*):crc32(exact|*):method(exact|*):fileno(exact|*):maxdepth(exact|*) */
|
||||
|
||||
/* Scan file header metadata. */
|
||||
|
@ -804,14 +804,18 @@ parse_central_directory_file_header(
|
|||
struct zip_record *record)
|
||||
{
|
||||
char name[256];
|
||||
int last = 0;
|
||||
const uint8_t *central_header;
|
||||
int virus_found = 0;
|
||||
int last = 0;
|
||||
const uint8_t *central_header = NULL;
|
||||
int virus_found = 0;
|
||||
|
||||
if (!(central_header = fmap_need_off(map, coff, SIZEOF_CENTRAL_HEADER)) || CENTRAL_HEADER_magic != ZIP_MAGIC_CENTRAL_DIRECTORY_RECORD_BEGIN) {
|
||||
if (central_header) fmap_unneed_ptr(map, central_header, SIZEOF_CENTRAL_HEADER);
|
||||
if (central_header) {
|
||||
fmap_unneed_ptr(map, central_header, SIZEOF_CENTRAL_HEADER);
|
||||
central_header = NULL;
|
||||
}
|
||||
cli_dbgmsg("cli_unzip: central header - wrkcomplete\n");
|
||||
return 0;
|
||||
last = 1;
|
||||
goto done;
|
||||
}
|
||||
coff += SIZEOF_CENTRAL_HEADER;
|
||||
|
||||
|
@ -821,6 +825,7 @@ parse_central_directory_file_header(
|
|||
if (zsize - coff <= CENTRAL_HEADER_flen) {
|
||||
cli_dbgmsg("cli_unzip: central header - fname out of file\n");
|
||||
last = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
name[0] = '\0';
|
||||
|
@ -836,9 +841,15 @@ parse_central_directory_file_header(
|
|||
coff += CENTRAL_HEADER_flen;
|
||||
|
||||
/* requests do not supply a ctx; also prevent multiple scans */
|
||||
if (ctx && cli_matchmeta(ctx, name, CENTRAL_HEADER_csize, CENTRAL_HEADER_usize, (CENTRAL_HEADER_flags & F_ENCR) != 0, file_count, CENTRAL_HEADER_crc32, NULL) == CL_VIRUS)
|
||||
if (ctx && (CL_VIRUS == cli_matchmeta(ctx, name, CENTRAL_HEADER_csize, CENTRAL_HEADER_usize, (CENTRAL_HEADER_flags & F_ENCR) != 0, file_count, CENTRAL_HEADER_crc32, NULL))) {
|
||||
virus_found = 1;
|
||||
|
||||
if (!SCAN_ALLMATCHES) {
|
||||
last = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (zsize - coff <= CENTRAL_HEADER_extra_len && !last) {
|
||||
cli_dbgmsg("cli_unzip: central header - extra out of file\n");
|
||||
last = 1;
|
||||
|
@ -886,9 +897,14 @@ parse_central_directory_file_header(
|
|||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (virus_found == 1)
|
||||
*ret = CL_VIRUS;
|
||||
fmap_unneed_ptr(map, central_header, SIZEOF_CENTRAL_HEADER);
|
||||
|
||||
if (NULL != central_header) {
|
||||
fmap_unneed_ptr(map, central_header, SIZEOF_CENTRAL_HEADER);
|
||||
}
|
||||
|
||||
return (last ? 0 : coff);
|
||||
}
|
||||
|
||||
|
@ -958,6 +974,7 @@ cl_error_t index_the_central_directory(
|
|||
struct zip_record *prev_record = NULL;
|
||||
uint32_t num_overlapping_files = 0;
|
||||
int virus_found = 0;
|
||||
bool exceeded_max_files = false;
|
||||
|
||||
if (NULL == catalogue || NULL == num_records) {
|
||||
cli_errmsg("index_the_central_directory: Invalid NULL arguments\n");
|
||||
|
@ -1007,6 +1024,9 @@ cl_error_t index_the_central_directory(
|
|||
/* stop checking file entries if we'll exceed maxfiles */
|
||||
if (ctx->engine->maxfiles && records_count >= ctx->engine->maxfiles) {
|
||||
cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles);
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles");
|
||||
exceeded_max_files = true; // Set a bool so we can return the correct status code later.
|
||||
// We still need to scan the files we found while reviewing the file records up to this limit.
|
||||
break;
|
||||
}
|
||||
records_count++;
|
||||
|
@ -1109,7 +1129,10 @@ done:
|
|||
}
|
||||
}
|
||||
|
||||
if (virus_found) status = CL_VIRUS;
|
||||
if (virus_found)
|
||||
status = CL_VIRUS;
|
||||
else if (exceeded_max_files)
|
||||
status = CL_EMAXFILES;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -1119,7 +1142,7 @@ cl_error_t cli_unzip(cli_ctx *ctx)
|
|||
unsigned int file_count = 0, num_files_unzipped = 0;
|
||||
cl_error_t ret = CL_CLEAN;
|
||||
uint32_t fsize, lhoff = 0, coff = 0;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
char *tmpd = NULL;
|
||||
const char *ptr;
|
||||
int virus_found = 0;
|
||||
|
@ -1221,8 +1244,15 @@ cl_error_t cli_unzip(cli_ctx *ctx)
|
|||
}
|
||||
|
||||
file_count++;
|
||||
|
||||
if (ctx->engine->maxfiles && num_files_unzipped >= ctx->engine->maxfiles) {
|
||||
// Note: this check piggybacks on the MaxFiles setting, but is not actually
|
||||
// scanning these files or incrementing the ctx->scannedfiles count
|
||||
// This check is also redundant. zip_scan_cb == cli_magic_scan_desc,
|
||||
// so we will also check and update the limits for the actual number of scanned
|
||||
// files inside cli_magic_scan()
|
||||
cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles);
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles");
|
||||
ret = CL_EMAXFILES;
|
||||
}
|
||||
|
||||
|
@ -1275,7 +1305,13 @@ cl_error_t cli_unzip(cli_ctx *ctx)
|
|||
virus_found = 1;
|
||||
}
|
||||
if (ctx->engine->maxfiles && num_files_unzipped >= ctx->engine->maxfiles) {
|
||||
// Note: this check piggybacks on the MaxFiles setting, but is not actually
|
||||
// scanning these files or incrementing the ctx->scannedfiles count
|
||||
// This check is also redundant. zip_scan_cb == cli_magic_scan_desc,
|
||||
// so we will also check and update the limits for the actual number of scanned
|
||||
// files inside cli_magic_scan()
|
||||
cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles);
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles");
|
||||
ret = CL_EMAXFILES;
|
||||
}
|
||||
#if HAVE_JSON
|
||||
|
@ -1319,7 +1355,7 @@ cl_error_t unzip_single_internal(cli_ctx *ctx, off_t local_header_offset, zip_cb
|
|||
|
||||
unsigned int num_files_unzipped = 0;
|
||||
uint32_t fsize;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
|
||||
cli_dbgmsg("in cli_unzip_single\n");
|
||||
fsize = (uint32_t)(map->len - local_header_offset);
|
||||
|
@ -1391,9 +1427,9 @@ cl_error_t unzip_search(cli_ctx *ctx, fmap_t *map, struct zip_requests *requests
|
|||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
/* get priority to given map over *ctx->fmap */
|
||||
/* get priority to given map over ctx->fmap */
|
||||
if (ctx && !map)
|
||||
zmap = *ctx->fmap;
|
||||
zmap = ctx->fmap;
|
||||
fsize = zmap->len;
|
||||
if (sizeof(off_t) != sizeof(uint32_t) && fsize != zmap->len) {
|
||||
cli_dbgmsg("unzip_search: file too big\n");
|
||||
|
@ -1433,7 +1469,10 @@ cl_error_t unzip_search(cli_ctx *ctx, fmap_t *map, struct zip_requests *requests
|
|||
|
||||
file_count++;
|
||||
if (ctx && ctx->engine->maxfiles && file_count >= ctx->engine->maxfiles) {
|
||||
// Note: this check piggybacks on the MaxFiles setting, but is not actually
|
||||
// scanning these files or incrementing the ctx->scannedfiles count
|
||||
cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles);
|
||||
cli_append_virus_if_heur_exceedsmax(ctx, "Heuristics.Limits.Exceeded.MaxFiles");
|
||||
ret = CL_EMAXFILES;
|
||||
}
|
||||
#if HAVE_JSON
|
||||
|
|
|
@ -428,7 +428,7 @@ int cli_scanxar(cli_ctx *ctx)
|
|||
#if HAVE_LIBXML2
|
||||
int fd = -1;
|
||||
struct xar_header hdr;
|
||||
fmap_t *map = *ctx->fmap;
|
||||
fmap_t *map = ctx->fmap;
|
||||
size_t length, offset, size, at;
|
||||
int encoding;
|
||||
z_stream strm;
|
||||
|
@ -443,7 +443,7 @@ int cli_scanxar(cli_ctx *ctx)
|
|||
memset(&strm, 0x00, sizeof(z_stream));
|
||||
|
||||
/* retrieve xar header */
|
||||
if (fmap_readn(*ctx->fmap, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) {
|
||||
if (fmap_readn(ctx->fmap, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) {
|
||||
cli_dbgmsg("cli_scanxar: Invalid header, too short.\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
@ -469,7 +469,7 @@ int cli_scanxar(cli_ctx *ctx)
|
|||
/* cli_dbgmsg("hdr.chksum_alg %i\n", hdr.chksum_alg); */
|
||||
|
||||
/* Uncompress TOC */
|
||||
strm.next_in = (unsigned char *)fmap_need_off_once(*ctx->fmap, hdr.size, hdr.toc_length_compressed);
|
||||
strm.next_in = (unsigned char *)fmap_need_off_once(ctx->fmap, hdr.size, hdr.toc_length_compressed);
|
||||
if (strm.next_in == NULL) {
|
||||
cli_dbgmsg("cli_scanxar: fmap_need_off_once fails on TOC.\n");
|
||||
return CL_EREAD;
|
||||
|
|
|
@ -94,7 +94,6 @@ cl_error_t cli_scanxdp(cli_ctx *ctx)
|
|||
{
|
||||
#if HAVE_LIBXML2
|
||||
xmlTextReaderPtr reader = NULL;
|
||||
fmap_t *map = *(ctx->fmap);
|
||||
const char *buf;
|
||||
const xmlChar *name, *value;
|
||||
char *decoded;
|
||||
|
@ -103,12 +102,12 @@ cl_error_t cli_scanxdp(cli_ctx *ctx)
|
|||
char *dumpname;
|
||||
size_t i;
|
||||
|
||||
buf = (const char *)fmap_need_off_once(map, map->offset, map->len);
|
||||
buf = (const char *)fmap_need_off_once(ctx->fmap, ctx->fmap->nested_offset, ctx->fmap->len);
|
||||
if (!(buf))
|
||||
return CL_EREAD;
|
||||
|
||||
if (ctx->engine->keeptmp) {
|
||||
dumpname = dump_xdp(ctx, buf, map->len);
|
||||
dumpname = dump_xdp(ctx, buf, ctx->fmap->len);
|
||||
if (dumpname)
|
||||
free(dumpname);
|
||||
}
|
||||
|
@ -120,7 +119,7 @@ cl_error_t cli_scanxdp(cli_ctx *ctx)
|
|||
* silently ignore the error and return CL_SUCCESS so the filetyping code can
|
||||
* continue on.
|
||||
*/
|
||||
reader = xmlReaderForMemory(buf, (int)(map->len), "noname.xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS);
|
||||
reader = xmlReaderForMemory(buf, (int)(ctx->fmap->len), "noname.xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS);
|
||||
if (!(reader))
|
||||
return CL_SUCCESS;
|
||||
|
||||
|
|
|
@ -4187,7 +4187,7 @@ static cl_error_t parse_formula(FILE *out_file, char data[], unsigned data_size)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
if (ptg < sizeof(TOKENS) / sizeof(char*)) {
|
||||
if (ptg < sizeof(TOKENS) / sizeof(char *)) {
|
||||
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Encountered unexpected ptg token: %s\n", TOKENS[ptg]);
|
||||
} else {
|
||||
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Encountered unknown ptg token: 0x%02x\n", ptg);
|
||||
|
@ -4988,15 +4988,10 @@ cl_error_t cli_extract_xlm_macros_and_images(const char *dir, cli_ctx *ctx, char
|
|||
goto done;
|
||||
}
|
||||
|
||||
ctx->recursion += 1;
|
||||
cli_set_container(ctx, CL_TYPE_MSOLE2, 0); //TODO: set correct container size
|
||||
|
||||
if (cli_scan_desc(out_fd, ctx, CL_TYPE_SCRIPT, 0, NULL, AC_SCAN_VIR, NULL, NULL) == CL_VIRUS) {
|
||||
ctx->recursion -= 1;
|
||||
ret = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
ctx->recursion -= 1;
|
||||
|
||||
/* If a read failed, return with an error. */
|
||||
if (size_read == (size_t)-1) {
|
||||
|
|
|
@ -172,87 +172,78 @@ static int hexdump(void)
|
|||
|
||||
static int hashpe(const char *filename, unsigned int class, int type)
|
||||
{
|
||||
int status = -1;
|
||||
STATBUF sb;
|
||||
const char *fmptr;
|
||||
struct cl_engine *engine;
|
||||
cli_ctx ctx;
|
||||
struct cl_scan_options options;
|
||||
int fd, ret;
|
||||
struct cl_engine *engine = NULL;
|
||||
cli_ctx ctx = {0};
|
||||
struct cl_scan_options options = {0};
|
||||
cl_fmap_t *new_map = NULL;
|
||||
int fd = -1;
|
||||
cl_error_t ret;
|
||||
|
||||
/* Prepare file */
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
mprintf("!hashpe: Can't open file %s!\n", filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
FSTAT(fd, &sb);
|
||||
|
||||
new_map = fmap(fd, 0, sb.st_size, filename);
|
||||
if (NULL == new_map) {
|
||||
mprintf("!hashpe: Can't create fmap for open file\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* build engine */
|
||||
if (!(engine = cl_engine_new())) {
|
||||
mprintf("!hashpe: Can't create new engine\n");
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
|
||||
|
||||
if (cli_initroots(engine, 0) != CL_SUCCESS) {
|
||||
mprintf("!hashpe: cli_initroots() failed\n");
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli_parse_add(engine->root[0], "test", "deadbeef", 0, 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
|
||||
mprintf("!hashpe: Can't parse signature\n");
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cl_engine_compile(engine) != CL_SUCCESS) {
|
||||
mprintf("!hashpe: Can't compile engine\n");
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* prepare context */
|
||||
memset(&ctx, '\0', sizeof(cli_ctx));
|
||||
memset(&options, 0, sizeof(struct cl_scan_options));
|
||||
ctx.engine = engine;
|
||||
ctx.options = &options;
|
||||
ctx.options->parse = ~0;
|
||||
ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
|
||||
if (!ctx.containers) {
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
}
|
||||
ctx.containers[0].type = CL_TYPE_ANY;
|
||||
ctx.dconf = (struct cli_dconf *)engine->dconf;
|
||||
ctx.fmap = calloc(sizeof(fmap_t *), 1);
|
||||
if (!ctx.fmap) {
|
||||
free(ctx.containers);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
ctx.dconf = (struct cli_dconf *)engine->dconf;
|
||||
|
||||
ctx.recursion_stack_size = ctx.engine->max_recursion_level;
|
||||
ctx.recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx.recursion_stack_size);
|
||||
if (!ctx.recursion_stack) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Prepare file */
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
mprintf("!hashpe: Can't open file %s!\n", filename);
|
||||
free(ctx.containers);
|
||||
free(ctx.fmap);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
}
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
ctx.recursion_stack[ctx.recursion_level].fmap = new_map;
|
||||
ctx.recursion_stack[ctx.recursion_level].type = CL_TYPE_ANY; // ANY for the top level, because we don't yet know the type.
|
||||
ctx.recursion_stack[ctx.recursion_level].size = new_map->len - new_map->nested_offset; // Realistically nested_offset will be 0,
|
||||
// but taking the diff is the "right" way.
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
FSTAT(fd, &sb);
|
||||
if (!(*ctx.fmap = fmap(fd, 0, sb.st_size, filename))) {
|
||||
free(ctx.containers);
|
||||
free(ctx.fmap);
|
||||
close(fd);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
}
|
||||
ctx.fmap = ctx.recursion_stack[ctx.recursion_level].fmap;
|
||||
|
||||
fmptr = fmap_need_off_once(*ctx.fmap, 0, sb.st_size);
|
||||
fmptr = fmap_need_off_once(ctx.fmap, 0, sb.st_size);
|
||||
if (!fmptr) {
|
||||
mprintf("!hashpe: fmap_need_off_once failed!\n");
|
||||
free(ctx.containers);
|
||||
funmap(*ctx.fmap);
|
||||
free(ctx.fmap);
|
||||
close(fd);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cl_debug();
|
||||
|
@ -267,12 +258,7 @@ static int hashpe(const char *filename, unsigned int class, int type)
|
|||
break;
|
||||
default:
|
||||
mprintf("!hashpe: unknown classification(%u) for pe hash!\n", class);
|
||||
free(ctx.containers);
|
||||
funmap(*ctx.fmap);
|
||||
free(ctx.fmap);
|
||||
close(fd);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* THIS MAY BE UNNECESSARY */
|
||||
|
@ -293,13 +279,23 @@ static int hashpe(const char *filename, unsigned int class, int type)
|
|||
break;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
|
||||
done:
|
||||
/* Cleanup */
|
||||
free(ctx.containers);
|
||||
funmap(*ctx.fmap);
|
||||
free(ctx.fmap);
|
||||
close(fd);
|
||||
cl_engine_free(engine);
|
||||
return 0;
|
||||
if (NULL != new_map) {
|
||||
funmap(new_map);
|
||||
}
|
||||
if (NULL != ctx.recursion_stack) {
|
||||
free(ctx.recursion_stack);
|
||||
}
|
||||
if (NULL == engine) {
|
||||
cl_engine_free(engine);
|
||||
}
|
||||
if (-1 != fd) {
|
||||
close(fd);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int hashsig(const struct optstruct *opts, unsigned int class, int type)
|
||||
|
@ -1761,13 +1757,13 @@ static int vbadump(const struct optstruct *opts)
|
|||
return -1;
|
||||
}
|
||||
if (cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL)) {
|
||||
destroy_ctx(-1, ctx);
|
||||
destroy_ctx(ctx);
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
destroy_ctx(-1, ctx);
|
||||
destroy_ctx(ctx);
|
||||
if (has_vba && files)
|
||||
sigtool_vba_scandir(dir, hex_output, files);
|
||||
cli_rmdirs(dir);
|
||||
|
@ -2209,71 +2205,74 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir)
|
|||
|
||||
static void matchsig(const char *sig, const char *offset, int fd)
|
||||
{
|
||||
struct cl_engine *engine;
|
||||
struct cli_ac_result *acres = NULL, *res;
|
||||
STATBUF sb;
|
||||
unsigned int matches = 0;
|
||||
cli_ctx ctx;
|
||||
struct cl_scan_options options;
|
||||
int ret;
|
||||
unsigned int matches = 0;
|
||||
struct cl_engine *engine = NULL;
|
||||
cli_ctx ctx = {0};
|
||||
struct cl_scan_options options = {0};
|
||||
cl_fmap_t *new_map = NULL;
|
||||
|
||||
mprintf("SUBSIG: %s\n", sig);
|
||||
|
||||
/* Prepare file */
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
FSTAT(fd, &sb);
|
||||
|
||||
new_map = fmap(fd, 0, sb.st_size, NULL);
|
||||
if (NULL == new_map) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* build engine */
|
||||
if (!(engine = cl_engine_new())) {
|
||||
mprintf("!matchsig: Can't create new engine\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
|
||||
|
||||
if (cli_initroots(engine, 0) != CL_SUCCESS) {
|
||||
mprintf("!matchsig: cli_initroots() failed\n");
|
||||
cl_engine_free(engine);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli_parse_add(engine->root[0], "test", sig, 0, 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
|
||||
mprintf("!matchsig: Can't parse signature\n");
|
||||
cl_engine_free(engine);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cl_engine_compile(engine) != CL_SUCCESS) {
|
||||
mprintf("!matchsig: Can't compile engine\n");
|
||||
cl_engine_free(engine);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
memset(&ctx, '\0', sizeof(cli_ctx));
|
||||
memset(&options, 0, sizeof(struct cl_scan_options));
|
||||
|
||||
ctx.engine = engine;
|
||||
ctx.options = &options;
|
||||
ctx.options->parse = ~0;
|
||||
ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
|
||||
if (!ctx.containers) {
|
||||
cl_engine_free(engine);
|
||||
return;
|
||||
ctx.dconf = (struct cli_dconf *)engine->dconf;
|
||||
|
||||
ctx.recursion_stack_size = ctx.engine->max_recursion_level;
|
||||
ctx.recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx.recursion_stack_size);
|
||||
if (!ctx.recursion_stack) {
|
||||
goto done;
|
||||
}
|
||||
ctx.containers[0].type = CL_TYPE_ANY;
|
||||
ctx.dconf = (struct cli_dconf *)engine->dconf;
|
||||
ctx.fmap = calloc(sizeof(fmap_t *), 1);
|
||||
if (!ctx.fmap) {
|
||||
free(ctx.containers);
|
||||
cl_engine_free(engine);
|
||||
return;
|
||||
}
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
FSTAT(fd, &sb);
|
||||
if (!(*ctx.fmap = fmap(fd, 0, sb.st_size, NULL))) {
|
||||
free(ctx.containers);
|
||||
free(ctx.fmap);
|
||||
cl_engine_free(engine);
|
||||
return;
|
||||
}
|
||||
ret = cli_scan_fmap(&ctx, 0, 0, NULL, AC_SCAN_VIR, &acres, NULL);
|
||||
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
ctx.recursion_stack[ctx.recursion_level].fmap = new_map;
|
||||
ctx.recursion_stack[ctx.recursion_level].type = CL_TYPE_ANY; // ANY for the top level, because we don't yet know the type.
|
||||
ctx.recursion_stack[ctx.recursion_level].size = new_map->len - new_map->nested_offset; // Realistically nested_offset will be 0,
|
||||
// but taking the diff is the "right" way.
|
||||
|
||||
ctx.fmap = ctx.recursion_stack[ctx.recursion_level].fmap;
|
||||
|
||||
(void)cli_scan_fmap(&ctx, 0, 0, NULL, AC_SCAN_VIR, &acres, NULL);
|
||||
|
||||
res = acres;
|
||||
while (res) {
|
||||
matches++;
|
||||
res = res->next;
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
/* TODO: check offsets automatically */
|
||||
mprintf("MATCH: ** YES%s ** (%u %s:", offset ? "/CHECK OFFSET" : "", matches, matches > 1 ? "matches at offsets" : "match at offset");
|
||||
|
@ -2286,15 +2285,23 @@ static void matchsig(const char *sig, const char *offset, int fd)
|
|||
} else {
|
||||
mprintf("MATCH: ** NO **\n");
|
||||
}
|
||||
|
||||
done:
|
||||
/* Cleanup */
|
||||
while (acres) {
|
||||
res = acres;
|
||||
acres = acres->next;
|
||||
free(res);
|
||||
}
|
||||
free(ctx.containers);
|
||||
funmap(*ctx.fmap);
|
||||
free(ctx.fmap);
|
||||
cl_engine_free(engine);
|
||||
if (NULL != new_map) {
|
||||
funmap(new_map);
|
||||
}
|
||||
if (NULL != ctx.recursion_stack) {
|
||||
free(ctx.recursion_stack);
|
||||
}
|
||||
if (NULL == engine) {
|
||||
cl_engine_free(engine);
|
||||
}
|
||||
}
|
||||
|
||||
static char *decodehexstr(const char *hex, unsigned int *dlen)
|
||||
|
@ -3395,12 +3402,14 @@ static int makediff(const struct optstruct *opts)
|
|||
|
||||
static int dumpcerts(const struct optstruct *opts)
|
||||
{
|
||||
int status = -1;
|
||||
char *filename = NULL;
|
||||
STATBUF sb;
|
||||
struct cl_engine *engine;
|
||||
cli_ctx ctx;
|
||||
struct cl_scan_options options;
|
||||
int fd;
|
||||
struct cl_engine *engine = NULL;
|
||||
cli_ctx ctx = {0};
|
||||
struct cl_scan_options options = {0};
|
||||
int fd = -1;
|
||||
cl_fmap_t *new_map = NULL;
|
||||
cl_error_t ret;
|
||||
|
||||
logg_file = NULL;
|
||||
|
@ -3408,7 +3417,23 @@ static int dumpcerts(const struct optstruct *opts)
|
|||
filename = optget(opts, "print-certs")->strarg;
|
||||
if (!filename) {
|
||||
mprintf("!dumpcerts: No filename!\n");
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Prepare file */
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
mprintf("!dumpcerts: Can't open file %s!\n", filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
FSTAT(fd, &sb);
|
||||
|
||||
new_map = fmap(fd, 0, sb.st_size, filename);
|
||||
if (NULL == new_map) {
|
||||
mprintf("!dumpcerts: Can't create fmap for open file\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* build engine */
|
||||
|
@ -3420,64 +3445,41 @@ static int dumpcerts(const struct optstruct *opts)
|
|||
|
||||
if (cli_initroots(engine, 0) != CL_SUCCESS) {
|
||||
mprintf("!dumpcerts: cli_initroots() failed\n");
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cli_parse_add(engine->root[0], "test", "deadbeef", 0, 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
|
||||
mprintf("!dumpcerts: Can't parse signature\n");
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cl_engine_compile(engine) != CL_SUCCESS) {
|
||||
mprintf("!dumpcerts: Can't compile engine\n");
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cl_engine_set_num(engine, CL_ENGINE_PE_DUMPCERTS, 1);
|
||||
cl_debug();
|
||||
|
||||
/* prepare context */
|
||||
memset(&ctx, '\0', sizeof(cli_ctx));
|
||||
memset(&options, 0, sizeof(struct cl_scan_options));
|
||||
ctx.engine = engine;
|
||||
ctx.options = &options;
|
||||
ctx.options->parse = ~0;
|
||||
ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
|
||||
if (!ctx.containers) {
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
}
|
||||
ctx.containers[0].type = CL_TYPE_ANY;
|
||||
ctx.dconf = (struct cli_dconf *)engine->dconf;
|
||||
ctx.fmap = calloc(sizeof(fmap_t *), 1);
|
||||
if (!ctx.fmap) {
|
||||
free(ctx.containers);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
ctx.dconf = (struct cli_dconf *)engine->dconf;
|
||||
|
||||
ctx.recursion_stack_size = ctx.engine->max_recursion_level;
|
||||
ctx.recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx.recursion_stack_size);
|
||||
if (!ctx.recursion_stack) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Prepare file */
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
mprintf("!dumpcerts: Can't open file %s!\n", filename);
|
||||
free(ctx.containers);
|
||||
free(ctx.fmap);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
}
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
ctx.recursion_stack[ctx.recursion_level].fmap = new_map;
|
||||
ctx.recursion_stack[ctx.recursion_level].type = CL_TYPE_ANY; // ANY for the top level, because we don't yet know the type.
|
||||
ctx.recursion_stack[ctx.recursion_level].size = new_map->len - new_map->nested_offset; // Realistically nested_offset will be 0,
|
||||
// but taking the diff is the "right" way.
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
FSTAT(fd, &sb);
|
||||
if (!(*ctx.fmap = fmap(fd, 0, sb.st_size, filename))) {
|
||||
free(ctx.containers);
|
||||
free(ctx.fmap);
|
||||
close(fd);
|
||||
cl_engine_free(engine);
|
||||
return -1;
|
||||
}
|
||||
ctx.fmap = ctx.recursion_stack[ctx.recursion_level].fmap;
|
||||
|
||||
ret = cli_check_auth_header(&ctx, NULL);
|
||||
|
||||
|
@ -3501,13 +3503,23 @@ static int dumpcerts(const struct optstruct *opts)
|
|||
break;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
|
||||
done:
|
||||
/* Cleanup */
|
||||
free(ctx.containers);
|
||||
funmap(*ctx.fmap);
|
||||
free(ctx.fmap);
|
||||
close(fd);
|
||||
cl_engine_free(engine);
|
||||
return 0;
|
||||
if (NULL != new_map) {
|
||||
funmap(new_map);
|
||||
}
|
||||
if (NULL != ctx.recursion_stack) {
|
||||
free(ctx.recursion_stack);
|
||||
}
|
||||
if (NULL == engine) {
|
||||
cl_engine_free(engine);
|
||||
}
|
||||
if (-1 != fd) {
|
||||
close(fd);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void help(void)
|
||||
|
|
169
sigtool/vba.c
169
sigtool/vba.c
|
@ -60,6 +60,7 @@ cli_ctx *convenience_ctx(int fd)
|
|||
cl_error_t status = CL_EMEM;
|
||||
cli_ctx *ctx = NULL;
|
||||
struct cl_engine *engine = NULL;
|
||||
cl_fmap_t *new_map = NULL;
|
||||
|
||||
/* build engine */
|
||||
engine = cl_engine_new();
|
||||
|
@ -85,6 +86,13 @@ cli_ctx *convenience_ctx(int fd)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* fake input fmap */
|
||||
new_map = fmap(fd, 0, 0, NULL);
|
||||
if (NULL == new_map) {
|
||||
printf("convenience_ctx: fmap failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* prepare context */
|
||||
ctx = cli_calloc(1, sizeof(cli_ctx));
|
||||
if (!ctx) {
|
||||
|
@ -94,21 +102,23 @@ cli_ctx *convenience_ctx(int fd)
|
|||
|
||||
ctx->engine = (const struct cl_engine *)engine;
|
||||
|
||||
ctx->containers = cli_calloc(sizeof(cli_ctx_container), ctx->engine->maxreclevel + 2);
|
||||
if (NULL == ctx->containers) {
|
||||
printf("convenience_ctx: failed to allocate ctx containers.");
|
||||
goto done;
|
||||
}
|
||||
ctx->containers[0].type = CL_TYPE_ANY;
|
||||
|
||||
ctx->dconf = (struct cli_dconf *)engine->dconf;
|
||||
|
||||
ctx->fmap = cli_calloc(sizeof(fmap_t *), ctx->engine->maxreclevel + 2);
|
||||
if (!(ctx->fmap)) {
|
||||
printf("convenience_ctx: fmap initialization failed\n");
|
||||
ctx->recursion_stack_size = ctx->engine->max_recursion_level;
|
||||
ctx->recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx->recursion_stack_size);
|
||||
if (!ctx->recursion_stack) {
|
||||
status = CL_EMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// ctx was calloc'd, so recursion_level starts at 0.
|
||||
ctx->recursion_stack[ctx->recursion_level].fmap = new_map;
|
||||
ctx->recursion_stack[ctx->recursion_level].type = CL_TYPE_ANY; // ANY for the top level, because we don't yet know the type.
|
||||
ctx->recursion_stack[ctx->recursion_level].size = new_map->len - new_map->nested_offset; // Realistically nested_offset will be 0,
|
||||
// but taking the diff is the "right" way.
|
||||
|
||||
ctx->fmap = ctx->recursion_stack[ctx->recursion_level].fmap;
|
||||
|
||||
ctx->options = cli_calloc(1, sizeof(struct cl_scan_options));
|
||||
if (!ctx->options) {
|
||||
printf("convenience_ctx: scan options allocation failed\n");
|
||||
|
@ -117,24 +127,19 @@ cli_ctx *convenience_ctx(int fd)
|
|||
ctx->options->general |= CL_SCAN_GENERAL_HEURISTICS;
|
||||
ctx->options->parse = ~(0);
|
||||
|
||||
if (!(*ctx->fmap = fmap(fd, 0, 0, NULL))) {
|
||||
printf("convenience_ctx: fmap failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (CL_SUCCESS != status) {
|
||||
if (NULL != ctx) {
|
||||
if (NULL != ctx->fmap) {
|
||||
free(ctx->fmap);
|
||||
if (NULL != new_map) {
|
||||
funmap(new_map);
|
||||
}
|
||||
if (NULL != ctx->options) {
|
||||
free(ctx->options);
|
||||
}
|
||||
if (NULL != ctx->containers) {
|
||||
free(ctx->containers);
|
||||
if (NULL != ctx->recursion_stack) {
|
||||
free(ctx->recursion_stack);
|
||||
}
|
||||
free(ctx);
|
||||
ctx = NULL;
|
||||
|
@ -147,33 +152,37 @@ done:
|
|||
return ctx;
|
||||
}
|
||||
|
||||
void destroy_ctx(int desc, cli_ctx *ctx)
|
||||
void destroy_ctx(cli_ctx *ctx)
|
||||
{
|
||||
if (desc >= 0)
|
||||
close(desc);
|
||||
|
||||
if (NULL != ctx) {
|
||||
if (NULL != ctx->fmap) {
|
||||
if (NULL != *(ctx->fmap)) {
|
||||
funmap(*(ctx->fmap));
|
||||
*(ctx->fmap) = NULL;
|
||||
if (NULL != ctx->recursion_stack) {
|
||||
/* Clean up any fmaps */
|
||||
while (ctx->recursion_level > 0) {
|
||||
if (NULL != ctx->recursion_stack[ctx->recursion_level].fmap) {
|
||||
funmap(ctx->recursion_stack[ctx->recursion_level].fmap);
|
||||
ctx->recursion_stack[ctx->recursion_level].fmap = NULL;
|
||||
}
|
||||
ctx->recursion_level -= 1;
|
||||
}
|
||||
if (NULL != ctx->recursion_stack[0].fmap) {
|
||||
funmap(ctx->recursion_stack[0].fmap);
|
||||
ctx->recursion_stack[0].fmap = NULL;
|
||||
}
|
||||
|
||||
free(ctx->fmap);
|
||||
ctx->fmap = NULL;
|
||||
free(ctx->recursion_stack);
|
||||
ctx->recursion_stack = NULL;
|
||||
}
|
||||
|
||||
if (NULL != ctx->engine) {
|
||||
cl_engine_free((struct cl_engine *)ctx->engine);
|
||||
ctx->engine = NULL;
|
||||
}
|
||||
|
||||
if (NULL != ctx->options) {
|
||||
free(ctx->options);
|
||||
ctx->options = NULL;
|
||||
}
|
||||
if (NULL != ctx->containers) {
|
||||
free(ctx->containers);
|
||||
ctx->containers = NULL;
|
||||
}
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
@ -1087,17 +1096,18 @@ static void wm_decode_macro(unsigned char *buff, uint32_t len, int hex_output)
|
|||
|
||||
static int sigtool_scandir(const char *dirname, int hex_output)
|
||||
{
|
||||
DIR *dd;
|
||||
int status = -1;
|
||||
DIR *dd = NULL;
|
||||
struct dirent *dent;
|
||||
STATBUF statbuf;
|
||||
char *fname;
|
||||
const char *tmpdir;
|
||||
char *dir;
|
||||
int ret = CL_CLEAN, desc;
|
||||
cli_ctx *ctx;
|
||||
char *fname = NULL;
|
||||
char *dir = NULL;
|
||||
cl_error_t ret = CL_CLEAN;
|
||||
int desc = -1;
|
||||
cli_ctx *ctx = NULL;
|
||||
int has_vba = 0, has_xlm = 0;
|
||||
|
||||
fname = NULL;
|
||||
if ((dd = opendir(dirname)) != NULL) {
|
||||
while ((dent = readdir(dd))) {
|
||||
if (dent->d_ino) {
|
||||
|
@ -1105,18 +1115,18 @@ static int sigtool_scandir(const char *dirname, int hex_output)
|
|||
/* build the full name */
|
||||
fname = (char *)cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
|
||||
if (!fname) {
|
||||
closedir(dd);
|
||||
return -1;
|
||||
status = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name);
|
||||
|
||||
/* stat the file */
|
||||
if (LSTAT(fname, &statbuf) != -1) {
|
||||
if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
|
||||
if (sigtool_scandir(fname, hex_output)) {
|
||||
free(fname);
|
||||
closedir(dd);
|
||||
return CL_VIRUS;
|
||||
status = CL_VIRUS;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
|
@ -1127,53 +1137,55 @@ static int sigtool_scandir(const char *dirname, int hex_output)
|
|||
dir = cli_gentemp(tmpdir);
|
||||
if (!dir) {
|
||||
printf("cli_gentemp() failed\n");
|
||||
free(fname);
|
||||
closedir(dd);
|
||||
return -1;
|
||||
status = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (mkdir(dir, 0700)) {
|
||||
printf("Can't create temporary directory %s\n", dir);
|
||||
free(fname);
|
||||
closedir(dd);
|
||||
free(dir);
|
||||
return CL_ETMPDIR;
|
||||
status = CL_ETMPDIR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((desc = open(fname, O_RDONLY | O_BINARY)) == -1) {
|
||||
printf("Can't open file %s\n", fname);
|
||||
free(fname);
|
||||
closedir(dd);
|
||||
free(dir);
|
||||
return 1;
|
||||
status = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(ctx = convenience_ctx(desc))) {
|
||||
free(fname);
|
||||
close(desc);
|
||||
closedir(dd);
|
||||
free(dir);
|
||||
return 1;
|
||||
status = 1;
|
||||
goto done;
|
||||
}
|
||||
if ((ret = cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL))) {
|
||||
printf("ERROR %s\n", cl_strerror(ret));
|
||||
destroy_ctx(desc, ctx);
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
closedir(dd);
|
||||
free(fname);
|
||||
return ret;
|
||||
|
||||
status = ret;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (has_vba && files)
|
||||
sigtool_vba_scandir(dir, hex_output, files);
|
||||
destroy_ctx(desc, ctx);
|
||||
|
||||
// Cleanup
|
||||
if (desc >= 0) {
|
||||
close(desc);
|
||||
desc = -1;
|
||||
}
|
||||
|
||||
destroy_ctx(ctx);
|
||||
ctx = NULL;
|
||||
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
dir = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
free(fname);
|
||||
fname = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1182,8 +1194,27 @@ static int sigtool_scandir(const char *dirname, int hex_output)
|
|||
return CL_EOPEN;
|
||||
}
|
||||
|
||||
closedir(dd);
|
||||
return 0;
|
||||
status = 0;
|
||||
|
||||
done:
|
||||
if (desc >= 0) {
|
||||
close(desc);
|
||||
}
|
||||
if (NULL != dd) {
|
||||
closedir(dd);
|
||||
}
|
||||
if (NULL != ctx) {
|
||||
destroy_ctx(ctx);
|
||||
}
|
||||
if (NULL != dir) {
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
}
|
||||
if (NULL != fname) {
|
||||
free(fname);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U)
|
||||
|
|
|
@ -26,6 +26,6 @@
|
|||
|
||||
int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U);
|
||||
cli_ctx *convenience_ctx(int fd);
|
||||
void destroy_ctx(int desc, cli_ctx *ctx);
|
||||
void destroy_ctx(cli_ctx *ctx);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -77,8 +77,17 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
|
|||
ck_assert_msg(!!cctx.engine, "cannot create engine");
|
||||
rc = cl_engine_compile(engine);
|
||||
ck_assert_msg(!rc, "cannot compile engine");
|
||||
cctx.fmap = cli_calloc(sizeof(fmap_t *), engine->maxreclevel + 2);
|
||||
ck_assert_msg(!!cctx.fmap, "cannot allocate fmap");
|
||||
|
||||
cctx.dconf = cctx.engine->dconf;
|
||||
|
||||
cctx.recursion_stack_size = cctx.engine->max_recursion_level;
|
||||
cctx.recursion_stack = cli_calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
|
||||
ck_assert_msg(!!cctx.recursion_stack, "cli_calloc() for recursion_stack failed");
|
||||
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
cctx.recursion_stack[cctx.recursion_level].fmap = NULL;
|
||||
|
||||
cctx.fmap = cctx.recursion_stack[cctx.recursion_level].fmap;
|
||||
|
||||
ck_assert_msg(fd >= 0, "retmagic open failed");
|
||||
f = fdopen(fd, "r");
|
||||
|
@ -149,7 +158,7 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
|
|||
funmap(map);
|
||||
cli_bytecode_destroy(&bc);
|
||||
cli_bytecode_done(&bcs);
|
||||
free(cctx.fmap);
|
||||
free(cctx.recursion_stack);
|
||||
cl_engine_free(engine);
|
||||
if (fdin >= 0)
|
||||
close(fdin);
|
||||
|
|
|
@ -156,22 +156,34 @@ static const struct pcre_testdata_s {
|
|||
static cli_ctx ctx;
|
||||
static struct cl_scan_options options;
|
||||
|
||||
static fmap_t *thefmap = NULL;
|
||||
static fmap_t thefmap;
|
||||
static const char *virname = NULL;
|
||||
static void setup(void)
|
||||
{
|
||||
struct cli_matcher *root;
|
||||
virname = NULL;
|
||||
thefmap = NULL;
|
||||
|
||||
memset(&thefmap, 0, sizeof(thefmap));
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
memset(&options, 0, sizeof(struct cl_scan_options));
|
||||
ctx.options = &options;
|
||||
|
||||
ctx.virname = &virname;
|
||||
ctx.fmap = &thefmap;
|
||||
ctx.engine = cl_engine_new();
|
||||
ck_assert_msg(!!ctx.engine, "cl_engine_new() failed");
|
||||
|
||||
ctx.dconf = ctx.engine->dconf;
|
||||
|
||||
ctx.recursion_stack_size = ctx.engine->max_recursion_level;
|
||||
ctx.recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx.recursion_stack_size);
|
||||
ck_assert_msg(!!ctx.recursion_stack, "cli_calloc() for recursion_stack failed");
|
||||
|
||||
// ctx was memset, so recursion_level starts at 0.
|
||||
ctx.recursion_stack[ctx.recursion_level].fmap = &thefmap;
|
||||
|
||||
ctx.fmap = ctx.recursion_stack[ctx.recursion_level].fmap;
|
||||
|
||||
root = (struct cli_matcher *)MPOOL_CALLOC(ctx.engine->mempool, 1, sizeof(struct cli_matcher));
|
||||
ck_assert_msg(root != NULL, "root == NULL");
|
||||
#ifdef USE_MPOOL
|
||||
|
@ -184,6 +196,7 @@ static void setup(void)
|
|||
static void teardown(void)
|
||||
{
|
||||
cl_engine_free((struct cl_engine *)ctx.engine);
|
||||
free(ctx.recursion_stack);
|
||||
}
|
||||
|
||||
START_TEST(test_ac_scanbuff)
|
||||
|
|
|
@ -515,7 +515,7 @@ TCPAddr localhost
|
|||
# file, all files within it will also be scanned. This options specifies how
|
||||
# deeply the process should be continued.
|
||||
# Note: setting this limit too high may result in severe damage to the system.
|
||||
# Default: 16
|
||||
# Default: 17
|
||||
#MaxRecursion 10
|
||||
|
||||
# Number of files to be scanned within an archive, a document, or any other
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue