/src/clamav/fuzz/clamav_scanfile_fuzzer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Fuzz target for cl_scanfile() |
3 | | * |
4 | | * Copyright (C) 2018-2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
5 | | * Authors: Micah Snyder, Alex Gaynor |
6 | | * |
7 | | * Redistribution and use in source and binary forms, with or without |
8 | | * modification, are permitted provided that the following conditions are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright notice, |
11 | | * this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
14 | | * this list of conditions and the following disclaimer in the documentation |
15 | | * and/or other materials provided with the distribution. |
16 | | * |
17 | | * 3. Neither the name of the copyright holder nor the names of its contributors |
18 | | * may be used to endorse or promote products derived from this software without |
19 | | * specific prior written permission. |
20 | | * |
21 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
22 | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
25 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | | * POSSIBILITY OF SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | #include <stdint.h> |
35 | | #include <stdlib.h> |
36 | | #include <unistd.h> |
37 | | #include <string.h> |
38 | | |
39 | | #include "clamav.h" |
40 | | |
41 | | void clamav_message_callback(enum cl_msg severity, const char* fullmsg, |
42 | | const char* msg, void* context) |
43 | 2.29M | { |
44 | 2.29M | } |
45 | | |
46 | | class ClamAVState |
47 | | { |
48 | | public: |
49 | | ClamAVState() |
50 | 156 | { |
51 | | // Silence all the log messages, none of them are meaningful. |
52 | 156 | cl_set_clcb_msg(clamav_message_callback); |
53 | | |
54 | 156 | cl_init(CL_INIT_DEFAULT); |
55 | 156 | engine = cl_engine_new(); |
56 | 156 | cl_engine_compile(engine); |
57 | | |
58 | 156 | memset(&scanopts, 0, sizeof(struct cl_scan_options)); |
59 | | |
60 | | #if defined(CLAMAV_FUZZ_ARCHIVE) |
61 | | scanopts.parse |= CL_SCAN_PARSE_ARCHIVE; |
62 | | #elif defined(CLAMAV_FUZZ_MAIL) |
63 | | scanopts.parse |= CL_SCAN_PARSE_MAIL; |
64 | | #elif defined(CLAMAV_FUZZ_OLE2) |
65 | | scanopts.parse |= CL_SCAN_PARSE_OLE2; |
66 | | #elif defined(CLAMAV_FUZZ_PDF) |
67 | | scanopts.parse |= CL_SCAN_PARSE_PDF; |
68 | | #elif defined(CLAMAV_FUZZ_HTML) |
69 | 78 | scanopts.parse |= CL_SCAN_PARSE_HTML; |
70 | | #elif defined(CLAMAV_FUZZ_PE) |
71 | | scanopts.parse |= CL_SCAN_PARSE_PE; |
72 | | #elif defined(CLAMAV_FUZZ_ELF) |
73 | | scanopts.parse |= CL_SCAN_PARSE_ELF; |
74 | | #elif defined(CLAMAV_FUZZ_SWF) |
75 | | scanopts.parse |= CL_SCAN_PARSE_SWF; |
76 | | #elif defined(CLAMAV_FUZZ_XMLDOCS) |
77 | | scanopts.parse |= CL_SCAN_PARSE_XMLDOCS; |
78 | | #elif defined(CLAMAV_FUZZ_HWP3) |
79 | | scanopts.parse |= CL_SCAN_PARSE_HWP3; |
80 | | #else |
81 | | scanopts.parse |= ~(0); |
82 | | #endif |
83 | 156 | scanopts.general |= CL_SCAN_GENERAL_HEURISTICS; |
84 | 156 | scanopts.general |= CL_SCAN_GENERAL_COLLECT_METADATA; /* Enable the gen-json feature */ |
85 | 156 | scanopts.heuristic |= ~(0); /* Enable all heuristic code */ |
86 | 156 | scanopts.general |= CL_SCAN_GENERAL_ALLMATCHES; /* Enable all-match, so heuristic alerts don't end the scan early */ |
87 | 156 | } ClamAVState::ClamAVState() Line | Count | Source | 50 | 78 | { | 51 | | // Silence all the log messages, none of them are meaningful. | 52 | 78 | cl_set_clcb_msg(clamav_message_callback); | 53 | | | 54 | 78 | cl_init(CL_INIT_DEFAULT); | 55 | 78 | engine = cl_engine_new(); | 56 | 78 | cl_engine_compile(engine); | 57 | | | 58 | 78 | memset(&scanopts, 0, sizeof(struct cl_scan_options)); | 59 | | | 60 | | #if defined(CLAMAV_FUZZ_ARCHIVE) | 61 | | scanopts.parse |= CL_SCAN_PARSE_ARCHIVE; | 62 | | #elif defined(CLAMAV_FUZZ_MAIL) | 63 | | scanopts.parse |= CL_SCAN_PARSE_MAIL; | 64 | | #elif defined(CLAMAV_FUZZ_OLE2) | 65 | | scanopts.parse |= CL_SCAN_PARSE_OLE2; | 66 | | #elif defined(CLAMAV_FUZZ_PDF) | 67 | | scanopts.parse |= CL_SCAN_PARSE_PDF; | 68 | | #elif defined(CLAMAV_FUZZ_HTML) | 69 | 78 | scanopts.parse |= CL_SCAN_PARSE_HTML; | 70 | | #elif defined(CLAMAV_FUZZ_PE) | 71 | | scanopts.parse |= CL_SCAN_PARSE_PE; | 72 | | #elif defined(CLAMAV_FUZZ_ELF) | 73 | | scanopts.parse |= CL_SCAN_PARSE_ELF; | 74 | | #elif defined(CLAMAV_FUZZ_SWF) | 75 | | scanopts.parse |= CL_SCAN_PARSE_SWF; | 76 | | #elif defined(CLAMAV_FUZZ_XMLDOCS) | 77 | | scanopts.parse |= CL_SCAN_PARSE_XMLDOCS; | 78 | | #elif defined(CLAMAV_FUZZ_HWP3) | 79 | | scanopts.parse |= CL_SCAN_PARSE_HWP3; | 80 | | #else | 81 | | scanopts.parse |= ~(0); | 82 | | #endif | 83 | 78 | scanopts.general |= CL_SCAN_GENERAL_HEURISTICS; | 84 | 78 | scanopts.general |= CL_SCAN_GENERAL_COLLECT_METADATA; /* Enable the gen-json feature */ | 85 | 78 | scanopts.heuristic |= ~(0); /* Enable all heuristic code */ | 86 | 78 | scanopts.general |= CL_SCAN_GENERAL_ALLMATCHES; /* Enable all-match, so heuristic alerts don't end the scan early */ | 87 | 78 | } |
ClamAVState::ClamAVState() Line | Count | Source | 50 | 78 | { | 51 | | // Silence all the log messages, none of them are meaningful. | 52 | 78 | cl_set_clcb_msg(clamav_message_callback); | 53 | | | 54 | 78 | cl_init(CL_INIT_DEFAULT); | 55 | 78 | engine = cl_engine_new(); | 56 | 78 | cl_engine_compile(engine); | 57 | | | 58 | 78 | memset(&scanopts, 0, sizeof(struct cl_scan_options)); | 59 | | | 60 | | #if defined(CLAMAV_FUZZ_ARCHIVE) | 61 | | scanopts.parse |= CL_SCAN_PARSE_ARCHIVE; | 62 | | #elif defined(CLAMAV_FUZZ_MAIL) | 63 | | scanopts.parse |= CL_SCAN_PARSE_MAIL; | 64 | | #elif defined(CLAMAV_FUZZ_OLE2) | 65 | | scanopts.parse |= CL_SCAN_PARSE_OLE2; | 66 | | #elif defined(CLAMAV_FUZZ_PDF) | 67 | | scanopts.parse |= CL_SCAN_PARSE_PDF; | 68 | | #elif defined(CLAMAV_FUZZ_HTML) | 69 | | scanopts.parse |= CL_SCAN_PARSE_HTML; | 70 | | #elif defined(CLAMAV_FUZZ_PE) | 71 | | scanopts.parse |= CL_SCAN_PARSE_PE; | 72 | | #elif defined(CLAMAV_FUZZ_ELF) | 73 | | scanopts.parse |= CL_SCAN_PARSE_ELF; | 74 | | #elif defined(CLAMAV_FUZZ_SWF) | 75 | | scanopts.parse |= CL_SCAN_PARSE_SWF; | 76 | | #elif defined(CLAMAV_FUZZ_XMLDOCS) | 77 | | scanopts.parse |= CL_SCAN_PARSE_XMLDOCS; | 78 | | #elif defined(CLAMAV_FUZZ_HWP3) | 79 | | scanopts.parse |= CL_SCAN_PARSE_HWP3; | 80 | | #else | 81 | 78 | scanopts.parse |= ~(0); | 82 | 78 | #endif | 83 | 78 | scanopts.general |= CL_SCAN_GENERAL_HEURISTICS; | 84 | 78 | scanopts.general |= CL_SCAN_GENERAL_COLLECT_METADATA; /* Enable the gen-json feature */ | 85 | 78 | scanopts.heuristic |= ~(0); /* Enable all heuristic code */ | 86 | 78 | scanopts.general |= CL_SCAN_GENERAL_ALLMATCHES; /* Enable all-match, so heuristic alerts don't end the scan early */ | 87 | 78 | } |
|
88 | | |
89 | | ~ClamAVState() |
90 | 0 | { |
91 | 0 | cl_engine_free(engine); |
92 | 0 | } |
93 | | |
94 | | struct cl_engine* engine; |
95 | | struct cl_scan_options scanopts; |
96 | | }; |
97 | | |
98 | | // Global with static initializer to setup an engine so we don't need to do |
99 | | // that on each execution. |
100 | | ClamAVState kClamAVState; |
101 | | |
102 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) |
103 | 133k | { |
104 | 133k | FILE* fuzzfile = NULL; |
105 | 133k | char tmp_file_name[200] = {0}; |
106 | | |
107 | 133k | __pid_t pid = getpid(); |
108 | | |
109 | 133k | snprintf(tmp_file_name, sizeof(tmp_file_name), "tmp.scanfile.%d", pid); |
110 | | |
111 | 133k | fuzzfile = fopen(tmp_file_name, "w"); |
112 | 133k | fwrite(data, size, 1, fuzzfile); |
113 | 133k | fclose(fuzzfile); |
114 | | |
115 | 133k | const char* virus_name = nullptr; |
116 | 133k | unsigned long scanned = 0; |
117 | | |
118 | 133k | cl_scanfile( |
119 | 133k | tmp_file_name, |
120 | 133k | &virus_name, |
121 | 133k | &scanned, |
122 | 133k | kClamAVState.engine, |
123 | 133k | &kClamAVState.scanopts); |
124 | | |
125 | 133k | unlink(tmp_file_name); |
126 | | |
127 | 133k | return 0; |
128 | 133k | } |