56e816b12bf119e281d3293acd4e70143453779b
[metze/wireshark/wip.git] / tools / oss-fuzzshark / fuzzshark.c
1 /* oss-fuzzshark.c
2  *
3  * Fuzzer variant of Wireshark for oss-fuzz
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include <config.h>
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <limits.h>
30
31 #include <glib.h>
32
33 #include <epan/epan-int.h>
34 #include <epan/epan.h>
35
36 #include <wsutil/cmdarg_err.h>
37 #include <wsutil/crash_info.h>
38 #include <wsutil/filesystem.h>
39 #include <wsutil/privileges.h>
40 #include <wsutil/report_message.h>
41 #include <version_info.h>
42
43 #include <wiretap/wtap.h>
44
45 #include <epan/color_filters.h>
46 #include <epan/timestamp.h>
47 #include <epan/prefs.h>
48 #include <epan/column.h>
49 #include <epan/print.h>
50 #include <epan/epan_dissect.h>
51
52 #ifdef HAVE_PLUGINS
53 #include <wsutil/plugins.h>
54 #endif
55
56 #define EPAN_INIT_FAIL 2
57
58 static column_info fuzz_cinfo;
59 static epan_t *fuzz_epan;
60 static epan_dissect_t *fuzz_edt;
61
62 /*
63  * General errors and warnings are reported with an console message
64  * in oss-fuzzshark.
65  */
66 static void
67 failure_warning_message(const char *msg_format, va_list ap)
68 {
69         fprintf(stderr, "oss-fuzzshark: ");
70         vfprintf(stderr, msg_format, ap);
71         fprintf(stderr, "\n");
72 }
73
74 /*
75  * Open/create errors are reported with an console message in oss-fuzzshark.
76  */
77 static void
78 open_failure_message(const char *filename, int err, gboolean for_writing)
79 {
80         fprintf(stderr, "oss-fuzzshark: ");
81         fprintf(stderr, file_open_error_message(err, for_writing), filename);
82         fprintf(stderr, "\n");
83 }
84
85 /*
86  * Read errors are reported with an console message in oss-fuzzshark.
87  */
88 static void
89 read_failure_message(const char *filename, int err)
90 {
91         cmdarg_err("An error occurred while reading from the file \"%s\": %s.", filename, g_strerror(err));
92 }
93
94 /*
95  * Write errors are reported with an console message in oss-fuzzshark.
96  */
97 static void
98 write_failure_message(const char *filename, int err)
99 {
100         cmdarg_err("An error occurred while writing to the file \"%s\": %s.", filename, g_strerror(err));
101 }
102
103 /*
104  * Report additional information for an error in command-line arguments.
105  */
106 static void
107 failure_message_cont(const char *msg_format, va_list ap)
108 {
109         vfprintf(stderr, msg_format, ap);
110         fprintf(stderr, "\n");
111 }
112
113 static const nstime_t *
114 fuzzshark_get_frame_ts(struct packet_provider *prov _U_, guint32 frame_num _U_)
115 {
116         static nstime_t empty;
117
118         return &empty;
119 }
120
121 static epan_t *
122 fuzzshark_epan_new(void)
123 {
124         epan_t *epan = epan_new(NULL);
125
126         epan->get_frame_ts = fuzzshark_get_frame_ts;
127         epan->get_interface_name = NULL;
128         epan->get_interface_description = NULL;
129         epan->get_user_comment = NULL;
130
131         return epan;
132 }
133
134 static dissector_handle_t
135 get_dissector_handle(const char *table, const char *target)
136 {
137         dissector_handle_t fuzz_handle = NULL;
138
139         if (table != NULL && target != NULL)
140         {
141                 /* search for handle, cannot use dissector_table_get_dissector_handle() cause it's using short-name, and I already used filter name in samples ;/ */
142                 GSList *handle_list = dissector_table_get_dissector_handles(find_dissector_table(table));
143                 while (handle_list)
144                 {
145                         dissector_handle_t handle = (dissector_handle_t) handle_list->data;
146                         const char *handle_filter_name = proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle));
147
148                         if (!strcmp(handle_filter_name, target))
149                                 fuzz_handle = handle;
150                         handle_list = handle_list->next;
151                 }
152         }
153         else if (target != NULL)
154         {
155                 fuzz_handle = find_dissector(target);
156         }
157
158         return fuzz_handle;
159 }
160
161 static int
162 fuzz_init(int argc _U_, char **argv)
163 {
164         GString             *comp_info_str;
165         GString             *runtime_info_str;
166         char                *init_progfile_dir_error;
167
168         char                *err_msg = NULL;
169         e_prefs             *prefs_p;
170         int                  ret = EXIT_SUCCESS;
171
172         dissector_handle_t fuzz_handle = NULL;
173
174         g_setenv("WIRESHARK_DEBUG_WMEM_OVERRIDE", "simple", 0);
175         g_setenv("G_SLICE", "always-malloc", 0);
176
177         cmdarg_err_init(failure_warning_message, failure_message_cont);
178
179         /*
180          * Get credential information for later use, and drop privileges
181          * before doing anything else.
182          * Let the user know if anything happened.
183          */
184         init_process_policies();
185 #if 0 /* disable setresgid(), it fails with -EINVAL https://github.com/google/oss-fuzz/pull/532#issuecomment-294515463 */
186         relinquish_special_privs_perm();
187 #endif
188
189         /*
190          * Attempt to get the pathname of the executable file.
191          */
192         init_progfile_dir_error = init_progfile_dir(argv[0], fuzz_init);
193         if (init_progfile_dir_error != NULL)
194                 fprintf(stderr, "fuzzshark: Can't get pathname of oss-fuzzshark program: %s.\n", init_progfile_dir_error);
195
196         /* Get the compile-time version information string */
197         comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info);
198
199         /* Get the run-time version information string */
200         runtime_info_str = get_runtime_version_info(epan_get_runtime_version_info);
201
202         /* Add it to the information to be reported on a crash. */
203         ws_add_crash_info("OSS Fuzzshark (Wireshark) %s\n"
204              "\n"
205              "%s"
206              "\n"
207              "%s",
208              get_ws_vcs_version_info(),
209              comp_info_str->str,
210              runtime_info_str->str);
211         g_string_free(comp_info_str, TRUE);
212         g_string_free(runtime_info_str, TRUE);
213
214         init_report_message(failure_warning_message, failure_warning_message,
215              open_failure_message, read_failure_message, write_failure_message);
216
217         timestamp_set_type(TS_RELATIVE);
218         timestamp_set_precision(TS_PREC_AUTO);
219         timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
220
221         wtap_init();
222
223 #ifdef HAVE_PLUGINS
224         /* Register all the plugin types we have. */
225         epan_register_plugin_types(); /* Types known to libwireshark */
226
227         /* Scan for plugins.  This does *not* call their registration routines; that's done later. */
228         scan_plugins(REPORT_LOAD_FAILURE);
229
230         /* Register all libwiretap plugin modules. */
231         register_all_wiretap_modules();
232 #endif
233
234         /* Register all dissectors; we must do this before checking for the
235            "-G" flag, as the "-G" flag dumps information registered by the
236            dissectors, and we must do it before we read the preferences, in
237            case any dissectors register preferences. */
238         if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, NULL))
239         {
240                 ret = EPAN_INIT_FAIL;
241                 goto clean_exit;
242         }
243
244         /* Load libwireshark settings from the current profile. */
245         prefs_p = epan_load_settings();
246
247         if (!color_filters_init(&err_msg, NULL))
248         {
249                 fprintf(stderr, "%s\n", err_msg);
250                 g_free(err_msg);
251         }
252
253         /* Notify all registered modules that have had any of their preferences
254            changed either from one of the preferences file or from the command
255            line that their preferences have changed. */
256         prefs_apply_all();
257
258         /* Build the column format array */
259         build_column_format_array(&fuzz_cinfo, prefs_p->num_cols, TRUE);
260
261 #if defined(FUZZ_DISSECTOR_TABLE) && defined(FUZZ_DISSECTOR_TARGET)
262 # define FUZZ_EPAN 1
263         fprintf(stderr, "oss-fuzzshark: configured for dissector: %s in table: %s\n", FUZZ_DISSECTOR_TARGET, FUZZ_DISSECTOR_TABLE);
264         fuzz_handle = get_dissector_handle(FUZZ_DISSECTOR_TABLE, FUZZ_DISSECTOR_TARGET);
265
266 #elif defined(FUZZ_DISSECTOR_TARGET)
267 # define FUZZ_EPAN 2
268         fprintf(stderr, "oss-fuzzshark: configured for dissector: %s\n", FUZZ_DISSECTOR_TARGET);
269         fuzz_handle = get_dissector_handle(FUZZ_DISSECTOR_TARGET);
270
271 #else
272 # define FUZZ_EPAN 3
273         fprintf(stderr, "oss-fuzzshark: target not configured. Using env\n");
274         fuzz_handle = get_dissector_handle(getenv("FUZZSHARK_TABLE"), getenv("FUZZSHARK_TARGET"));
275 #endif
276
277 #ifdef FUZZ_EPAN
278         g_assert(fuzz_handle != NULL);
279         register_postdissector(fuzz_handle);
280 #endif
281
282         fuzz_epan = fuzzshark_epan_new();
283         fuzz_edt = epan_dissect_new(fuzz_epan, TRUE, FALSE);
284
285         return 0;
286 clean_exit:
287         wtap_cleanup();
288         free_progdirs();
289 #ifdef HAVE_PLUGINS
290         plugins_cleanup();
291 #endif
292         return ret;
293 }
294
295 #ifdef FUZZ_EPAN
296 int
297 LLVMFuzzerTestOneInput(guint8 *buf, size_t real_len)
298 {
299         static guint32 framenum = 0;
300         epan_dissect_t *edt = fuzz_edt;
301
302         guint32 len = (guint32) real_len;
303
304         struct wtap_pkthdr whdr;
305         frame_data fdlocal;
306
307         memset(&whdr, 0, sizeof(whdr));
308
309         whdr.rec_type = REC_TYPE_PACKET;
310         whdr.caplen = len;
311         whdr.len = len;
312
313         /* whdr.pkt_encap = WTAP_ENCAP_ETHERNET; */
314         whdr.pkt_encap = G_MAXINT16;
315         whdr.presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN; /* most common flags... */
316
317         frame_data_init(&fdlocal, ++framenum, &whdr, /* offset */ 0, /* cum_bytes */ 0);
318         /* frame_data_set_before_dissect() not needed */
319         epan_dissect_run(edt, WTAP_FILE_TYPE_SUBTYPE_UNKNOWN, &whdr, tvb_new_real_data(buf, len, len), &fdlocal, NULL /* &fuzz_cinfo */);
320         frame_data_destroy(&fdlocal);
321
322         epan_dissect_reset(edt);
323         return 0;
324 }
325
326 #else
327 # error "Missing fuzz target."
328 #endif
329
330 int
331 LLVMFuzzerInitialize(int *argc, char ***argv)
332 {
333         int ret;
334
335         ret = fuzz_init(*argc, *argv);
336         if (ret != 0)
337                 exit(ret);
338
339         return 0;
340 }
341
342 /*
343  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
344  *
345  * Local variables:
346  * c-basic-offset: 8
347  * tab-width: 8
348  * indent-tabs-mode: t
349  * End:
350  *
351  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
352  * :indentSize=8:tabSize=8:noTabs=false:
353  */