/src/ntopng/fuzz/fuzz_dissect_packet.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * (C) 2013-23 - ntop.org |
4 | | * |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software Foundation, |
18 | | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | | * |
20 | | */ |
21 | | |
22 | | #ifdef FUZZ_WITH_PROTOBUF |
23 | | #include <bits/types/struct_timeval.h> |
24 | | #include <src/libfuzzer/libfuzzer_macro.h> |
25 | | #include <sys/time.h> |
26 | | |
27 | | #include "proto/pcap.pb.h" |
28 | | #endif |
29 | | |
30 | | #include <unistd.h> |
31 | | |
32 | | #include "ntop_includes.h" |
33 | | |
34 | | #ifdef INCLUDE_ONEFILE |
35 | | #include "onefile.cpp" |
36 | | #endif |
37 | | |
38 | | AfterShutdownAction afterShutdownAction = after_shutdown_nop; |
39 | | NetworkInterface *iface; |
40 | | |
41 | | constexpr const char *PROG_NAME = "ntopng"; |
42 | | static ndpi_protocol ndpiUnknownProtocol; |
43 | | |
44 | | bool trace_new_delete = false; |
45 | | |
46 | 2 | static void cleanup() { |
47 | 2 | if (iface) delete iface; |
48 | 2 | if (ntop) delete ntop; |
49 | 2 | } |
50 | | |
51 | | /** |
52 | | * Set the CLI args for prefs. |
53 | | * |
54 | | * The function must be called like this: |
55 | | * setCLIArgs(Prefs *prefs, int params, const char * ...) |
56 | | */ |
57 | 2 | static void setCLIArgs(Prefs *prefs, int params...) { |
58 | 2 | if (params == 0) return; |
59 | | |
60 | 2 | va_list args; |
61 | 2 | va_start(args, params); |
62 | | |
63 | | // Get path of the binary itself. This is needed to get the absolute path of |
64 | | // the required directories |
65 | 2 | char exePath[MAX_PATH + 1]; |
66 | 2 | ssize_t pathLen = readlink("/proc/self/exe", exePath, MAX_PATH); |
67 | 2 | if (pathLen != -1) { |
68 | 2 | exePath[pathLen] = '\0'; |
69 | 2 | ssize_t len = pathLen; |
70 | 42 | while (len > 0 && exePath[len] != '/') len--; |
71 | 2 | if (len == 0) { |
72 | 0 | std::cerr << "Error while crafting the command line. Relative path " |
73 | 0 | "have been used." |
74 | 0 | << std::endl; |
75 | 0 | exit(1); |
76 | 0 | } |
77 | 2 | exePath[len] = '\0'; |
78 | 2 | pathLen = len; |
79 | 2 | } else { |
80 | 0 | std::cerr << "Error while crafting the command line. Failed to " |
81 | 0 | "retrieve the absolute path of the executable." |
82 | 0 | << std::endl; |
83 | 0 | exit(1); |
84 | 0 | } |
85 | | |
86 | | // Create the new argv |
87 | 2 | char *new_argv[params]; |
88 | 24 | for (int i = 0; i < params; ++i) { |
89 | 22 | const char *opt = va_arg(args, const char *); |
90 | | |
91 | 22 | if (!strstr(opt, "_PATH_")) { |
92 | 12 | new_argv[i] = strdup(opt); |
93 | 12 | } else { |
94 | | // size = pathLen + / + opt - _PATH_ + \0 |
95 | 10 | size_t size = pathLen + 1 + strlen(opt) - 6 + 1; |
96 | 10 | new_argv[i] = (char *)malloc(size); |
97 | 10 | int len = snprintf(new_argv[i], size, "%s/%s", exePath, opt + 6); |
98 | 10 | if (len <= 0) { |
99 | 0 | std::cerr << "Error while crafting the command line. Wrong " |
100 | 0 | "buffer size." |
101 | 0 | << std::endl; |
102 | 0 | exit(1); |
103 | 0 | } |
104 | 10 | } |
105 | 22 | } |
106 | | |
107 | 2 | prefs->loadFromCLI(params, new_argv); // = true; |
108 | | |
109 | | // Free arguments |
110 | 24 | for (int k = 0; k < params; ++k) free(new_argv[k]); |
111 | | |
112 | 2 | va_end(args); |
113 | 2 | } |
114 | | |
115 | 183k | const ndpi_protocol getConstNdpiUnknownProtocol() { |
116 | 183k | return((const ndpi_protocol)ndpiUnknownProtocol); |
117 | 183k | } |
118 | 2 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { |
119 | | // Final cleanup |
120 | 2 | atexit(cleanup); |
121 | | |
122 | 2 | Prefs *prefs = NULL; |
123 | | |
124 | 2 | if ((ntop = new (std::nothrow) Ntop(PROG_NAME)) == NULL) _exit(1); |
125 | 2 | if ((prefs = new (std::nothrow) Prefs(ntop)) == NULL) _exit(1); |
126 | | |
127 | 2 | ntop->getTrace()->set_trace_level(1); |
128 | 2 | memset((void*)&ndpiUnknownProtocol, 0, sizeof(ndpiUnknownProtocol)); |
129 | | |
130 | 2 | setCLIArgs(prefs, 11, PROG_NAME, "-1", "_PATH_docs", "-2", "_PATH_scripts", |
131 | 2 | "-3", "_PATH_scripts/callbacks", "-d", "_PATH_data-dir", "-t", |
132 | 2 | "_PATH_install"); |
133 | | |
134 | 2 | ntop->registerPrefs(prefs, false); |
135 | | |
136 | 2 | ntop->loadGeolocation(); |
137 | | |
138 | 2 | iface = new NetworkInterface("custom"); |
139 | 2 | iface->allocateStructures(); |
140 | | |
141 | 2 | return 0; |
142 | 2 | } |
143 | | |
144 | | #ifdef FUZZ_WITH_PROTOBUF |
145 | | |
146 | | template <class Proto> |
147 | | using PostProcessor = |
148 | | protobuf_mutator::libfuzzer::PostProcessorRegistration<Proto>; |
149 | | |
150 | | DEFINE_PROTO_FUZZER(const ntopng_fuzz::Pcap &message) { |
151 | | ntop->getTrace()->traceEvent(TRACE_INFO, "Starting"); |
152 | | |
153 | | for (const ntopng_fuzz::Record &packet : message.packets()) { |
154 | | char pcap_error_buffer[PCAP_ERRBUF_SIZE]; |
155 | | u_int16_t p; |
156 | | Host *srcHost = NULL, *dstHost = NULL; |
157 | | Flow *flow = NULL; |
158 | | |
159 | | const u_char *pkt = |
160 | | reinterpret_cast<const u_char *>(packet.data().data()); |
161 | | struct pcap_pkthdr *hdr = new pcap_pkthdr(); |
162 | | |
163 | | hdr->caplen = message.packets().size(); |
164 | | hdr->len = packet.header().len(); |
165 | | hdr->ts = {packet.header().timestamp(), |
166 | | packet.header().micronano_timestamp()}; |
167 | | |
168 | | // printf("caplen %d len %d ts %d sus %d\n", hdr->caplen, hdr->len, |
169 | | // hdr->ts.tv_sec, hdr->ts.tv_usec); |
170 | | |
171 | | iface->dissectPacket(UNKNOWN_PKT_IFACE_IDX, |
172 | | DUMMY_BRIDGE_INTERFACE_ID, true, DLT_NULL, NULL, hdr, pkt, |
173 | | &p, &srcHost, &dstHost, &flow); |
174 | | // ntop->getTrace()->traceEvent(TRACE_ERROR, "dissecting packet"); |
175 | | } |
176 | | ntop->getTrace()->traceEvent(TRACE_INFO, "Ending"); |
177 | | } |
178 | | |
179 | | #else |
180 | | |
181 | 15.4k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { |
182 | 15.4k | if (len == 0) return -1; |
183 | | |
184 | 15.4k | FILE *fd = fmemopen((void *)buf, len, "r"); |
185 | 15.4k | if (fd == NULL) { |
186 | 0 | std::cerr << "Cannot create the file descriptor with fmemopen" |
187 | 0 | << std::endl; |
188 | 0 | return -1; |
189 | 0 | } |
190 | | |
191 | 15.4k | char pcap_error_buffer[PCAP_ERRBUF_SIZE]; |
192 | 15.4k | pcap_t *pcap_handle; |
193 | 15.4k | const u_char *pkt; |
194 | 15.4k | struct pcap_pkthdr *hdr; |
195 | 15.4k | u_int16_t p; |
196 | 15.4k | Host *srcHost = NULL, *dstHost = NULL; |
197 | 15.4k | Flow *flow = NULL; |
198 | | |
199 | 15.4k | pcap_handle = pcap_fopen_offline(fd, pcap_error_buffer); |
200 | 15.4k | if (pcap_handle == NULL) goto end; |
201 | 15.4k | iface->set_datalink(pcap_datalink(pcap_handle)); |
202 | 15.4k | pcap_setnonblock(pcap_handle, 1, pcap_error_buffer); |
203 | | |
204 | 130k | while (pcap_next_ex(pcap_handle, &hdr, &pkt) > 0) { |
205 | 114k | iface->dissectPacket(UNKNOWN_PKT_IFACE_IDX, |
206 | 114k | DUMMY_BRIDGE_INTERFACE_ID, DLT_NULL, true, NULL, hdr, pkt, |
207 | 114k | &p, &srcHost, &dstHost, &flow); |
208 | 114k | } |
209 | 15.4k | pcap_close(pcap_handle); |
210 | | |
211 | 15.4k | end: |
212 | 15.4k | iface->cleanup(); |
213 | | |
214 | 15.4k | return 0; |
215 | 15.4k | } |
216 | | |
217 | | #endif |