diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 777b0c1906..9eac358439 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,32 +3,76 @@ # # Example executables # -add_executable(ex1) -target_sources(ex1 - PRIVATE ex1.c) -set_target_properties( ex1 PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" ) -target_link_libraries(ex1 +add_executable(ex_basic_scandesc) +target_sources(ex_basic_scandesc + PRIVATE ex_basic_scandesc.c) +set_target_properties( ex_basic_scandesc PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" ) +target_link_libraries(ex_basic_scandesc PRIVATE ClamAV::libclamav) if(LLVM_FOUND) - target_link_directories( ex1 PUBLIC ${LLVM_LIBRARY_DIRS} ) - target_link_libraries( ex1 PUBLIC ${LLVM_LIBRARIES} ) + target_link_directories( ex_basic_scandesc PUBLIC ${LLVM_LIBRARY_DIRS} ) + target_link_libraries( ex_basic_scandesc PUBLIC ${LLVM_LIBRARIES} ) +endif() +if(WIN32) + install(TARGETS ex_basic_scandesc DESTINATION .) +else() + install(TARGETS ex_basic_scandesc DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() if(ENABLE_STATIC_LIB) - add_executable(ex1_static) - set_target_properties( ex1_static PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" ) - target_sources(ex1_static - PRIVATE ex1.c) - target_link_libraries(ex1_static + add_executable(ex_basic_scandesc_static) + set_target_properties( ex_basic_scandesc_static PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" ) + target_sources(ex_basic_scandesc_static + PRIVATE ex_basic_scandesc.c) + target_link_libraries(ex_basic_scandesc_static PRIVATE ClamAV::libclamav_static) if(LLVM_FOUND) - target_link_directories( ex1_static PUBLIC ${LLVM_LIBRARY_DIRS} ) - target_link_libraries( ex1_static PUBLIC ${LLVM_LIBRARIES} ) + target_link_directories( ex_basic_scandesc_static PUBLIC ${LLVM_LIBRARY_DIRS} ) + target_link_libraries( ex_basic_scandesc_static PUBLIC ${LLVM_LIBRARIES} ) + endif() + if(WIN32) + install(TARGETS ex_basic_scandesc_static DESTINATION .) + else() + install(TARGETS ex_basic_scandesc_static DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif() +add_executable(ex_prescan_callback) +target_sources(ex_prescan_callback + PRIVATE ex_prescan_callback.c) +set_target_properties(ex_prescan_callback PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}") +target_link_libraries(ex_prescan_callback + PRIVATE + ClamAV::libclamav) +if(LLVM_FOUND) + target_link_directories( ex_prescan_callback PUBLIC ${LLVM_LIBRARY_DIRS} ) + target_link_libraries( ex_prescan_callback PUBLIC ${LLVM_LIBRARIES} ) +endif() +if(WIN32) + install(TARGETS ex_prescan_callback DESTINATION .) +else() + install(TARGETS ex_prescan_callback DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() + +add_executable(ex_file_inspection_callback) +target_sources(ex_file_inspection_callback + PRIVATE ex_file_inspection_callback.c) +set_target_properties(ex_file_inspection_callback PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}") +target_link_libraries(ex_file_inspection_callback + PRIVATE + ClamAV::libclamav) +if(LLVM_FOUND) + target_link_directories( ex_file_inspection_callback PUBLIC ${LLVM_LIBRARY_DIRS} ) + target_link_libraries( ex_file_inspection_callback PUBLIC ${LLVM_LIBRARIES} ) +endif() +if(WIN32) + install(TARGETS ex_file_inspection_callback DESTINATION .) +else() + install(TARGETS ex_file_inspection_callback DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() + add_executable(ex_cl_cvdunpack) target_sources(ex_cl_cvdunpack PRIVATE ex_cl_cvdunpack.c) diff --git a/examples/ex1.c b/examples/ex_basic_scandesc.c similarity index 99% rename from examples/ex1.c rename to examples/ex_basic_scandesc.c index 22b6d23d50..73e065ae0f 100644 --- a/examples/ex1.c +++ b/examples/ex_basic_scandesc.c @@ -30,6 +30,7 @@ #include #include #include + #include #ifndef O_BINARY diff --git a/examples/ex_file_inspection_callback.c b/examples/ex_file_inspection_callback.c new file mode 100644 index 0000000000..60ca91ce98 --- /dev/null +++ b/examples/ex_file_inspection_callback.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * This example demonstrates using callbacks to record information about each + * file found during a recursive scan. + */ + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include + +#include + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +/** Max # of bytes to show for archive inspection preview */ +#define MAX_PREVIEW 10 + +cl_error_t inspection_callback( + int fd, + const char *type, + const char **ancestors, // array of null-terminated strings, array size == recursion_level + size_t parent_file_size, + const char *file_name, + size_t file_size, + const char *file_buffer, + uint32_t recursion_level, + uint32_t attributes, // E.g.: was normalized, decrypted, etc. See LAYER_ATTRIBUTES_* flags in clamav.h + void *context) // Could be used to retrieve / store contextual information for app +{ + size_t i = 0; + + // printf("Message: %s\n", (char *)context.blah); + UNUSEDPARAM(context); + + printf("ancestors: "); + for (i = 0; i < recursion_level; i++) { + printf("%s", ancestors[i]); + if (i + 1 < recursion_level) { + printf(" > "); + } + } + printf("\n"); + printf("parent size: %zu\n", parent_file_size); + printf("file name: %s\n", file_name); + printf("file desc: %d\n", fd); + printf("file size: %zu\n", file_size); + printf("file type: %s\n", type); + printf("recursion level: %u\n", recursion_level); + printf("decrypted: %s\n", attributes & LAYER_ATTRIBUTES_DECRYPTED ? "yes" : "no"); + printf("normalized: %s\n", attributes & LAYER_ATTRIBUTES_NORMALIZED ? "yes" : "no"); + printf("file preview: "); + for (i = 0; i < MIN(file_size, MAX_PREVIEW); i++) { + uint8_t byte = file_buffer[i]; + printf("%02x ", byte); + } + printf("\n\n"); + + return CL_CLEAN; /* keep scanning */ +} + +cl_error_t post_callback( + int fd, + int result, + const char *virname, + void *context) // Could be used to retrieve / store contextual information for app +{ + printf("result: %d\n", result); + printf("virname: %s\n", virname); + printf("\n\n"); + + return CL_CLEAN; // respect the original result +} + +/* + * Exit codes: + * 0: clean + * 1: infected + * 2: error + */ + +int main(int argc, char **argv) +{ + int status = 2; + cl_error_t ret = CL_ERROR; + + int db_fd = -1; + int target_fd = -1; + + unsigned long int size = 0; + long double mb; + const char *virname; + const char *filename; + struct cl_engine *engine; + struct cl_scan_options options; + char database_filepath[256]; + bool created_database = false; + + STATBUF st; + char *mem = NULL; + ssize_t bytes_read; + cl_fmap_t *map = NULL; + + if (argc != 2) { + printf("Usage: %s file\n", argv[0]); + return 2; + } + + filename = argv[1]; + + if ((target_fd = open(argv[1], O_RDONLY)) == -1) { + printf("Can't open file %s\n", argv[1]); + goto done; + } + + if (FSTAT(target_fd, &st)) { + printf("fmap: fstat failed\n"); + goto done; + } + + if (NULL == (mem = malloc((size_t)st.st_size))) { + printf("malloc failed, buffer size: %zu\n", (size_t)st.st_size); + goto done; + } + + bytes_read = read(target_fd, mem, (size_t)st.st_size); + if (bytes_read != (ssize_t)st.st_size) { + printf("read failed, buffer size: %zu\n", (size_t)st.st_size); + goto done; + } + + map = cl_fmap_open_memory(mem, (size_t)st.st_size); + + if (CL_SUCCESS != (ret = cl_init(CL_INIT_DEFAULT))) { + printf("Can't initialize libclamav: %s\n", cl_strerror(ret)); + goto done; + } + + if (!(engine = cl_engine_new())) { + printf("Can't create new engine\n"); + goto done; + } + + /* Example version macro usage to determine if new feature is available */ +#if defined(LIBCLAMAV_VERSION_NUM) && (LIBCLAMAV_VERSION_NUM >= 0x090400) + /* Example feature usage lowering max scan time to 15 seconds. */ + cl_engine_set_num(engine, CL_ENGINE_MAX_SCANTIME, 15000); +#endif + cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); + cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); + + /* load a pwdb signature, to demonstrate the "was decrypted" feature */ +#define PWDB_FILENAME "./ex3.pwdb" + unsigned int signo = 0; + if (-1 == (db_fd = open(PWDB_FILENAME, O_CREAT | O_RDWR, 0600))) { + printf("Failed to create ex3.pwdb database\n"); + goto done; + } + +#define PWDB_SIGNATURE "SignatureName;Engine:80-1000;0;virus" + if (-1 == write(db_fd, PWDB_SIGNATURE, strlen(PWDB_SIGNATURE))) { + printf("Failed write to ex3.pwdb database\n"); + goto done; + } + + if (CL_SUCCESS != (ret = cl_load(PWDB_FILENAME, engine, &signo, CL_DB_STDOPT))) { + printf("Database load error: %s\n", cl_strerror(ret)); + goto done; + } + + close(db_fd); + + /* build engine */ + if (CL_SUCCESS != (ret = cl_engine_compile(engine))) { + printf("Database initialization error: %s\n", cl_strerror(ret)); + goto done; + } + + /* scan file descriptor */ + memset(&options, 0, sizeof(struct cl_scan_options)); + options.parse |= ~0; /* enable all parsers */ + options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */ + options.general |= CL_SCAN_GENERAL_ALLMATCHES; /* run in all-match mode, so it keeps looking for alerts after the first one */ + options.general |= CL_SCAN_GENERAL_COLLECT_METADATA; /* collect metadata may enable collecting additional filenames (like in zip) */ + + options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE; + options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED_DOC; + + /* + * Set our callbacks for inspecting embedded files during the scan. + */ + cl_engine_set_clcb_file_inspection(engine, &inspection_callback); + /* + * Set our callbacks for inspecting embedded files during the scan. + */ + cl_engine_set_clcb_post_scan(engine, &post_callback); + + printf("Testing file inspection on FD %d - %s\n", target_fd, filename); + + if (CL_VIRUS == (ret = cl_scanmap_callback( + map, + filename, + &virname, + &size, + engine, + &options, + (void *)"Hello, World!"))) { + printf("Virus detected: %s\n", virname); + } else { + if (ret != CL_CLEAN) { + printf("Error: %s\n", cl_strerror(ret)); + goto done; + } + } + /* calculate size of scanned data */ + mb = size * (CL_COUNT_PRECISION / 1024) / 1024.0; + printf("Data scanned: %2.2Lf MB\n", mb); + + status = ret == CL_VIRUS ? 1 : 0; + +done: + + if (NULL != map) { + cl_fmap_close(map); + } + if (NULL != mem) { + free(mem); + } + unlink(PWDB_FILENAME); + if (-1 != db_fd) { + close(db_fd); + } + if (-1 != target_fd) { + close(target_fd); + } + if (NULL != engine) { + cl_engine_free(engine); + } + if (true == created_database) { + unlink(database_filepath); + } + + return status; +} diff --git a/examples/ex_prescan_callback.c b/examples/ex_prescan_callback.c new file mode 100644 index 0000000000..62901e60d6 --- /dev/null +++ b/examples/ex_prescan_callback.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * This example demonstrates using callbacks to record information about each + * file found during a recursive scan. + */ + +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include + +#include + +#ifdef _WIN32 +typedef int ssize_t; +#endif + +cl_error_t scan_callback(int fd, const char *type, void *context) +{ + char buf[10]; + ssize_t bytes_read = 0; + (void)context; /* Could be used to retrieve/store info */ + + printf("fd: %u, type: %s, initial bytes: ", fd, type); + if (-1 != (bytes_read = read(fd, &buf, sizeof(buf)))) { + /* Was able to read a few bytes */ + ssize_t i = 0; + for (i = 0; i < bytes_read; i++) { + printf("%02x", (unsigned int)buf[i]); + } + printf("\n"); + } + return CL_CLEAN; /* keep scanning */ +} + +/* + * Exit codes: + * 0: clean + * 1: infected + * 2: error + */ + +int main(int argc, char **argv) +{ + int status = 2; + cl_error_t ret = CL_ERROR; + + char *db_filepath = NULL; + int db_fd = -1; + int target_fd = -1; + + unsigned long int size = 0; + long double mb; + const char *virname; + const char *filename; + struct cl_engine *engine; + struct cl_scan_options options; + + if (argc != 2) { + printf("Usage: %s file\n", argv[0]); + return 2; + } + + filename = argv[1]; + + if ((target_fd = open(argv[1], O_RDONLY)) == -1) { + printf("Can't open file %s\n", argv[1]); + goto done; + } + + if (CL_SUCCESS != (ret = cl_init(CL_INIT_DEFAULT))) { + printf("Can't initialize libclamav: %s\n", cl_strerror(ret)); + goto done; + } + + if (!(engine = cl_engine_new())) { + printf("Can't create new engine\n"); + goto done; + } + + /* Example version macro usage to determine if new feature is available */ +#if defined(LIBCLAMAV_VERSION_NUM) && (LIBCLAMAV_VERSION_NUM >= 0x090400) + /* Example feature usage lowering max scan time to 15 seconds. */ + cl_engine_set_num(engine, CL_ENGINE_MAX_SCANTIME, 15000); +#endif + cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); + cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); + + /* build engine */ + if (CL_SUCCESS != (ret = cl_engine_compile(engine))) { + printf("Database initialization error: %s\n", cl_strerror(ret)); + goto done; + } + + /* scan file descriptor */ + memset(&options, 0, sizeof(struct cl_scan_options)); + options.parse |= ~0; /* enable all parsers */ + options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */ + options.general |= CL_SCAN_GENERAL_ALLMATCHES; /* run in all-match mode, so it keeps looking for alerts after the first one */ + options.general |= CL_SCAN_GENERAL_COLLECT_METADATA; /* collect metadata may enable collecting additional filenames (like in zip) */ + + /* + * Set our callbacks for inspecting embedded files during the scan. + */ + cl_engine_set_clcb_pre_scan(engine, &scan_callback); + + printf("Testing prescan on FD %d - %s\n", target_fd, filename); + + if (CL_VIRUS == (ret = cl_scandesc(target_fd, filename, &virname, &size, engine, &options))) { + printf("Virus detected: %s\n", virname); + } else { + if (ret != CL_CLEAN) { + printf("Error: %s\n", cl_strerror(ret)); + goto done; + } + } + /* calculate size of scanned data */ + mb = size * (CL_COUNT_PRECISION / 1024) / 1024.0; + printf("Data scanned: %2.2Lf MB\n", mb); + + status = ret == CL_VIRUS ? 1 : 0; + +done: + + if (-1 != db_fd) { + close(db_fd); + } + if (-1 != target_fd) { + close(target_fd); + } + if (NULL != engine) { + cl_engine_free(engine); + } + if (NULL != db_filepath) { + free(db_filepath); + } + + return status; +} diff --git a/libclamav/7z_iface.c b/libclamav/7z_iface.c index 69a3c8c721..d82134f785 100644 --- a/libclamav/7z_iface.c +++ b/libclamav/7z_iface.c @@ -191,7 +191,7 @@ int cli_7unz(cli_ctx *ctx, size_t offset) cli_dbgmsg("cli_7unz: Saving to %s\n", tmp_name); if (cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed) found = CL_EWRITE; - else if ((found = cli_magic_scan_desc(fd, tmp_name, ctx, name)) == CL_VIRUS) + else if (CL_VIRUS == (found = cli_magic_scan_desc(fd, tmp_name, ctx, name, LAYER_ATTRIBUTES_NONE))) viruses_found++; close(fd); if (!ctx->engine->keeptmp && cli_unlink(tmp_name)) diff --git a/libclamav/apm.c b/libclamav/apm.c index c4f738df4c..9297fc3c76 100644 --- a/libclamav/apm.c +++ b/libclamav/apm.c @@ -223,7 +223,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret != CL_CLEAN) { if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) detection = CL_VIRUS; diff --git a/libclamav/autoit.c b/libclamav/autoit.c index 5d93517c25..ad34f0e196 100644 --- a/libclamav/autoit.c +++ b/libclamav/autoit.c @@ -857,7 +857,7 @@ static int ea05(cli_ctx *ctx, const uint8_t *base, char *tmpd) close(i); return CL_ESEEK; } - if (cli_magic_scan_desc(i, tempfile, ctx, NULL) == CL_VIRUS) { + if (CL_VIRUS == cli_magic_scan_desc(i, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE)) { if (!SCAN_ALLMATCHES) { close(i); if (!ctx->engine->keeptmp) @@ -1474,7 +1474,7 @@ static int ea06(cli_ctx *ctx, const uint8_t *base, char *tmpd) close(i); return CL_ESEEK; } - if (cli_magic_scan_desc(i, tempfile, ctx, NULL) == CL_VIRUS) { + if (CL_VIRUS == cli_magic_scan_desc(i, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE)) { if (!SCAN_ALLMATCHES) { close(i); if (!ctx->engine->keeptmp) diff --git a/libclamav/binhex.c b/libclamav/binhex.c index 98d04a32b5..8c117ed373 100644 --- a/libclamav/binhex.c +++ b/libclamav/binhex.c @@ -122,7 +122,7 @@ int cli_binhex(cli_ctx *ctx) ret = CL_ESEEK; break; } - ret = cli_magic_scan_desc(datafd, dname, ctx, NULL); + ret = cli_magic_scan_desc(datafd, dname, ctx, NULL, LAYER_ATTRIBUTES_NONE); if (ret == CL_VIRUS) break; } if (dec_done) @@ -168,7 +168,7 @@ int cli_binhex(cli_ctx *ctx) ret = CL_ESEEK; break; } - ret = cli_magic_scan_desc(resfd, rname, ctx, NULL); + ret = cli_magic_scan_desc(resfd, rname, ctx, NULL, LAYER_ATTRIBUTES_NONE); break; } } @@ -180,7 +180,7 @@ int cli_binhex(cli_ctx *ctx) ret = CL_ESEEK; break; } - ret = cli_magic_scan_desc(datafd, dname, ctx, NULL); + ret = cli_magic_scan_desc(datafd, dname, ctx, NULL, LAYER_ATTRIBUTES_NONE); } else if (write_phase == IN_RES) { cli_dbgmsg("cli_binhex: scanning partially extracted resource fork\n"); if (lseek(resfd, 0, SEEK_SET) == -1) { @@ -188,7 +188,7 @@ int cli_binhex(cli_ctx *ctx) ret = CL_ESEEK; break; } - ret = cli_magic_scan_desc(resfd, rname, ctx, NULL); + ret = cli_magic_scan_desc(resfd, rname, ctx, NULL, LAYER_ATTRIBUTES_NONE); } break; } diff --git a/libclamav/blob.c b/libclamav/blob.c index 5d583ecd72..b1d3ca05bb 100644 --- a/libclamav/blob.c +++ b/libclamav/blob.c @@ -661,7 +661,7 @@ int fileblobScan(const fileblob *fb) virus_found = 1; } - rc = cli_magic_scan_desc(fb->fd, fb->fullname, fb->ctx, fb->b.name); + rc = cli_magic_scan_desc(fb->fd, fb->fullname, fb->ctx, fb->b.name, LAYER_ATTRIBUTES_NONE); if (rc == CL_VIRUS || virus_found != 0) { cli_dbgmsg("%s is infected\n", fb->fullname); return CL_VIRUS; diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c index 30cab344ee..446bace96e 100644 --- a/libclamav/bytecode.c +++ b/libclamav/bytecode.c @@ -165,16 +165,14 @@ 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); + ret = cli_scan_desc(fd, cctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED); if (ret == CL_CLEAN) { if (lseek(fd, 0, SEEK_SET) == -1) cli_dbgmsg("cli_bytecode: call to lseek() has failed\n"); else { - 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); + ret = cli_scan_desc(fd, cctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED); } } close(fd); @@ -2910,7 +2908,7 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c lseek(fd, 0, SEEK_SET); cli_dbgmsg("***** Scanning unpacked file ******\n"); - ret = cli_magic_scan_desc(fd, tempfile, cctx, NULL); + ret = cli_magic_scan_desc(fd, tempfile, cctx, NULL, LAYER_ATTRIBUTES_NONE); if (!cctx->engine->keeptmp) if (ftruncate(fd, 0) == -1) diff --git a/libclamav/bytecode_api.c b/libclamav/bytecode_api.c index 23da485b56..f59ff11dc9 100644 --- a/libclamav/bytecode_api.c +++ b/libclamav/bytecode_api.c @@ -550,7 +550,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) { - res = cli_magic_scan_desc_type(ctx->outfd, ctx->tempfile, cctx, ctx->containertype, NULL); + res = cli_magic_scan_desc_type(ctx->outfd, ctx->tempfile, cctx, ctx->containertype, NULL, LAYER_ATTRIBUTES_NONE); if (res == CL_VIRUS) { ctx->virname = cli_get_last_virus(cctx); ctx->found = 1; diff --git a/libclamav/clamav.h b/libclamav/clamav.h index c1d25d51f7..aa9439e536 100644 --- a/libclamav/clamav.h +++ b/libclamav/clamav.h @@ -489,6 +489,46 @@ typedef cl_error_t (*clcb_pre_cache)(int fd, const char *type, void *context); */ extern void cl_engine_set_clcb_pre_cache(struct cl_engine *engine, clcb_pre_cache callback); +/* + * Attributes of each layer in scan. + */ +#define LAYER_ATTRIBUTES_NONE 0x0 +#define LAYER_ATTRIBUTES_NORMALIZED 0x1 /** This layer was modified to make matching more generic, reliable. */ +#define LAYER_ATTRIBUTES_DECRYPTED 0x2 /** Decryption was used to extract this layer. I.e. had to decrypt some previous layer. */ + +/** + * @brief Pre-scan callback. + * + * Called for each NEW file (inner and outer). + * Provides capability to record embedded file information during a scan. + * + * @param fd Current file descriptor which is about to be scanned. + * @param type Current file type detected via magic - i.e. NOT on the fly - (e.g. "CL_TYPE_MSEXE"). + * @param ancestors An array of ancestors filenames of size `recursion_level`. filenames may be NULL. + * @param parent_file_size Parent file size. + * @param file_name Current file name, or NULL if the file does not have a name or ClamAV failed to record the name. + * @param file_size Current file size. + * @param file_buffer Current file buffer pointer. + * @param recursion_level Recursion level / depth of the current file. + * @param layer_attributes See LAYER_ATTRIBUTES_* flags. + * @param context Opaque application provided data. + * @return CL_CLEAN = File is scanned. + * @return CL_BREAK = Whitelisted by callback - file is skipped and marked as clean. + * @return CL_VIRUS = Blacklisted by callback - file is skipped and marked as infected. + */ +typedef cl_error_t (*clcb_file_inspection)(int fd, const char *type, const char **ancestors, size_t parent_file_size, + const char *file_name, size_t file_size, const char *file_buffer, + uint32_t recursion_level, uint32_t layer_attributes, void *context); +/** + * @brief Set a custom file inspection callback function. + * + * Caution: changing options for an engine that is in-use is not thread-safe! + * + * @param engine The initialized scanning engine. + * @param callback The callback function pointer. + */ +extern void cl_engine_set_clcb_file_inspection(struct cl_engine *engine, clcb_file_inspection callback); + /** * @brief Pre-scan callback. * diff --git a/libclamav/cpio.c b/libclamav/cpio.c index 3c6cd2af8b..a691144854 100644 --- a/libclamav/cpio.c +++ b/libclamav/cpio.c @@ -168,7 +168,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret == CL_VIRUS) { if (!SCAN_ALLMATCHES) return ret; @@ -259,7 +260,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret == CL_VIRUS) { if (!SCAN_ALLMATCHES) return ret; @@ -352,7 +354,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret == CL_VIRUS) { if (!SCAN_ALLMATCHES) return ret; diff --git a/libclamav/dmg.c b/libclamav/dmg.c index 7b882022da..0c44e1dfa7 100644 --- a/libclamav/dmg.c +++ b/libclamav/dmg.c @@ -179,7 +179,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret != CL_CLEAN) { cli_dbgmsg("cli_scandmg: retcode from scanning TOC xml: %s\n", cl_strerror(ret)); if (!ctx->engine->keeptmp) @@ -1083,7 +1084,7 @@ static int dmg_handle_mish(cli_ctx *ctx, unsigned int mishblocknum, char *dir, /* If okay so far, scan rebuilt partition */ if (ret == CL_CLEAN) { /* Have to keep partition typing separate */ - ret = cli_magic_scan_desc_type(ofd, outfile, ctx, CL_TYPE_PART_ANY, NULL); + ret = cli_magic_scan_desc_type(ofd, outfile, ctx, CL_TYPE_PART_ANY, NULL, LAYER_ATTRIBUTES_NONE); } close(ofd); diff --git a/libclamav/elf.c b/libclamav/elf.c index f9ead2c0dd..c5b428a671 100644 --- a/libclamav/elf.c +++ b/libclamav/elf.c @@ -870,7 +870,7 @@ int cli_unpackelf(cli_ctx *ctx) cli_dbgmsg("cli_scanelf: Unpacked and rebuilt executable\n"); lseek(ndesc, 0, SEEK_SET); cli_dbgmsg("***** Scanning rebuilt ELF file *****\n"); - if (cli_magic_scan_desc(ndesc, tempfile, ctx, NULL) == CL_VIRUS) { + if (CL_VIRUS == cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE)) { close(ndesc); CLI_TMPUNLK(); free(tempfile); diff --git a/libclamav/events.h b/libclamav/events.h index 4df739fbe3..e7a54417a3 100644 --- a/libclamav/events.h +++ b/libclamav/events.h @@ -106,6 +106,7 @@ int cli_event_errors(cli_events_t *ctx); enum perfev { PERFT_SCAN, + PERFT_INSPECT, PERFT_PRECB, PERFT_POSTCB, PERFT_CACHE, diff --git a/libclamav/gif.c b/libclamav/gif.c index d608ce91a4..21c75a7edb 100644 --- a/libclamav/gif.c +++ b/libclamav/gif.c @@ -416,8 +416,11 @@ cl_error_t cli_parsegif(cli_ctx *ctx) // Is there an overlay? if (offset < map->len) { cli_dbgmsg("GIF: Found extra data after the end of the GIF data stream: %zu bytes, we'll scan it!\n", map->len - offset); - cl_error_t nested_scan_result = cli_magic_scan_nested_fmap_type(map, offset, map->len - offset, ctx, CL_TYPE_ANY, NULL); - status = nested_scan_result != CL_SUCCESS ? nested_scan_result : status; + cl_error_t nested_scan_result = cli_magic_scan_nested_fmap_type(map, offset, map->len - offset, + ctx, CL_TYPE_ANY, NULL, + LAYER_ATTRIBUTES_NONE); + + status = nested_scan_result != CL_SUCCESS ? nested_scan_result : status; } done: diff --git a/libclamav/gpt.c b/libclamav/gpt.c index 0540d26b08..378fb5e14f 100644 --- a/libclamav/gpt.c +++ b/libclamav/gpt.c @@ -344,7 +344,9 @@ 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, LAYER_ATTRIBUTES_NONE); if (NULL != namestr) { free(namestr); } diff --git a/libclamav/hfsplus.c b/libclamav/hfsplus.c index 406789e089..47fbe13352 100644 --- a/libclamav/hfsplus.c +++ b/libclamav/hfsplus.c @@ -433,7 +433,7 @@ static cl_error_t hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, *filename = tmpname; } else { if (ret == CL_CLEAN) { - ret = cli_magic_scan_desc(ofd, tmpname, ctx, orig_filename); + ret = cli_magic_scan_desc(ofd, tmpname, ctx, orig_filename, LAYER_ATTRIBUTES_NONE); } if (!ctx->engine->keeptmp) { @@ -1319,7 +1319,7 @@ static cl_error_t hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHea cli_dbgmsg("hfsplus_walk_catalog: Extracted to %s\n", tmpname); /* if successful so far, scan the output */ - ret = cli_magic_scan_desc(ofd, tmpname, ctx, name_utf8); + ret = cli_magic_scan_desc(ofd, tmpname, ctx, name_utf8, LAYER_ATTRIBUTES_NONE); if (ret == CL_VIRUS) { has_alerts = 1; diff --git a/libclamav/hwp.c b/libclamav/hwp.c index c03726ed75..d93710cff3 100644 --- a/libclamav/hwp.c +++ b/libclamav/hwp.c @@ -175,7 +175,7 @@ static cl_error_t decompress_and_callback(cli_ctx *ctx, fmap_t *input, size_t at ret = cb(cbdata, ofd, tmpname, ctx); } else { /* default to scanning what we got */ - ret = cli_magic_scan_desc(ofd, tmpname, ctx, NULL); + ret = cli_magic_scan_desc(ofd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); } /* clean-up */ @@ -293,8 +293,8 @@ cl_error_t cli_scanhwpole2(cli_ctx *ctx) else cli_dbgmsg("HWPOLE2: Matched uncompressed prefix and size: %u == %u\n", usize, asize); - return cli_magic_scan_nested_fmap_type(map, 4, 0, ctx, CL_TYPE_ANY, NULL); - // return cli_magic_scan_nested_fmap_type(map, 4, 0, ctx, CL_TYPE_OLE2); + return cli_magic_scan_nested_fmap_type(map, 4, 0, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); } /*** HWP5 ***/ @@ -374,7 +374,7 @@ static cl_error_t hwp5_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c if (fd < 0 || !ctx) return CL_ENULLARG; - return cli_magic_scan_desc(fd, filepath, ctx, NULL); + return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE); } cl_error_t cli_scanhwp5_stream(cli_ctx *ctx, hwp5_header_t *hwp5, char *name, int fd, const char *filepath) @@ -394,7 +394,7 @@ cl_error_t cli_scanhwp5_stream(cli_ctx *ctx, hwp5_header_t *hwp5, char *name, in if (hwp5->flags & HWP5_PASSWORD) { cli_dbgmsg("HWP5.x: Password encrypted stream, scanning as-is\n"); - return cli_magic_scan_desc(fd, filepath, ctx, name); + return cli_magic_scan_desc(fd, filepath, ctx, name, LAYER_ATTRIBUTES_NONE); } if (hwp5->flags & HWP5_COMPRESSED) { @@ -437,7 +437,7 @@ cl_error_t cli_scanhwp5_stream(cli_ctx *ctx, hwp5_header_t *hwp5, char *name, in } /* normal streams */ - return cli_magic_scan_desc(fd, filepath, ctx, name); + return cli_magic_scan_desc(fd, filepath, ctx, name, LAYER_ATTRIBUTES_NONE); } /*** HWP3 ***/ @@ -1642,7 +1642,8 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t #endif /* 32 bytes for extra data fields */ if (infolen > 0) - ret = cli_magic_scan_nested_fmap_type(map, *offset + 32, infolen - 32, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(map, *offset + 32, infolen - 32, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); break; case 2: /* OLE2 Data */ hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: OLE2 Data\n", infoloc); @@ -1651,7 +1652,8 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t cli_jsonstr(entry, "Type", "OLE2 Data"); #endif if (infolen > 0) - ret = cli_magic_scan_nested_fmap_type(map, *offset, infolen, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(map, *offset, infolen, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); break; case 3: /* Hypertext/Hyperlink Information */ hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Hypertext/Hyperlink Information\n", infoloc); @@ -1679,7 +1681,8 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t hwp3_debug("HWP3.x: Information Block[%llu]: %d: NAME: %s\n", infoloc, i, field); #endif /* scanning macros - TODO - check numbers */ - ret = cli_magic_scan_nested_fmap_type(map, *offset + (617 * i) + 288, 325, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(map, *offset + (617 * i) + 288, 325, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); } break; case 4: /* Presentation Information */ @@ -1716,7 +1719,8 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t #endif /* 324 bytes for extra data fields */ if (infolen > 0) - ret = cli_magic_scan_nested_fmap_type(map, *offset + 324, infolen - 324, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(map, *offset + 324, infolen - 324, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); break; case 0x100: /* Table Extension */ hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Table Extension\n", infoloc); @@ -1737,7 +1741,8 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t default: cli_warnmsg("HWP3.x: Information Block[%llu]: TYPE: UNKNOWN(%u)\n", infoloc, infoid); if (infolen > 0) - ret = cli_magic_scan_nested_fmap_type(map, *offset, infolen, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(map, *offset, infolen, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); } *offset += infolen; @@ -1860,8 +1865,8 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c cl_error_t subret = ret; size_t dlen = offset - start; - ret = cli_magic_scan_nested_fmap_type(map, start, dlen, ctx, CL_TYPE_ANY, NULL); - // ret = cli_magic_scan_nested_fmap_type(map, 0, 0, ctx, CL_TYPE_ANY); + ret = cli_magic_scan_nested_fmap_type(map, start, dlen, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); if (ret == CL_SUCCESS) ret = subret; @@ -1972,7 +1977,7 @@ static cl_error_t hwpml_scan_cb(void *cbdata, int fd, const char *filepath, cli_ if (fd < 0 || !ctx) return CL_ENULLARG; - return cli_magic_scan_desc(fd, filepath, ctx, NULL); + return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE); } static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, int num_attribs, struct attrib_entry *attribs, void *cbdata) @@ -2008,7 +2013,7 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in /* decode the binary data if needed - base64 */ if (enc < 0) { cli_errmsg("HWPML: Unrecognized encoding method\n"); - return cli_magic_scan_desc(fd, filepath, ctx, NULL); + return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE); } else if (enc == 1) { STATBUF statbuf; fmap_t *input; @@ -2040,7 +2045,7 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in funmap(input); if (!decoded) { cli_errmsg("HWPML: Failed to get base64 decode binary data\n"); - return cli_magic_scan_desc(fd, filepath, ctx, NULL); + return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE); } /* open file for writing and scanning */ diff --git a/libclamav/ishield.c b/libclamav/ishield.c index dcdff6458a..f831f8f111 100644 --- a/libclamav/ishield.c +++ b/libclamav/ishield.c @@ -311,7 +311,7 @@ int cli_scanishield_msi(cli_ctx *ctx, off_t off) cli_dbgmsg("ishield-msi: call to lseek() failed\n"); ret = CL_ESEEK; } - ret = cli_magic_scan_desc(ofd, tempfile, ctx, filename); + ret = cli_magic_scan_desc(ofd, tempfile, ctx, filename, LAYER_ATTRIBUTES_NONE); } close(ofd); @@ -502,7 +502,7 @@ static int is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize) cli_dbgmsg("ishield: call to lseek() failed\n"); ret = CL_ESEEK; } - ret = cli_magic_scan_desc(ofd, fname, ctx, NULL); + ret = cli_magic_scan_desc(ofd, fname, ctx, NULL, LAYER_ATTRIBUTES_NONE); } close(ofd); if (!ctx->engine->keeptmp) @@ -802,7 +802,7 @@ static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t cs cli_dbgmsg("is_extract_cab: extracted to %s\n", tempfile); if (lseek(ofd, 0, SEEK_SET) == -1) cli_dbgmsg("is_extract_cab: call to lseek() failed\n"); - ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL); + ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE); } close(ofd); diff --git a/libclamav/iso9660.c b/libclamav/iso9660.c index 9a74fbc70c..51938f4978 100644 --- a/libclamav/iso9660.c +++ b/libclamav/iso9660.c @@ -82,7 +82,7 @@ static int iso_scan_file(const iso9660_t *iso, unsigned int block, unsigned int } if (!len) - ret = cli_magic_scan_desc(fd, tmpf, iso->ctx, iso->buf); + ret = cli_magic_scan_desc(fd, tmpf, iso->ctx, iso->buf, LAYER_ATTRIBUTES_NONE); close(fd); if (!iso->ctx->engine->keeptmp) { diff --git a/libclamav/jpeg.c b/libclamav/jpeg.c index 3f41e4ca3c..5f9ee1624f 100644 --- a/libclamav/jpeg.c +++ b/libclamav/jpeg.c @@ -303,7 +303,8 @@ static cl_error_t jpeg_check_photoshop_8bim(cli_ctx *ctx, size_t *off) offset += 4 + 28; /* Scan the thumbnail JPEG */ - retval = cli_magic_scan_nested_fmap_type(map, offset, 0, ctx, CL_TYPE_JPEG, "photoshop-thumbnail"); + retval = cli_magic_scan_nested_fmap_type(map, offset, 0, ctx, CL_TYPE_JPEG, + "photoshop-thumbnail", LAYER_ATTRIBUTES_NONE); return retval; } diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map index 27591f69d3..05519b240a 100644 --- a/libclamav/libclamav.map +++ b/libclamav/libclamav.map @@ -15,6 +15,7 @@ CLAMAV_PUBLIC { cl_engine_set_clcb_meta; cl_engine_set_clcb_file_props; cl_set_clcb_msg; + cl_engine_set_clcb_file_inspection; cl_engine_set_clcb_pre_scan; cl_engine_set_clcb_post_scan; cl_engine_set_clcb_virus_found; diff --git a/libclamav/libmspack.c b/libclamav/libmspack.c index e26fd74e37..04a28e0476 100644 --- a/libclamav/libmspack.c +++ b/libclamav/libmspack.c @@ -432,7 +432,7 @@ int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset) /* Failed to extract. Try to scan what is there */ cli_dbgmsg("%s() failed to extract %d\n", __func__, ret); - ret = cli_magic_scan_file(tmp_fname, ctx, cab_f->filename); + ret = cli_magic_scan_file(tmp_fname, ctx, cab_f->filename, LAYER_ATTRIBUTES_NONE); if (CL_EOPEN == ret) { ret = CL_CLEAN; } else if (CL_VIRUS == ret) { @@ -549,7 +549,7 @@ int cli_scanmschm(cli_ctx *ctx) /* Failed to extract. Try to scan what is there */ cli_dbgmsg("%s() failed to extract %d\n", __func__, ret); - ret = cli_magic_scan_file(tmp_fname, ctx, mschm_f->filename); + ret = cli_magic_scan_file(tmp_fname, ctx, mschm_f->filename, LAYER_ATTRIBUTES_NONE); if (CL_EOPEN == ret) { ret = CL_CLEAN; } else if (CL_VIRUS == ret) { diff --git a/libclamav/macho.c b/libclamav/macho.c index 2922cd4a63..5ebbfc71a8 100644 --- a/libclamav/macho.c +++ b/libclamav/macho.c @@ -569,7 +569,8 @@ int cli_scanmacho_unibin(cli_ctx *ctx) RETURN_BROKEN; } - ret = cli_magic_scan_nested_fmap_type(map, fat_arch.offset, fat_arch.size, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_nested_fmap_type(map, fat_arch.offset, fat_arch.size, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); if (ret == CL_VIRUS) break; } @@ -608,7 +609,7 @@ int cli_unpackmacho(cli_ctx *ctx) cli_dbgmsg("cli_scanmacho: Unpacked and rebuilt executable\n"); lseek(ndesc, 0, SEEK_SET); cli_dbgmsg("***** Scanning rebuilt Mach-O file *****\n"); - if (cli_magic_scan_desc(ndesc, tempfile, ctx, NULL) == CL_VIRUS) { + if (CL_VIRUS == cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE)) { close(ndesc); CLI_TMPUNLK(); free(tempfile); diff --git a/libclamav/matcher.c b/libclamav/matcher.c index 68fa5f3173..f7d7bf607b 100644 --- a/libclamav/matcher.c +++ b/libclamav/matcher.c @@ -769,7 +769,8 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t return (int32_t)ret; } -cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name) +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, uint32_t attributes) { cl_error_t status = CL_CLEAN; int empty; @@ -785,7 +786,7 @@ cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonl goto done; } - status = cli_recursion_stack_push(ctx, new_map, ftype, true); /* Perform scan with child fmap */ + status = cli_recursion_stack_push(ctx, new_map, ftype, true, attributes); /* Perform scan with child fmap */ if (CL_SUCCESS != status) { cli_dbgmsg("cli_scan_desc: Failed to scan fmap.\n"); goto done; @@ -877,7 +878,7 @@ static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a 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 */ + status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true, LAYER_ATTRIBUTES_NONE); /* Perform scan with child fmap */ if (CL_SUCCESS != status) { cli_dbgmsg("Failed to re-scan fmap as a new type.\n"); goto done; diff --git a/libclamav/matcher.h b/libclamav/matcher.h index 896eb39709..a04373f99a 100644 --- a/libclamav/matcher.h +++ b/libclamav/matcher.h @@ -283,9 +283,11 @@ cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t * @param acmode Use AC_SCAN_VIR and AC_SCAN_FT to set scanning modes. * @param[out] acres A list of cli_ac_result AC pattern matching results. * @param name (optional) Original name of the file (to set fmap name metadata) + * @param attributes Layer attributes for the thing to be scanned. * @return cl_error_t */ -cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name); +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, uint32_t attributes); /** * @brief Non-magic scan matching of the current fmap in the scan context. Newer API. diff --git a/libclamav/mbr.c b/libclamav/mbr.c index 26fa332361..97395499a3 100644 --- a/libclamav/mbr.c +++ b/libclamav/mbr.c @@ -184,7 +184,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret != CL_CLEAN) { if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) detection = CL_VIRUS; @@ -240,7 +241,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret != CL_CLEAN) { if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) detection = CL_VIRUS; @@ -381,7 +383,8 @@ 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, LAYER_ATTRIBUTES_NONE); if (ret != CL_CLEAN) { if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) detection = CL_VIRUS; diff --git a/libclamav/msxml_parser.c b/libclamav/msxml_parser.c index 04ec738a57..0049af88e9 100644 --- a/libclamav/msxml_parser.c +++ b/libclamav/msxml_parser.c @@ -462,7 +462,7 @@ static int msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr reader, cli_dbgmsg("msxml_parse_element: extracted binary data to %s\n", tempfile); - ret = cli_magic_scan_desc(of, tempfile, ctx, NULL); + ret = cli_magic_scan_desc(of, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE); close(of); if (!(ctx->engine->keeptmp)) cli_unlink(tempfile); diff --git a/libclamav/nsis/nulsft.c b/libclamav/nsis/nulsft.c index fab42e6bbc..6655b6b34d 100644 --- a/libclamav/nsis/nulsft.c +++ b/libclamav/nsis/nulsft.c @@ -546,9 +546,9 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset) return CL_ESEEK; } if (nsist.fno == 1) - ret = cli_scan_desc(nsist.ofd, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, NULL); /// TODO: Extract file names + ret = cli_scan_desc(nsist.ofd, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names else - ret = cli_magic_scan_desc(nsist.ofd, nsist.ofn, ctx, NULL); /// TODO: Extract file names + ret = cli_magic_scan_desc(nsist.ofd, nsist.ofn, ctx, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names close(nsist.ofd); if (!ctx->engine->keeptmp) if (cli_unlink(nsist.ofn)) ret = CL_EUNLINK; diff --git a/libclamav/ole2_extract.c b/libclamav/ole2_extract.c index 3f3fa8795a..e4bcd8fa41 100644 --- a/libclamav/ole2_extract.c +++ b/libclamav/ole2_extract.c @@ -1503,7 +1503,7 @@ static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx) } /* scanning inflated stream */ - ret = cli_magic_scan_desc(ofd, tmpname, ctx, NULL); + ret = cli_magic_scan_desc(ofd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); /* clean-up */ mso_end: @@ -1666,7 +1666,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char * ret = scan_mso_stream(ofd, ctx); } else { /* Normal File Scan */ - ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL); + ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE); } ret = ret == CL_VIRUS ? CL_VIRUS : CL_SUCCESS; diff --git a/libclamav/ooxml.c b/libclamav/ooxml.c index 644779432c..de56860677 100644 --- a/libclamav/ooxml.c +++ b/libclamav/ooxml.c @@ -146,12 +146,13 @@ static cl_error_t ooxml_parse_document(int fd, cli_ctx *ctx) return ret; } -static cl_error_t ooxml_core_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name) +static cl_error_t ooxml_core_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name, uint32_t attributes) { cl_error_t ret; UNUSEDPARAM(filepath); UNUSEDPARAM(name); + UNUSEDPARAM(attributes); cli_dbgmsg("in ooxml_core_cb\n"); ret = ooxml_parse_document(fd, ctx); @@ -163,12 +164,13 @@ static cl_error_t ooxml_core_cb(int fd, const char *filepath, cli_ctx *ctx, cons return ret; } -static cl_error_t ooxml_extn_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name) +static cl_error_t ooxml_extn_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name, uint32_t attributes) { cl_error_t ret; UNUSEDPARAM(filepath); UNUSEDPARAM(name); + UNUSEDPARAM(attributes); cli_dbgmsg("in ooxml_extn_cb\n"); ret = ooxml_parse_document(fd, ctx); @@ -180,7 +182,7 @@ static cl_error_t ooxml_extn_cb(int fd, const char *filepath, cli_ctx *ctx, cons return ret; } -static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name) +static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name, uint32_t attributes) { cl_error_t ret = CL_SUCCESS; int tmp, toval = 0, state; @@ -192,6 +194,7 @@ static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, c UNUSEDPARAM(filepath); UNUSEDPARAM(name); + UNUSEDPARAM(attributes); unsigned long sav_scansize = ctx->scansize; unsigned int sav_scannedfiles = ctx->scannedfiles; @@ -351,13 +354,14 @@ static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, c return ret; } -static cl_error_t ooxml_hwp_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name) +static cl_error_t ooxml_hwp_cb(int fd, const char *filepath, cli_ctx *ctx, const char *name, uint32_t attributes) { cl_error_t ret = CL_SUCCESS; xmlTextReaderPtr reader = NULL; UNUSEDPARAM(filepath); UNUSEDPARAM(name); + UNUSEDPARAM(attributes); cli_dbgmsg("in ooxml_hwp_cb\n"); diff --git a/libclamav/others.c b/libclamav/others.c index 39129d546b..7ea357689a 100644 --- a/libclamav/others.c +++ b/libclamav/others.c @@ -1381,7 +1381,7 @@ const char *cli_get_last_virus_str(const cli_ctx *ctx) return ""; } -cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t type, bool is_new_buffer) +cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t type, bool is_new_buffer, uint32_t attributes) { cl_error_t status = CL_SUCCESS; @@ -1422,17 +1422,23 @@ cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t typ 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; + // Apply the requested next-layer attributes. + // + // Note that this is how we also keep track of normalized layers. + // 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->attributes = attributes; + + // If the current layer is marked "decrypted", all child-layers are also marked "decrypted". + if (current_container->attributes & LAYER_ATTRIBUTES_DECRYPTED) { + new_container->attributes |= LAYER_ATTRIBUTES_DECRYPTED; } ctx->fmap = new_container->fmap; done: + return status; } @@ -1497,7 +1503,7 @@ static int recursion_stack_get(cli_ctx *ctx, int index) } while (current_layer >= desired_layer && current_layer > 0) { - if (ctx->recursion_stack[current_layer].is_normalized_layer) { + if (ctx->recursion_stack[current_layer].attributes & LAYER_ATTRIBUTES_NORMALIZED) { // The current layer is normalized, so we should step back an extra layer // It's okay if desired_layer goes negative. desired_layer--; @@ -1778,6 +1784,11 @@ void cl_engine_set_clcb_pre_cache(struct cl_engine *engine, clcb_pre_cache callb engine->cb_pre_cache = callback; } +void cl_engine_set_clcb_file_inspection(struct cl_engine *engine, clcb_file_inspection callback) +{ + engine->cb_file_inspection = callback; +} + void cl_engine_set_clcb_pre_scan(struct cl_engine *engine, clcb_pre_scan callback) { engine->cb_pre_scan = callback; diff --git a/libclamav/others.h b/libclamav/others.h index d4c71b1a7d..ff041571a0 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -185,7 +185,7 @@ typedef struct recursion_level_tag { 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. */ + uint32_t attributes; /* layer attributes. */ image_fuzzy_hash_t image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */ bool calculated_image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */ } recursion_level_t; @@ -209,7 +209,6 @@ typedef struct cli_ctx_tag { 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; bitset_t *hook_lsig_matches; @@ -408,6 +407,7 @@ struct cl_engine { crtmgr cmgr; /* Callback(s) */ + clcb_file_inspection cb_file_inspection; clcb_pre_cache cb_pre_cache; clcb_pre_scan cb_pre_scan; clcb_post_scan cb_post_scan; @@ -745,9 +745,10 @@ void cli_virus_found_cb(cli_ctx *ctx); * @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. + * @param attributes Layer attributes for the thing to be scanned. * @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); +cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t type, bool is_new_buffer, uint32_t attributes); /** * @brief Pop off a layer of our scan recursion stack. diff --git a/libclamav/pdf.c b/libclamav/pdf.c index d36cf519c0..de37f23826 100644 --- a/libclamav/pdf.c +++ b/libclamav/pdf.c @@ -1419,7 +1419,7 @@ static int pdf_scan_contents(int fd, struct pdf_struct *pdf) cli_writen(fout, s.out, s.out_pos); lseek(fout, 0, SEEK_SET); - rc = cli_magic_scan_desc(fout, fullname, pdf->ctx, NULL); + rc = cli_magic_scan_desc(fout, fullname, pdf->ctx, NULL, LAYER_ATTRIBUTES_NONE); close(fout); if (!pdf->ctx->engine->keeptmp || (s.out_pos == 0)) @@ -1814,7 +1814,7 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t /* 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); + rc2 = cli_magic_scan_desc(fout, fullname, pdf->ctx, NULL, LAYER_ATTRIBUTES_NONE); if (rc2 == CL_VIRUS || rc == CL_SUCCESS) rc = rc2; diff --git a/libclamav/pe.c b/libclamav/pe.c index 1f85004d5f..27a57a002c 100644 --- a/libclamav/pe.c +++ b/libclamav/pe.c @@ -191,44 +191,44 @@ free(tempfile); \ break; -#define CLI_UNPRESULTS_(NAME, FSGSTUFF, EXPR, GOOD, FREEME) \ - switch (EXPR) { \ - case GOOD: /* Unpacked and rebuilt */ \ - if (ctx->engine->keeptmp) \ - cli_dbgmsg(NAME ": Unpacked and rebuilt executable saved in %s\n", tempfile); \ - else \ - cli_dbgmsg(NAME ": Unpacked and rebuilt executable\n"); \ - cli_multifree FREEME; \ - cli_exe_info_destroy(peinfo); \ - lseek(ndesc, 0, SEEK_SET); \ - cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \ - SHA_OFF; \ - if (cli_magic_scan_desc(ndesc, tempfile, ctx, NULL) == CL_VIRUS) { \ - close(ndesc); \ - SHA_RESET; \ - CLI_TMPUNLK(); \ - free(tempfile); \ - return CL_VIRUS; \ - } \ - SHA_RESET; \ - close(ndesc); \ - CLI_TMPUNLK(); \ - free(tempfile); \ - return CL_CLEAN; \ - \ - FSGSTUFF; \ - \ - default: \ - cli_dbgmsg(NAME ": Unpacking failed\n"); \ - close(ndesc); \ - if (cli_unlink(tempfile)) { \ - cli_exe_info_destroy(peinfo); \ - free(tempfile); \ - cli_multifree FREEME; \ - return CL_EUNLINK; \ - } \ - cli_multifree FREEME; \ - free(tempfile); \ +#define CLI_UNPRESULTS_(NAME, FSGSTUFF, EXPR, GOOD, FREEME) \ + switch (EXPR) { \ + case GOOD: /* Unpacked and rebuilt */ \ + if (ctx->engine->keeptmp) \ + cli_dbgmsg(NAME ": Unpacked and rebuilt executable saved in %s\n", tempfile); \ + else \ + cli_dbgmsg(NAME ": Unpacked and rebuilt executable\n"); \ + cli_multifree FREEME; \ + cli_exe_info_destroy(peinfo); \ + lseek(ndesc, 0, SEEK_SET); \ + cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \ + SHA_OFF; \ + if (CL_VIRUS == cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE)) { \ + close(ndesc); \ + SHA_RESET; \ + CLI_TMPUNLK(); \ + free(tempfile); \ + return CL_VIRUS; \ + } \ + SHA_RESET; \ + close(ndesc); \ + CLI_TMPUNLK(); \ + free(tempfile); \ + return CL_CLEAN; \ + \ + FSGSTUFF; \ + \ + default: \ + cli_dbgmsg(NAME ": Unpacking failed\n"); \ + close(ndesc); \ + if (cli_unlink(tempfile)) { \ + cli_exe_info_destroy(peinfo); \ + free(tempfile); \ + cli_multifree FREEME; \ + return CL_EUNLINK; \ + } \ + cli_multifree FREEME; \ + free(tempfile); \ } #define CLI_UNPRESULTS(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, (void)0, EXPR, GOOD, FREEME) @@ -4026,7 +4026,7 @@ int cli_scanpe(cli_ctx *ctx) cli_dbgmsg("***** Scanning decompressed file *****\n"); SHA_OFF; - if ((ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL)) == CL_VIRUS) { + if ((ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE)) == CL_VIRUS) { close(ndesc); SHA_RESET; CLI_TMPUNLK(); diff --git a/libclamav/png.c b/libclamav/png.c index ac7c5d47ea..ad5ae8de68 100644 --- a/libclamav/png.c +++ b/libclamav/png.c @@ -302,7 +302,8 @@ cl_error_t cli_parsepng(cli_ctx *ctx) /* Check if there's an overlay, and scan it if one exists. */ if (map->len > offset) { cli_dbgmsg("PNG: Found " STDu64 " additional data after end of PNG! Scanning as a nested file.\n", map->len - offset); - status = cli_magic_scan_nested_fmap_type(map, (size_t)offset, map->len - offset, ctx, CL_TYPE_ANY, NULL); + status = cli_magic_scan_nested_fmap_type(map, (size_t)offset, map->len - offset, ctx, + CL_TYPE_ANY, NULL, LAYER_ATTRIBUTES_NONE); goto done; } diff --git a/libclamav/rtf.c b/libclamav/rtf.c index 0c74b5439d..682835a2f5 100644 --- a/libclamav/rtf.c +++ b/libclamav/rtf.c @@ -246,7 +246,7 @@ static int decode_and_scan(struct rtf_object_data* data, cli_ctx* ctx) cli_dbgmsg("Decoding ole object\n"); ret = cli_scan_ole10(data->fd, ctx); } else if (data->fd > 0) - ret = cli_magic_scan_desc(data->fd, data->name, ctx, NULL); + ret = cli_magic_scan_desc(data->fd, data->name, ctx, NULL, LAYER_ATTRIBUTES_NONE); if (data->fd > 0) close(data->fd); data->fd = -1; diff --git a/libclamav/scanners.c b/libclamav/scanners.c index 3e51eadcf7..6666c63571 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -128,15 +128,14 @@ #include #include -cl_error_t cli_magic_scan_dir(const char *dir, cli_ctx *ctx) +cl_error_t cli_magic_scan_dir(const char *dir, cli_ctx *ctx, uint32_t attributes) { cl_error_t status = CL_CLEAN; DIR *dd = NULL; struct dirent *dent; STATBUF statbuf; - char *fname = NULL; - unsigned int viruses_found = 0; - bool processing_normalized_files = ctx->next_layer_is_normalized; + char *fname = NULL; + unsigned int viruses_found = 0; if ((dd = opendir(dir)) != NULL) { while ((dent = readdir(dd))) { @@ -155,7 +154,7 @@ cl_error_t cli_magic_scan_dir(const char *dir, cli_ctx *ctx) /* stat the file */ if (LSTAT(fname, &statbuf) != -1) { if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) { - if (cli_magic_scan_dir(fname, ctx) == CL_VIRUS) { + if (cli_magic_scan_dir(fname, ctx, attributes) == CL_VIRUS) { if (SCAN_ALLMATCHES) { viruses_found++; continue; @@ -166,8 +165,7 @@ cl_error_t cli_magic_scan_dir(const char *dir, cli_ctx *ctx) } } else { if (S_ISREG(statbuf.st_mode)) { - ctx->next_layer_is_normalized = processing_normalized_files; // This flag ingested by cli_recursion_stack_push(). - if (cli_magic_scan_file(fname, ctx, dent->d_name) == CL_VIRUS) { + if (CL_VIRUS == cli_magic_scan_file(fname, ctx, dent->d_name, attributes)) { if (SCAN_ALLMATCHES) { viruses_found++; continue; @@ -191,7 +189,6 @@ cl_error_t cli_magic_scan_dir(const char *dir, cli_ctx *ctx) } done: - ctx->next_layer_is_normalized = false; if (NULL != dd) { closedir(dd); } @@ -309,7 +306,7 @@ static cl_error_t cli_scanrar_file(const char *filepath, int desc, cli_ctx *ctx) } /* Scan the comment */ - status = cli_magic_scan_buff(comment, comment_size, ctx, NULL); + status = cli_magic_scan_buff(comment, comment_size, ctx, NULL, LAYER_ATTRIBUTES_NONE); if ((status == CL_VIRUS) && SCAN_ALLMATCHES) { status = CL_CLEAN; @@ -465,7 +462,7 @@ static cl_error_t cli_scanrar_file(const char *filepath, int desc, cli_ctx *ctx) * ... scan the extracted file. */ cli_dbgmsg("RAR: Extraction complete. Scanning now...\n"); - status = cli_magic_scan_file(extract_fullpath, ctx, filename_base); + status = cli_magic_scan_file(extract_fullpath, ctx, filename_base, LAYER_ATTRIBUTES_NONE); if (status == CL_EOPEN) { cli_dbgmsg("RAR: File not found, Extraction failed!\n"); status = CL_CLEAN; @@ -755,7 +752,7 @@ static cl_error_t cli_scanegg(cli_ctx *ctx) /* * Scan the comment. */ - status = cli_magic_scan_buff(comments[i], strlen(comments[i]), ctx, NULL); + status = cli_magic_scan_buff(comments[i], strlen(comments[i]), ctx, NULL, LAYER_ATTRIBUTES_NONE); if ((status == CL_VIRUS) && SCAN_ALLMATCHES) { status = CL_CLEAN; @@ -925,7 +922,7 @@ static cl_error_t cli_scanegg(cli_ctx *ctx) * Scan the extracted file... */ cli_dbgmsg("EGG: Extraction complete. Scanning now...\n"); - status = cli_magic_scan_buff(extract_buffer, extract_buffer_len, ctx, filename_base); + status = cli_magic_scan_buff(extract_buffer, extract_buffer_len, ctx, filename_base, LAYER_ATTRIBUTES_NONE); if (status == CL_VIRUS) { cli_dbgmsg("EGG: infected with %s\n", cli_get_last_virus(ctx)); status = CL_VIRUS; @@ -1091,7 +1088,7 @@ static cl_error_t cli_scanarj(cli_ctx *ctx) if (lseek(metadata.ofd, 0, SEEK_SET) == -1) { cli_dbgmsg("ARJ: call to lseek() failed\n"); } - status = cli_magic_scan_desc(metadata.ofd, NULL, ctx, metadata.filename); + status = cli_magic_scan_desc(metadata.ofd, NULL, ctx, metadata.filename, LAYER_ATTRIBUTES_NONE); close(metadata.ofd); if (status == CL_VIRUS) { cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx)); @@ -1178,7 +1175,7 @@ static cl_error_t cli_scangzip_with_zib_from_the_80s(cli_ctx *ctx, unsigned char gzclose(gz); - if ((ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL)) == CL_VIRUS) { + if (CL_VIRUS == (ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx)); close(fd); if (!ctx->engine->keeptmp) { @@ -1280,7 +1277,7 @@ static cl_error_t cli_scangzip(cli_ctx *ctx) inflateEnd(&z); - if ((ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL)) == CL_VIRUS) { + if (CL_VIRUS == (ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx)); close(fd); if (!ctx->engine->keeptmp) { @@ -1386,7 +1383,7 @@ static cl_error_t cli_scanbzip(cli_ctx *ctx) BZ2_bzDecompressEnd(&strm); - if ((ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL)) == CL_VIRUS) { + if (CL_VIRUS == (ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx)); close(fd); if (!ctx->engine->keeptmp) { @@ -1495,7 +1492,7 @@ static cl_error_t cli_scanxz(cli_ctx *ctx) } while (XZ_STREAM_END != rc); /* scan decompressed file */ - if ((ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL)) == CL_VIRUS) { + if (CL_VIRUS == (ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { cli_dbgmsg("cli_scanxz: Infected with %s\n", cli_get_last_virus(ctx)); } @@ -1535,7 +1532,7 @@ static cl_error_t cli_scanszdd(cli_ctx *ctx) } cli_dbgmsg("MSEXPAND: Decompressed into %s\n", tmpname); - ret = cli_magic_scan_desc(ofd, tmpname, ctx, NULL); + ret = cli_magic_scan_desc(ofd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); close(ofd); if (!ctx->engine->keeptmp) if (cli_unlink(tmpname)) @@ -1587,9 +1584,7 @@ static cl_error_t vba_scandata(const unsigned char *data, size_t len, cli_ctx *c goto done; } - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push(). - - ret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_MSOLE2, true); /* Perform exp_eval with child fmap */ + ret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_MSOLE2, true, LAYER_ATTRIBUTES_NONE); /* Perform exp_eval with child fmap */ if (CL_SUCCESS != ret) { cli_dbgmsg("Failed to scan fmap.\n"); goto done; @@ -1752,7 +1747,7 @@ static cl_error_t cli_ole2_tempdir_scan_vba_new(const char *dir, cli_ctx *ctx, s goto done; } - ret = cli_scan_desc(tempfd, ctx, CL_TYPE_SCRIPT, 0, NULL, AC_SCAN_VIR, NULL, NULL); + ret = cli_scan_desc(tempfd, ctx, CL_TYPE_SCRIPT, 0, NULL, AC_SCAN_VIR, NULL, NULL, LAYER_ATTRIBUTES_NONE); close(tempfd); tempfd = -1; @@ -2004,7 +1999,7 @@ static cl_error_t cli_ole2_tempdir_scan_vba(const char *dir, cli_ctx *ctx, struc continue; } if ((fullname = cli_ppt_vba_read(fd, ctx))) { - ret = cli_magic_scan_dir(fullname, ctx); + ret = cli_magic_scan_dir(fullname, ctx, LAYER_ATTRIBUTES_NONE); if (!ctx->engine->keeptmp) cli_rmdirs(fullname); @@ -2171,9 +2166,11 @@ static cl_error_t cli_scanhtml(cli_ctx *ctx) snprintf(fullname, 1024, "%s" PATHSEP "nocomment.html", tempname); fd = open(fullname, O_RDONLY | O_BINARY); if (fd >= 0) { - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push(). - if ((ret = cli_scan_desc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL, NULL)) == CL_VIRUS) + if (CL_VIRUS == (ret = cli_scan_desc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED))) { viruses_found++; + } + close(fd); } @@ -2188,9 +2185,11 @@ static cl_error_t cli_scanhtml(cli_ctx *ctx) snprintf(fullname, 1024, "%s" PATHSEP "notags.html", tempname); fd = open(fullname, O_RDONLY | O_BINARY); if (fd >= 0) { - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push(). - if ((ret = cli_scan_desc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL, NULL)) == CL_VIRUS) + if (CL_VIRUS == (ret = cli_scan_desc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED))) { viruses_found++; + } + close(fd); } } @@ -2200,22 +2199,24 @@ static cl_error_t cli_scanhtml(cli_ctx *ctx) snprintf(fullname, 1024, "%s" PATHSEP "javascript", tempname); fd = open(fullname, O_RDONLY | O_BINARY); if (fd >= 0) { - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push(). - if ((ret = cli_scan_desc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL, NULL)) == CL_VIRUS) + if (CL_VIRUS == (ret = cli_scan_desc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED))) { viruses_found++; + } + if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) { - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push(). - if ((ret = cli_scan_desc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL, NULL)) == CL_VIRUS) + if (CL_VIRUS == (ret = cli_scan_desc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED))) { viruses_found++; + } } close(fd); } } if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) { - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push() or cleared when cli_magic_scan_dir() is done. snprintf(fullname, 1024, "%s" PATHSEP "rfc2397", tempname); - ret = cli_magic_scan_dir(fullname, ctx); + ret = cli_magic_scan_dir(fullname, ctx, LAYER_ATTRIBUTES_NORMALIZED); if (CL_EOPEN == ret) { /* If the directory doesn't exist, that's fine */ ret = CL_CLEAN; @@ -2330,9 +2331,8 @@ static cl_error_t cli_scanscript(cli_ctx *ctx) goto done; } - ctx->next_layer_is_normalized = true; // This flag ingested by cli_recursion_stack_push(). - - ret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_TEXT_ASCII, true); /* Perform cli_scan_fmap with child fmap */ + /* Perform cli_scan_fmap with child fmap */ + ret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_TEXT_ASCII, true, LAYER_ATTRIBUTES_NORMALIZED); if (CL_SUCCESS != ret) { cli_dbgmsg("Failed to scan fmap.\n"); goto done; @@ -2487,9 +2487,8 @@ static cl_error_t cli_scanhtml_utf16(cli_ctx *ctx) goto done; } - ctx->next_layer_is_normalized = true; // s/normalized/transcoded, practically the same thing. - - status = cli_recursion_stack_push(ctx, new_map, CL_TYPE_HTML, true); /* Perform exp_eval with child fmap */ + /* Perform exp_eval with child fmap */ + status = cli_recursion_stack_push(ctx, new_map, CL_TYPE_HTML, true, LAYER_ATTRIBUTES_NORMALIZED); if (CL_SUCCESS != status) { cli_dbgmsg("Failed to scan fmap.\n"); goto done; @@ -2617,7 +2616,7 @@ static cl_error_t cli_ole2_scan_tempdir( } if (has_xlm || has_vba) { - status = cli_magic_scan_dir(dir, ctx); + status = cli_magic_scan_dir(dir, ctx, LAYER_ATTRIBUTES_NONE); if (CL_VIRUS == status) { viruses_found++; if (!SCAN_ALLMATCHES) { @@ -2818,7 +2817,7 @@ static cl_error_t cli_scanscrenc(cli_ctx *ctx) } if (html_screnc_decode(ctx->fmap, tempname)) - ret = cli_magic_scan_dir(tempname, ctx); + ret = cli_magic_scan_dir(tempname, ctx, LAYER_ATTRIBUTES_NONE); if (!ctx->engine->keeptmp) cli_rmdirs(tempname); @@ -2883,7 +2882,7 @@ static cl_error_t cli_scancryptff(cli_ctx *ctx) cli_dbgmsg("CryptFF: Scanning decrypted data\n"); - if ((ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL)) == CL_VIRUS) + if (CL_VIRUS == (ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE))) cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus(ctx)); close(ndesc); @@ -2937,7 +2936,7 @@ static cl_error_t cli_scantnef(cli_ctx *ctx) ret = cli_tnef(dir, ctx); if (ret == CL_CLEAN) - ret = cli_magic_scan_dir(dir, ctx); + ret = cli_magic_scan_dir(dir, ctx, LAYER_ATTRIBUTES_NONE); if (!ctx->engine->keeptmp) cli_rmdirs(dir); @@ -2963,7 +2962,7 @@ static cl_error_t cli_scanuuencoded(cli_ctx *ctx) ret = cli_uuencode(dir, ctx->fmap); if (ret == CL_CLEAN) - ret = cli_magic_scan_dir(dir, ctx); + ret = cli_magic_scan_dir(dir, ctx, LAYER_ATTRIBUTES_NONE); if (!ctx->engine->keeptmp) cli_rmdirs(dir); @@ -3004,7 +3003,7 @@ static cl_error_t cli_scanmail(cli_ctx *ctx) } } - ret = cli_magic_scan_dir(dir, ctx); + ret = cli_magic_scan_dir(dir, ctx, LAYER_ATTRIBUTES_NONE); if (!ctx->engine->keeptmp) cli_rmdirs(dir); @@ -3164,7 +3163,7 @@ static cl_error_t cli_scanembpe(cli_ctx *ctx, off_t offset) corrupted_input = ctx->corrupted_input; ctx->corrupted_input = 1; - ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL); + ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); ctx->corrupted_input = corrupted_input; if (ret == CL_VIRUS) { cli_dbgmsg("cli_scanembpe: Infected with %s\n", cli_get_last_virus(ctx)); @@ -3631,7 +3630,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_RAR, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_RAR, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3654,7 +3654,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_EGG, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_EGG, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3677,7 +3678,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_ZIP, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_ZIP, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3700,7 +3702,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_MSCAB, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_MSCAB, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3723,7 +3726,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_ARJ, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_ARJ, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3746,7 +3750,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_7Z, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_7Z, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3769,7 +3774,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_NULSFT, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_NULSFT, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3792,7 +3798,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_AUTOIT, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_AUTOIT, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3815,7 +3822,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_ISHIELD_MSI, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_ISHIELD_MSI, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3838,7 +3846,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_PDF, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_PDF, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -3866,7 +3875,8 @@ static cl_error_t scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_fi break; } - nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_MSEXE, false); /* Perform scan with child fmap */ + /* Perform scan with child fmap */ + nret = cli_recursion_stack_push(ctx, new_map, CL_TYPE_MSEXE, false, LAYER_ATTRIBUTES_NONE); if (CL_SUCCESS != nret) { ret = nret; cli_dbgmsg("scanraw: Failed to add map to recursion stack to scan embedded file.\n"); @@ -4033,24 +4043,108 @@ void emax_reached(cli_ctx *ctx) #define LINESTR2(x) LINESTR(x) #define __AT__ " at line " LINESTR2(__LINE__) +/** + * @brief Provide the following to the calling application for each embedded file: + * - name of parent file + * - size of parent file + * - name of current file + * - size of current file + * - pointer to the current file data + * + * @param cb + * @param ctx + * @param filetype + * @param old_hook_lsig_matches + * @param parent_property + * @param run_cleanup + * @return cl_error_t + */ +static cl_error_t dispatch_file_inspection_callback(clcb_file_inspection cb, cli_ctx *ctx, const char *filetype) +{ + cl_error_t status = CL_CLEAN; + + int fd = -1; + size_t fmap_index = ctx->recursion_level; /* index of current file */ + + cl_fmap_t *fmap = NULL; + const char *file_name = NULL; + size_t file_size = 0; + const char *file_buffer = NULL; + const char **ancestors = NULL; + + size_t parent_file_size = 0; + + if (NULL == cb) { + // Callback is not set. + goto done; + } + + fmap = ctx->recursion_stack[fmap_index].fmap; + fd = fmap_fd(fmap); + + CLI_CALLOC(ancestors, ctx->recursion_level + 1, sizeof(char *), status = CL_EMEM); + + file_name = fmap->name; + file_buffer = fmap_need_off_once_len(fmap, 0, fmap->len, &file_size); + + while (fmap_index > 0) { + cl_fmap_t *previous_fmap; + + fmap_index -= 1; + previous_fmap = ctx->recursion_stack[fmap_index].fmap; + + if (ctx->recursion_level > 0 && (fmap_index == ctx->recursion_level - 1)) { + parent_file_size = previous_fmap->len; + } + + ancestors[fmap_index] = previous_fmap->name; + } + + perf_start(ctx, PERFT_INSPECT); + status = cb(fd, filetype, ancestors, parent_file_size, file_name, file_size, file_buffer, + ctx->recursion_level, ctx->recursion_stack[ctx->recursion_level].attributes, ctx->cb_ctx); + perf_stop(ctx, PERFT_INSPECT); + + switch (status) { + case CL_BREAK: + cli_dbgmsg("dispatch_file_inspection_callback: scan cancelled by callback\n"); + status = CL_BREAK; + break; + case CL_VIRUS: + cli_dbgmsg("dispatch_file_inspection_callback: file blocked by callback\n"); + cli_append_virus(ctx, "Detected.By.Callback.Inspection"); + status = CL_VIRUS; + break; + case CL_CLEAN: + break; + default: + status = CL_CLEAN; + cli_warnmsg("dispatch_file_inspection_callback: ignoring bad return code from callback\n"); + } + +done: + + FREE(ancestors); + return status; +} + static cl_error_t dispatch_prescan_callback(clcb_pre_scan cb, cli_ctx *ctx, const char *filetype) { cl_error_t status = CL_CLEAN; if (cb) { perf_start(ctx, PERFT_PRECB); - status = cb(fmap_fd(ctx->fmap), filetype, ctx->cb_ctx); + perf_stop(ctx, PERFT_PRECB); + switch (status) { case CL_BREAK: cli_dbgmsg("dispatch_prescan_callback: file allowed by callback\n"); - perf_stop(ctx, PERFT_PRECB); status = CL_BREAK; break; case CL_VIRUS: cli_dbgmsg("dispatch_prescan_callback: file blocked by callback\n"); cli_append_virus(ctx, "Detected.By.Callback"); - perf_stop(ctx, PERFT_PRECB); status = CL_VIRUS; break; case CL_CLEAN: @@ -4059,8 +4153,6 @@ static cl_error_t dispatch_prescan_callback(clcb_pre_scan cb, cli_ctx *ctx, cons status = CL_CLEAN; cli_warnmsg("dispatch_prescan_callback: ignoring bad return code from callback\n"); } - - perf_stop(ctx, PERFT_PRECB); } return status; @@ -4321,6 +4413,16 @@ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type) } hashed_size = ctx->fmap->len; + ret = dispatch_file_inspection_callback(ctx->engine->cb_file_inspection, ctx, filetype); + if (CL_CLEAN != ret) { + if (ret == CL_VIRUS) { + ret = cli_check_fp(ctx, NULL); + } else { + ret = CL_CLEAN; + } + goto done; + } + /* * Check if we've already scanned this file before. */ @@ -5019,7 +5121,8 @@ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type) return ret; } -cl_error_t cli_magic_scan_desc_type(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type, const char *name) +cl_error_t cli_magic_scan_desc_type(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type, + const char *name, uint32_t attributes) { STATBUF sb; cl_error_t status = CL_CLEAN; @@ -5064,7 +5167,7 @@ cl_error_t cli_magic_scan_desc_type(int desc, const char *filepath, cli_ctx *ctx goto done; } - status = cli_recursion_stack_push(ctx, new_map, type, true); /* Perform scan with child fmap */ + status = cli_recursion_stack_push(ctx, new_map, type, true, attributes); /* Perform scan with child fmap */ if (CL_SUCCESS != status) { cli_dbgmsg("Failed to scan fmap.\n"); goto done; @@ -5084,9 +5187,9 @@ cl_error_t cli_magic_scan_desc_type(int desc, const char *filepath, cli_ctx *ctx return status; } -cl_error_t cli_magic_scan_desc(int desc, const char *filepath, cli_ctx *ctx, const char *name) +cl_error_t cli_magic_scan_desc(int desc, const char *filepath, cli_ctx *ctx, const char *name, uint32_t attributes) { - return cli_magic_scan_desc_type(desc, filepath, ctx, CL_TYPE_ANY, name); + return cli_magic_scan_desc_type(desc, filepath, ctx, CL_TYPE_ANY, name, attributes); } cl_error_t cl_scandesc(int desc, const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *scanoptions) @@ -5107,7 +5210,8 @@ cl_error_t cl_scandesc(int desc, const char *filename, const char **virname, uns * @param name (optional) Original name of the file (to set fmap name metadata) * @return int CL_SUCCESS, or an error code. */ -static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name) +static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, + cli_file_t type, const char *name, uint32_t attributes) { cl_error_t status = CL_CLEAN; fmap_t *new_map = NULL; @@ -5140,7 +5244,7 @@ static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, siz goto done; } - status = cli_recursion_stack_push(ctx, new_map, type, false); /* Perform scan with child fmap */ + status = cli_recursion_stack_push(ctx, new_map, type, false, attributes); /* Perform scan with child fmap */ if (CL_SUCCESS != status) { cli_dbgmsg("magic_scan_nested_fmap_type: Failed to add map to recursion stack for magic scan.\n"); goto done; @@ -5159,7 +5263,8 @@ static cl_error_t magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, siz } /* For map scans that may be forced to disk */ -cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name) +cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, + cli_file_t type, const char *name, uint32_t attributes) { cl_error_t ret = CL_CLEAN; @@ -5217,7 +5322,7 @@ cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t } /* scan the temp file */ - ret = cli_magic_scan_desc_type(fd, tempfile, ctx, type, name); + ret = cli_magic_scan_desc_type(fd, tempfile, ctx, type, name, attributes); /* remove the temp file, if needed */ if (fd >= 0) { @@ -5236,12 +5341,12 @@ cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t * * Just use nested map by scanning given fmap at offset + length. */ - ret = magic_scan_nested_fmap_type(map, offset, length, ctx, type, name); + ret = magic_scan_nested_fmap_type(map, offset, length, ctx, type, name, attributes); } return ret; } -cl_error_t cli_magic_scan_buff(const void *buffer, size_t length, cli_ctx *ctx, const char *name) +cl_error_t cli_magic_scan_buff(const void *buffer, size_t length, cli_ctx *ctx, const char *name, uint32_t attributes) { cl_error_t ret; fmap_t *map = NULL; @@ -5251,7 +5356,7 @@ cl_error_t cli_magic_scan_buff(const void *buffer, size_t length, cli_ctx *ctx, return CL_EMAP; } - ret = cli_magic_scan_nested_fmap_type(map, 0, length, ctx, CL_TYPE_ANY, name); + ret = cli_magic_scan_nested_fmap_type(map, 0, length, ctx, CL_TYPE_ANY, name, attributes); funmap(map); @@ -5473,7 +5578,7 @@ static cl_error_t scan_common(cl_fmap_t *map, const char *filepath, const char * )) { cli_dbgmsg("scan_common: running deprecated preclass bytecodes for target type 13\n"); ctx.options->general &= ~CL_SCAN_GENERAL_COLLECT_METADATA; - status = cli_magic_scan_buff(jstring, strlen(jstring), &ctx, NULL); + status = cli_magic_scan_buff(jstring, strlen(jstring), &ctx, NULL, LAYER_ATTRIBUTES_NONE); } } @@ -5617,6 +5722,11 @@ cl_error_t cl_scanmap_callback(cl_fmap_t *map, const char *filename, const char return CL_CLEAN; } + if (NULL != filename && map->name == NULL) { + // Use the provided name for the fmap name if one wasn't already set. + cli_basename(filename, strlen(filename), &map->name); + } + return scan_common(map, filename, virname, scanned, engine, scanoptions, context); } @@ -5642,7 +5752,7 @@ cl_error_t cli_found_possibly_unwanted(cli_ctx *ctx) return CL_CLEAN; } -cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, const char *original_name) +cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, const char *original_name, uint32_t attributes) { int fd = -1; cl_error_t ret = CL_EOPEN; @@ -5653,12 +5763,13 @@ cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, const char *o goto done; } - ret = cli_magic_scan_desc(fd, filename, ctx, original_name); + ret = cli_magic_scan_desc(fd, filename, ctx, original_name, attributes); done: if (fd >= 0) { close(fd); } + return ret; } diff --git a/libclamav/scanners.h b/libclamav/scanners.h index ba869cff54..b5887b91cf 100644 --- a/libclamav/scanners.h +++ b/libclamav/scanners.h @@ -31,34 +31,38 @@ * * This API allows you to specify the file type in advance if you know it. * - * @param desc File descriptor - * @param filepath (optional) Full file path. - * @param ctx Scanning context structure. - * @param type CL_TYPE of data to be scanned. - * @param name (optional) Original name of the file (to set fmap name metadata) + * @param desc File descriptor + * @param filepath (optional) Full file path. + * @param ctx Scanning context structure. + * @param type CL_TYPE of data to be scanned. + * @param name (optional) Original name of the file (to set fmap name metadata) + * @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc) * @return cl_error_t */ -cl_error_t cli_magic_scan_desc_type(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type, const char *name); +cl_error_t cli_magic_scan_desc_type(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type, + const char *name, uint32_t attributes); /** * @brief Scan a tempfile / sub-file of _any_ type, passing in the fd, filepath (if available), and the scanning context. * - * @param desc File descriptor - * @param filepath (optional) Full file path. - * @param ctx Scanning context structure. - * @param name (optional) Original name of the file (to set fmap name metadata) - * @return int CL_SUCCESS, or an error code. + * @param desc File descriptor + * @param filepath (optional) Full file path. + * @param ctx Scanning context structure. + * @param name (optional) Original name of the file (to set fmap name metadata) + * @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc) + * @return int CL_SUCCESS, or an error code. */ -cl_error_t cli_magic_scan_desc(int desc, const char *filepath, cli_ctx *ctx, const char *name); +cl_error_t cli_magic_scan_desc(int desc, const char *filepath, cli_ctx *ctx, + const char *name, uint32_t attributes); /** * @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. + * @param ctx Scanning context structure. + * @param type CL_TYPE of data to be scanned. + * @return int CL_SUCCESS, or an error code. */ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type); @@ -71,28 +75,32 @@ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type); * or if force-to-disk IS enabled, it will write the file to a temp file and then * will scan with cli_magic_scan_desc_type(). * - * @param map File map. - * @param offset Offset into file map. - * @param length Length from offset. - * @param ctx Scanning context structure. - * @param type CL_TYPE of data to be scanned. - * @param name (optional) Original name of the file (to set fmap name metadata) - * @return int CL_SUCCESS, or an error code. + * @param map File map. + * @param offset Offset into file map. + * @param length Length from offset. + * @param ctx Scanning context structure. + * @param type CL_TYPE of data to be scanned. + * @param name (optional) Original name of the file (to set fmap name metadata) + * @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc) + * @return int CL_SUCCESS, or an error code. */ -cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, cli_file_t type, const char *name); +cl_error_t cli_magic_scan_nested_fmap_type(cl_fmap_t *map, size_t offset, size_t length, cli_ctx *ctx, + cli_file_t type, const char *name, uint32_t attributes); /** * @brief Convenience wrapper for cli_magic_scan_nested_fmap_type(). * * Creates an fmap and calls cli_magic_scan_nested_fmap_type() for you, with type CL_TYPE_ANY. * - * @param buffer Pointer to the buffer to be scanned. - * @param length Size in bytes of the buffer being scanned. - * @param ctx Scanning context structure. - * @param name (optional) Original name of the file (to set fmap name metadata) - * @return int CL_SUCCESS, or an error code. + * @param buffer Pointer to the buffer to be scanned. + * @param length Size in bytes of the buffer being scanned. + * @param ctx Scanning context structure. + * @param name (optional) Original name of the file (to set fmap name metadata) + * @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc) + * @return int CL_SUCCESS, or an error code. */ -cl_error_t cli_magic_scan_buff(const void *buffer, size_t length, cli_ctx *ctx, const char *name); +cl_error_t cli_magic_scan_buff(const void *buffer, size_t length, cli_ctx *ctx, + const char *name, uint32_t attributes); cl_error_t cli_found_possibly_unwanted(cli_ctx *ctx); @@ -104,9 +112,11 @@ cl_error_t cli_found_possibly_unwanted(cli_ctx *ctx); * @param filename Filepath of the file to be scanned. * @param ctx Scanning context structure. * @param original_name (optional) Original name of the file (to set fmap name metadata) + * @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc) * @return cl_error_t */ -cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, const char *original_name); +cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, + const char *original_name, uint32_t attributes); /** * @brief Internal function to recursively scan a directory. @@ -115,9 +125,10 @@ cl_error_t cli_magic_scan_file(const char *filename, cli_ctx *ctx, const char *o * * @param dirname Filepath of the directory to be scanned. * @param ctx Scanning context structure. + * @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc) * @return cl_error_t */ -cl_error_t cli_magic_scan_dir(const char *dirname, cli_ctx *ctx); +cl_error_t cli_magic_scan_dir(const char *dirname, cli_ctx *ctx, uint32_t attributes); /** * @brief Mark all scan recursion fmap layers as non-cacheable. diff --git a/libclamav/sis.c b/libclamav/sis.c index 28e89cdd1a..11a9c46b09 100644 --- a/libclamav/sis.c +++ b/libclamav/sis.c @@ -517,7 +517,7 @@ static cl_error_t real_scansis(cli_ctx *ctx, const char *tmpd) FREE(decomp); - if (cli_magic_scan_desc(fd, ofn, ctx, original_filepath) == CL_VIRUS) { + if (CL_VIRUS == cli_magic_scan_desc(fd, ofn, ctx, original_filepath, LAYER_ATTRIBUTES_NONE)) { status = CL_VIRUS; goto done; } @@ -840,7 +840,7 @@ static cl_error_t real_scansis9x(cli_ctx *ctx, const char *tmpd) break; } free(dst); - if (cli_magic_scan_desc(fd, tempf, ctx, NULL) == CL_VIRUS) { + if (cli_magic_scan_desc(fd, tempf, ctx, NULL, LAYER_ATTRIBUTES_NONE) == CL_VIRUS) { close(fd); return CL_VIRUS; } diff --git a/libclamav/swf.c b/libclamav/swf.c index 5f3966b8c4..404092cdaf 100644 --- a/libclamav/swf.c +++ b/libclamav/swf.c @@ -288,7 +288,7 @@ static cl_error_t scanzws(cli_ctx *ctx, struct swf_file_hdr *hdr) hdr->filesize, (long long unsigned)outsize); } - ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL); + ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); close(fd); if (!(ctx->engine->keeptmp)) { @@ -424,7 +424,7 @@ static cl_error_t scancws(cli_ctx *ctx, struct swf_file_hdr *hdr) hdr->filesize, outsize); } - ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL); + ret = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); close(fd); if (!ctx->engine->keeptmp) { diff --git a/libclamav/untar.c b/libclamav/untar.c index acf735bed2..6306500c1d 100644 --- a/libclamav/untar.c +++ b/libclamav/untar.c @@ -173,7 +173,7 @@ cl_error_t cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx) if (fout >= 0) { lseek(fout, 0, SEEK_SET); - ret = cli_magic_scan_desc(fout, fullname, ctx, name); + ret = cli_magic_scan_desc(fout, fullname, ctx, name, LAYER_ATTRIBUTES_NONE); close(fout); if (!ctx->engine->keeptmp) if (cli_unlink(fullname)) return CL_EUNLINK; @@ -369,7 +369,7 @@ cl_error_t cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx) } if (fout >= 0) { lseek(fout, 0, SEEK_SET); - ret = cli_magic_scan_desc(fout, fullname, ctx, name); + ret = cli_magic_scan_desc(fout, fullname, ctx, name, LAYER_ATTRIBUTES_NONE); close(fout); if (!ctx->engine->keeptmp) if (cli_unlink(fullname)) return CL_EUNLINK; diff --git a/libclamav/unzip.c b/libclamav/unzip.c index 1845d15831..37bed2992e 100644 --- a/libclamav/unzip.c +++ b/libclamav/unzip.c @@ -115,7 +115,8 @@ static cl_error_t unz( cli_ctx *ctx, char *tmpd, zip_cb zcb, - const char *original_filename) + const char *original_filename, + bool decrypted) { char obuf[BUFSIZ] = {0}; char *tempfile = NULL; @@ -146,7 +147,8 @@ static cl_error_t unz( if (csize < usize) { unsigned int fake = *num_files_unzipped + 1; cli_dbgmsg("cli_unzip: attempting to inflate stored file with inconsistent size\n"); - if ((ret = unz(src, csize, usize, ALG_DEFLATE, 0, &fake, ctx, tmpd, zcb, original_filename)) == CL_CLEAN) { + if (CL_CLEAN == (ret = unz(src, csize, usize, ALG_DEFLATE, 0, &fake, ctx, + tmpd, zcb, original_filename, decrypted))) { (*num_files_unzipped)++; res = fake - (*num_files_unzipped); } else @@ -154,7 +156,8 @@ static cl_error_t unz( } if (res == 1) { if (ctx->engine->maxfilesize && csize > ctx->engine->maxfilesize) { - cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (long unsigned int)ctx->engine->maxfilesize); + cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", + (long unsigned int)ctx->engine->maxfilesize); csize = ctx->engine->maxfilesize; } if (cli_writen(out_file, src, csize) != csize) @@ -354,7 +357,7 @@ static cl_error_t unz( close(out_file); return CL_ESEEK; } - ret = zcb(out_file, tempfile, ctx, original_filename); + ret = zcb(out_file, tempfile, ctx, original_filename, decrypted); close(out_file); if (!ctx->engine->keeptmp) if (cli_unlink(tempfile)) ret = CL_EUNLINK; @@ -556,7 +559,8 @@ static inline cl_error_t zdecrypt( } /* call unz on decrypted output */ - ret = unz(dcypt_zip, csize - SIZEOF_ENCRYPTION_HEADER, usize, LOCAL_HEADER_method, LOCAL_HEADER_flags, num_files_unzipped, ctx, tmpd, zcb, original_filename); + ret = unz(dcypt_zip, csize - SIZEOF_ENCRYPTION_HEADER, usize, LOCAL_HEADER_method, LOCAL_HEADER_flags, + num_files_unzipped, ctx, tmpd, zcb, original_filename, true); /* clean-up and return */ funmap(dcypt_map); @@ -728,7 +732,8 @@ static unsigned int parse_local_file_header( *ret = zdecrypt(zip, csize, usize, local_header, num_files_unzipped, ctx, tmpd, zcb, original_filename); } else { if (fmap_need_ptr_once(map, zip, csize)) - *ret = unz(zip, csize, usize, LOCAL_HEADER_method, LOCAL_HEADER_flags, num_files_unzipped, ctx, tmpd, zcb, original_filename); + *ret = unz(zip, csize, usize, LOCAL_HEADER_method, LOCAL_HEADER_flags, num_files_unzipped, + ctx, tmpd, zcb, original_filename, false); } } else { if ((NULL == original_filename) || @@ -1284,7 +1289,8 @@ cl_error_t cli_unzip(cli_ctx *ctx) ctx, tmpd, zip_scan_cb, - zip_catalogue[i].original_filename); + zip_catalogue[i].original_filename, + false); } file_count++; diff --git a/libclamav/unzip.h b/libclamav/unzip.h index 2b67660aa8..744ddb603a 100644 --- a/libclamav/unzip.h +++ b/libclamav/unzip.h @@ -28,7 +28,8 @@ #include "others.h" -typedef cl_error_t (*zip_cb)(int fd, const char *filepath, cli_ctx *ctx, const char *name); +// Callback is the same as cli_magic_scan_desc +typedef cl_error_t (*zip_cb)(int fd, const char *filepath, cli_ctx *ctx, const char *name, uint32_t attributes); #define zip_scan_cb cli_magic_scan_desc #define MAX_ZIP_REQUESTS 10 diff --git a/libclamav/vba_extract.c b/libclamav/vba_extract.c index d8280c68b3..3e2bf67fcb 100644 --- a/libclamav/vba_extract.c +++ b/libclamav/vba_extract.c @@ -1723,7 +1723,7 @@ int cli_scan_ole10(int fd, cli_ctx *ctx) cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname); ole_copy_file_data(fd, ofd, object_size); lseek(ofd, 0, SEEK_SET); - ret = cli_magic_scan_desc(ofd, fullname, ctx, NULL); + ret = cli_magic_scan_desc(ofd, fullname, ctx, NULL, LAYER_ATTRIBUTES_NONE); close(ofd); if (ctx && !ctx->engine->keeptmp) if (cli_unlink(fullname)) diff --git a/libclamav/xar.c b/libclamav/xar.c index 45e3d83f30..a5de297370 100644 --- a/libclamav/xar.c +++ b/libclamav/xar.c @@ -308,7 +308,7 @@ static int xar_scan_subdocuments(xmlTextReaderPtr reader, cli_ctx *ctx) } subdoc_len = xmlStrlen(subdoc); cli_dbgmsg("cli_scanxar: in-memory scan of xml subdocument, len %i.\n", subdoc_len); - rc = cli_magic_scan_buff(subdoc, subdoc_len, ctx, NULL); + rc = cli_magic_scan_buff(subdoc, subdoc_len, ctx, NULL, LAYER_ATTRIBUTES_NONE); if (rc == CL_VIRUS && SCAN_ALLMATCHES) rc = CL_SUCCESS; @@ -517,7 +517,7 @@ int cli_scanxar(cli_ctx *ctx) /* scan the xml */ cli_dbgmsg("cli_scanxar: scanning xar TOC xml in memory.\n"); - rc = cli_magic_scan_buff(toc, hdr.toc_length_decompressed, ctx, NULL); + rc = cli_magic_scan_buff(toc, hdr.toc_length_decompressed, ctx, NULL, LAYER_ATTRIBUTES_NONE); if (rc != CL_SUCCESS) { if (rc != CL_VIRUS || !SCAN_ALLMATCHES) goto exit_toc; @@ -846,7 +846,7 @@ int cli_scanxar(cli_ctx *ctx) } } - rc = cli_magic_scan_desc(fd, tmpname, ctx, NULL); /// TODO: collect file names in xar_get_toc_data_values() + rc = cli_magic_scan_desc(fd, tmpname, ctx, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: collect file names in xar_get_toc_data_values() if (rc != CL_SUCCESS) { if (rc == CL_VIRUS) { cli_dbgmsg("cli_scanxar: Infected with %s\n", cli_get_last_virus(ctx)); diff --git a/libclamav/xdp.c b/libclamav/xdp.c index 8b829457a1..6536d9ce6b 100644 --- a/libclamav/xdp.c +++ b/libclamav/xdp.c @@ -159,7 +159,7 @@ cl_error_t cli_scanxdp(cli_ctx *ctx) break; } - rc = cli_magic_scan_buff(decoded, decodedlen, ctx, NULL); + rc = cli_magic_scan_buff(decoded, decodedlen, ctx, NULL, LAYER_ATTRIBUTES_NONE); free(decoded); if (rc != CL_SUCCESS || rc == CL_BREAK) { xmlFree((void *)value); diff --git a/libclamav/xlm_extract.c b/libclamav/xlm_extract.c index 02fa5a0874..e242ed894d 100644 --- a/libclamav/xlm_extract.c +++ b/libclamav/xlm_extract.c @@ -4350,10 +4350,11 @@ cl_error_t process_blip_record(struct OfficeArtRecordHeader_Unpacked *rh, const goto done; } - ret = cli_magic_scan_desc_type(extracted_image_tempfd, extracted_image_filepath, ctx, CL_TYPE_ANY, NULL); + ret = cli_magic_scan_desc_type(extracted_image_tempfd, extracted_image_filepath, ctx, CL_TYPE_ANY, + NULL, LAYER_ATTRIBUTES_NONE); } else { /* Scan the buffer */ - ret = cli_magic_scan_buff(start_of_image, size_of_image, ctx, NULL); + ret = cli_magic_scan_buff(start_of_image, size_of_image, ctx, NULL, LAYER_ATTRIBUTES_NONE); } if (ret == CL_VIRUS) { if (!SCAN_ALLMATCHES) { @@ -4976,7 +4977,8 @@ cl_error_t cli_extract_xlm_macros_and_images(const char *dir, cli_ctx *ctx, char goto done; } - if (cli_scan_desc(out_fd, ctx, CL_TYPE_SCRIPT, 0, NULL, AC_SCAN_VIR, NULL, NULL) == CL_VIRUS) { + if (CL_VIRUS == cli_scan_desc(out_fd, ctx, CL_TYPE_SCRIPT, 0, NULL, AC_SCAN_VIR, + NULL, NULL, LAYER_ATTRIBUTES_NONE)) { status = CL_VIRUS; goto done; } diff --git a/libclamav_rust/src/sys.rs b/libclamav_rust/src/sys.rs index 575e5dd801..a7f5fb8afe 100644 --- a/libclamav_rust/src/sys.rs +++ b/libclamav_rust/src/sys.rs @@ -114,6 +114,38 @@ pub type clcb_pre_cache = ::std::option::Option< >; #[doc = " @brief Pre-scan callback."] #[doc = ""] +#[doc = " Called for each NEW file (inner and outer)."] +#[doc = " Provides capability to record embedded file information during a scan."] +#[doc = ""] +#[doc = " @param fd Current file descriptor which is about to be scanned."] +#[doc = " @param type Current file type detected via magic - i.e. NOT on the fly - (e.g. \"CL_TYPE_MSEXE\")."] +#[doc = " @param ancestors An array of ancestors filenames of size `recursion_level`. filenames may be NULL."] +#[doc = " @param parent_file_size Parent file size."] +#[doc = " @param file_name Current file name, or NULL if the file does not have a name or ClamAV failed to record the name."] +#[doc = " @param file_size Current file size."] +#[doc = " @param file_buffer Current file buffer pointer."] +#[doc = " @param recursion_level Recursion level / depth of the current file."] +#[doc = " @param layer_attributes See LAYER_ATTRIBUTES_* flags."] +#[doc = " @param context Opaque application provided data."] +#[doc = " @return CL_CLEAN = File is scanned."] +#[doc = " @return CL_BREAK = Whitelisted by callback - file is skipped and marked as clean."] +#[doc = " @return CL_VIRUS = Blacklisted by callback - file is skipped and marked as infected."] +pub type clcb_file_inspection = ::std::option::Option< + unsafe extern "C" fn( + fd: ::std::os::raw::c_int, + type_: *const ::std::os::raw::c_char, + ancestors: *mut *const ::std::os::raw::c_char, + parent_file_size: size_t, + file_name: *const ::std::os::raw::c_char, + file_size: size_t, + file_buffer: *const ::std::os::raw::c_char, + recursion_level: u32, + layer_attributes: u32, + context: *mut ::std::os::raw::c_void, + ) -> cl_error_t, +>; +#[doc = " @brief Pre-scan callback."] +#[doc = ""] #[doc = " Called for each NEW file (inner and outer) before the scanning takes place. This is"] #[doc = " roughly the the same as clcb_before_cache, but it is affected by clean file caching."] #[doc = " This means that it won't be called if a clean cached file (inner or outer) is"] @@ -741,7 +773,7 @@ pub struct recursion_level_tag { pub fmap: *mut cl_fmap_t, pub recursion_level_buffer: u32, pub recursion_level_buffer_fmap: u32, - pub is_normalized_layer: bool, + pub attributes: u32, pub image_fuzzy_hash: image_fuzzy_hash_t, pub calculated_image_fuzzy_hash: bool, } @@ -769,7 +801,6 @@ pub struct cli_ctx_tag { pub recursion_stack_size: u32, pub recursion_level: u32, pub fmap: *mut fmap_t, - pub next_layer_is_normalized: bool, pub handlertype_hash: [::std::os::raw::c_uchar; 16usize], pub dconf: *mut cli_dconf, pub hook_lsig_matches: *mut bitset_t, @@ -875,6 +906,7 @@ pub struct cl_engine { pub num_total_signatures: size_t, pub mempool: *mut mpool_t, pub cmgr: crtmgr, + pub cb_file_inspection: clcb_file_inspection, pub cb_pre_cache: clcb_pre_cache, pub cb_pre_scan: clcb_pre_scan, pub cb_post_scan: clcb_post_scan, @@ -1286,6 +1318,9 @@ pub struct cli_matcher { pub bcomp_metatable: *mut *mut cli_bcomp_meta, pub fuzzy_hashmap: fuzzyhashmap_t, pub linked_bcs: u32, + pub trans_array: *mut *mut cli_ac_node, + pub trans_cnt: size_t, + pub trans_capacity: size_t, pub mempool: *mut mpool_t, } #[repr(C)]