From cf4690725667211bc8a8998e362c6bda24dd7528 Mon Sep 17 00:00:00 2001 From: Joseph Bisch Date: Sat, 7 Jan 2017 20:01:07 -0500 Subject: [PATCH] Add frontend for fuzzing Use the following configure command: $ ./configure --with-fuzzer --with-fuzzer-lib=/path/to/libFuzzer.a \ CC=clang CXX=clang++ Places an irssi-fuzz in src/fe-fuzz/ after build. Also can specify SANFLAGS to override the chosen sanitizer flags (defaults to "-g -fsanitize=address -fsanitize-coverage=trace-pc-guard"). --- .gitignore | 4 + configure.ac | 40 ++++++++++ src/Makefile.am | 6 +- src/fe-fuzz/Makefile.am | 25 ++++++ src/fe-fuzz/irssi.c | 58 ++++++++++++++ src/fe-fuzz/module-formats.c | 82 ++++++++++++++++++++ src/fe-fuzz/module-formats.h | 58 ++++++++++++++ src/fe-fuzz/tokens.txt | 143 +++++++++++++++++++++++++++++++++++ 8 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 src/fe-fuzz/Makefile.am create mode 100644 src/fe-fuzz/irssi.c create mode 100644 src/fe-fuzz/module-formats.c create mode 100644 src/fe-fuzz/module-formats.h create mode 100644 src/fe-fuzz/tokens.txt diff --git a/.gitignore b/.gitignore index 945b6cf6..9af0c4b1 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ docs/help/[a-z]* docs/help/in/Makefile.am src/fe-text/irssi +src/fe-fuzz/irssi-fuzz src/fe-common/irc/irc-modules.c src/irc/irc.c @@ -46,6 +47,9 @@ src/perl/ui/*.c src/perl/*/MYMETA.* src/perl/*/Makefile.old +src/fe-fuzz/crash-* +src/fe-fuzz/oom-* + *.a *.bs *.la diff --git a/configure.ac b/configure.ac index 15ae74b1..03c7ddf5 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,19 @@ AC_ARG_WITH(bot, fi, want_irssibot=no) +AC_ARG_WITH(fuzzer, +[ --with-fuzzer Build irssi-fuzzer], + if test x$withval = xno; then + want_irssifuzzer=no + else + want_irssifuzzer=yes + fi, + want_irssifuzzer=no) + +AC_ARG_WITH(fuzzer-lib, +[ --with-fuzzer-lib Specify path to fuzzer library], + fuzzerlibpath="$withval") + AC_ARG_WITH(proxy, [ --with-proxy Build irssi-proxy], if test x$withval = xno; then @@ -297,6 +310,30 @@ if test "x$want_textui" != "xno"; then fi +dnl ** +dnl ** irssifuzzer checks +dnl ** + +if test "$want_irssifuzzer" != "no"; then + dnl * we need to build with -fsanitize-coverage=trace-pc-guard + dnl * otherwise fuzzer won't be very successful at finding bugs :) + if test -z "$SANFLAGS"; then + SANFLAGS="-g -fsanitize=address -fsanitize-coverage=trace-pc-guard" + fi + CFLAGS="$CFLAGS $SANFLAGS" + CXXFLAGS="$CXXFLAGS $SANFLAGS" + + AC_MSG_CHECKING(for fuzzer library) + + if test -z "$fuzzerlibpath"; then + AC_MSG_RESULT([not found, building without fuzzer front end]) + want_irssifuzzer=no + else + FUZZER_LIBS="$fuzzerlibpath" + AC_SUBST(FUZZER_LIBS) + fi +fi + dnl ** dnl ** perl checks dnl ** @@ -456,6 +493,7 @@ fi dnl ** check what we want to build AM_CONDITIONAL(BUILD_TEXTUI, test "$want_textui" = "yes") AM_CONDITIONAL(BUILD_IRSSIBOT, test "$want_irssibot" = "yes") +AM_CONDITIONAL(BUILD_IRSSIFUZZER, test "$want_irssifuzzer" = "yes") AM_CONDITIONAL(BUILD_IRSSIPROXY, test "$want_irssiproxy" = "yes") AM_CONDITIONAL(HAVE_PERL, test "$want_perl" != "no") @@ -572,6 +610,7 @@ src/fe-common/core/Makefile src/fe-common/irc/Makefile src/fe-common/irc/dcc/Makefile src/fe-common/irc/notifylist/Makefile +src/fe-fuzz/Makefile src/fe-none/Makefile src/fe-text/Makefile src/lib-config/Makefile @@ -611,6 +650,7 @@ echo echo "Building text frontend ........... : $want_textui" echo "Building irssi bot ............... : $want_irssibot" +echo "Building irssi fuzzer ............ : $want_irssifuzzer" echo "Building irssi proxy ............. : $want_irssiproxy" if test "x$have_gmodule" = "xyes"; then echo "Building with module support ..... : yes" diff --git a/src/Makefile.am b/src/Makefile.am index 76a4af4f..a7fb2ee2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,10 @@ if BUILD_IRSSIBOT BOTUI=fe-none endif +if BUILD_IRSSIFUZZER +FUZZERUI=fe-fuzz +endif + if HAVE_PERL PERLDIR=perl endif @@ -14,4 +18,4 @@ pkginc_srcdir=$(pkgincludedir)/src pkginc_src_HEADERS = \ common.h -SUBDIRS = lib-config core irc fe-common $(PERLDIR) $(TEXTUI) $(BOTUI) +SUBDIRS = lib-config core irc fe-common $(PERLDIR) $(TEXTUI) $(BOTUI) $(FUZZERUI) diff --git a/src/fe-fuzz/Makefile.am b/src/fe-fuzz/Makefile.am new file mode 100644 index 00000000..2ecf4a85 --- /dev/null +++ b/src/fe-fuzz/Makefile.am @@ -0,0 +1,25 @@ +bin_PROGRAMS = irssi-fuzz + +# Force link with clang++ for libfuzzer support +CCLD=clang++ $(CXXFLAGS) + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/core/ \ + -I$(top_srcdir)/src/irc/core/ \ + -I$(top_srcdir)/src/fe-common/core/ \ + $(GLIB_CFLAGS) + +irssi_fuzz_DEPENDENCIES = @COMMON_LIBS@ + +irssi_fuzz_LDADD = \ + @COMMON_LIBS@ \ + @PROG_LIBS@ \ + $(FUZZER_LIBS) + +irssi_fuzz_SOURCES = \ + irssi.c \ + module-formats.c + +noinst_HEADERS = \ + module-formats.h diff --git a/src/fe-fuzz/irssi.c b/src/fe-fuzz/irssi.c new file mode 100644 index 00000000..3b2c617a --- /dev/null +++ b/src/fe-fuzz/irssi.c @@ -0,0 +1,58 @@ +/* + irssi.c : irssi + + Copyright (C) 2017 Joseph Bisch + + 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. +*/ + +#include "module.h" +#include "modules-load.h" +#include "levels.h" +#include "module-formats.h" +#include "themes.h" +#include "core.h" +#include "fe-common-core.h" +#include "args.h" +#include "printtext.h" + +#include +#include +#include +#include +#include + +int LLVMFuzzerInitialize(int *argc, char ***argv) { + core_register_options(); + fe_common_core_register_options(); + /* no args */ + args_execute(0, NULL); + core_preinit((*argv)[0]); + core_init(); + fe_common_core_init(); + theme_register(gui_text_formats); + module_register("core", "fe-fuzz"); + printtext_string(NULL, NULL, MSGLEVEL_CLIENTCRAP, "init"); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + char *copy = (char *)malloc(sizeof(char)*(size+1)); + memcpy(copy, data, size); + copy[size] = '\0'; + printtext_string(NULL, NULL, MSGLEVEL_CLIENTCRAP, copy); + free(copy); + return 0; +} diff --git a/src/fe-fuzz/module-formats.c b/src/fe-fuzz/module-formats.c new file mode 100644 index 00000000..899827c2 --- /dev/null +++ b/src/fe-fuzz/module-formats.c @@ -0,0 +1,82 @@ +/* + module-formats.c : irssi + + Copyright (C) 2000 Timo Sirainen + + 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. +*/ + +#include "module.h" +#include "formats.h" + +FORMAT_REC gui_text_formats[] = +{ + { MODULE_NAME, "Text user interface", 0 }, + + /* ---- */ + { NULL, "Lastlog", 0 }, + + { "lastlog_too_long", "/LASTLOG would print $0 lines. If you really want to print all these lines use -force option.", 1, { 1 } }, + { "lastlog_count", "{hilight Lastlog}: $0 lines", 1, { 1 } }, + { "lastlog_start", "{hilight Lastlog}:", 0 }, + { "lastlog_end", "{hilight End of Lastlog}", 0 }, + { "lastlog_separator", "--", 0 }, + { "lastlog_date", "%%F ", 0 }, + + /* ---- */ + { NULL, "Windows", 0 }, + + { "refnum_not_found", "Window number $0 not found", 1, { 0 } }, + { "window_too_small", "Not enough room to resize this window", 0 }, + { "cant_hide_last", "You can't hide the last window", 0 }, + { "cant_hide_sticky_windows", "You can't hide sticky windows (use /WINDOW STICK OFF)", 0 }, + { "cant_show_sticky_windows", "You can't show sticky windows (use /WINDOW STICK OFF)", 0 }, + { "window_not_sticky", "Window is not sticky", 0 }, + { "window_set_sticky", "Window set sticky", 0 }, + { "window_unset_sticky", "Window is not sticky anymore", 0 }, + { "window_info_sticky", "%#Sticky : $0", 1, { 0 } }, + { "window_info_scroll", "%#Scroll : $0", 1, { 0 } }, + { "window_scroll", "Window scroll mode is now $0", 1, { 0 } }, + { "window_scroll_unknown", "Unknown scroll mode $0, must be ON, OFF or DEFAULT", 1, { 0 } }, + + /* ---- */ + { NULL, "Statusbars", 0 }, + + { "statusbar_list_header", "%#Name Type Placement Position Visible", 0 }, + { "statusbar_list_footer", "", 0 }, + { "statusbar_list", "%#$[30]0 $[6]1 $[9]2 $[8]3 $4", 5, { 0, 0, 0, 1, 0 } }, + { "statusbar_info_name", "%#Statusbar: {hilight $0}", 1, { 0 } }, + { "statusbar_info_type", "%#Type : $0", 1, { 0 } }, + { "statusbar_info_placement", "%#Placement: $0", 1, { 0 } }, + { "statusbar_info_position", "%#Position : $0", 1, { 1 } }, + { "statusbar_info_visible", "%#Visible : $0", 1, { 0 } }, + { "statusbar_info_item_header", "%#Items : Name Priority Alignment", 0 }, + { "statusbar_info_item_footer", "", 0 }, + { "statusbar_info_item_name", "%# : $[35]0 $[9]1 $2", 3, { 0, 1, 0 } }, + { "statusbar_not_found", "Statusbar doesn't exist: $0", 1, { 0 } }, + { "statusbar_item_not_found", "Statusbar item doesn't exist: $0", 1, { 0 } }, + { "statusbar_unknown_command", "Unknown statusbar command: $0", 1, { 0 } }, + { "statusbar_unknown_type", "Statusbar type must be 'window' or 'root'", 1, { 0 } }, + { "statusbar_unknown_placement", "Statusbar placement must be 'top' or 'bottom'", 1, { 0 } }, + { "statusbar_unknown_visibility", "Statusbar visibility must be 'always', 'active' or 'inactive'", 1, { 0 } }, + + /* ---- */ + { NULL, "Pasting", 0 }, + + { "paste_warning", "Pasting $0 lines to $1. Press Ctrl-K if you wish to do this or Ctrl-C to cancel.", 2, { 1, 0 } }, + { "paste_prompt", "Hit Ctrl-K to paste, Ctrl-C to abort?", 0 }, + + { NULL, NULL, 0 } +}; diff --git a/src/fe-fuzz/module-formats.h b/src/fe-fuzz/module-formats.h new file mode 100644 index 00000000..3fa8c511 --- /dev/null +++ b/src/fe-fuzz/module-formats.h @@ -0,0 +1,58 @@ +#include "formats.h" + +enum { + TXT_MODULE_NAME, + + TXT_FILL_1, + + TXT_LASTLOG_TOO_LONG, + TXT_LASTLOG_COUNT, + TXT_LASTLOG_START, + TXT_LASTLOG_END, + TXT_LASTLOG_SEPARATOR, + TXT_LASTLOG_DATE, + + TXT_FILL_2, + + TXT_REFNUM_NOT_FOUND, + TXT_WINDOW_TOO_SMALL, + TXT_CANT_HIDE_LAST, + TXT_CANT_HIDE_STICKY_WINDOWS, + TXT_CANT_SHOW_STICKY_WINDOWS, + TXT_WINDOW_NOT_STICKY, + TXT_WINDOW_SET_STICKY, + TXT_WINDOW_UNSET_STICKY, + TXT_WINDOW_INFO_STICKY, + TXT_WINDOW_INFO_SCROLL, + TXT_WINDOW_SCROLL, + TXT_WINDOW_SCROLL_UNKNOWN, + + TXT_FILL_3, + + TXT_STATUSBAR_LIST_HEADER, + TXT_STATUSBAR_LIST_FOOTER, + TXT_STATUSBAR_LIST, + TXT_STATUSBAR_INFO_NAME, + TXT_STATUSBAR_INFO_TYPE, + TXT_STATUSBAR_INFO_PLACEMENT, + TXT_STATUSBAR_INFO_POSITION, + TXT_STATUSBAR_INFO_VISIBLE, + TXT_STATUSBAR_INFO_ITEM_HEADER, + TXT_STATUSBAR_INFO_ITEM_FOOTER, + TXT_STATUSBAR_INFO_ITEM_NAME, + TXT_STATUSBAR_NOT_FOUND, + TXT_STATUSBAR_ITEM_NOT_FOUND, + TXT_STATUSBAR_UNKNOWN_COMMAND, + TXT_STATUSBAR_UNKNOWN_TYPE, + TXT_STATUSBAR_UNKNOWN_PLACEMENT, + TXT_STATUSBAR_UNKNOWN_VISIBILITY, + + TXT_FILL_4, + + TXT_PASTE_WARNING, + TXT_PASTE_PROMPT, + + TXT_COUNT +}; + +extern FORMAT_REC gui_text_formats[TXT_COUNT+1]; diff --git a/src/fe-fuzz/tokens.txt b/src/fe-fuzz/tokens.txt new file mode 100644 index 00000000..e337b6e9 --- /dev/null +++ b/src/fe-fuzz/tokens.txt @@ -0,0 +1,143 @@ +"@%+" +"*@*!*" +"001" +"002" +"003" +"004" +"005" +"221" +"254" +"271" +"272" +"281" +"301" +"302" +"303" +"305" +"306" +"311" +"312" +"313" +"314" +"315" +"317" +"318" +"319" +"324" +"326" +"327" +"328" +"329" +"330" +"332" +"333" +"338" +"341" +"344" +"345" +"346" +"347" +"348" +"349" +"352" +"353" +"364" +"365" +"366" +"367" +"368" +"369" +"372" +"375" +"376" +"377" +"378" +"379" +"381" +"386" +"387" +"388" +"389" +"396" +"401" +"403" +"404" +"405" +"407" +"408" +"410" +"421" +"422" +"433" +"436" +"437" +"438" +"439" +"442" +"465" +"470" +"471" +"472" +"473" +"474" +"475" +"476" +"477" +"478" +"479" +"482" +"486" +"489" +"494" +"506" +"707" +"716" +"717" +"728" +"729" +"902" +"903" +"904" +"905" +"906" +"907" +":a" +"+a" +"ACK" +"authenticate" +"away" +"-b" +"+b" +"cap" +"#chan" +"connected" +"empty" +"error" +"invite" +"join" +"kick" +"kill" +"LS" +"mode" +"multi-prefix" +"NAK" +"network" +"nick" +"nicklen" +"notice" +"-o" +"+o" +"part" +"ping" +"pong" +"prefix" +"privmsg" +"quit" +"sasl" +"topic" +"wallops" +"watch" +":\x01" +":\x01ACTION" +":\x01PING" +":\x01VERSION"