From 81a2f870dda76dd2fca64fea159ba05e41981d7f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 19 Jul 2018 15:21:29 -0400 Subject: zebra: Add code for fuzzing netlink This code allows you to fuzz the netlink listening socket in zebra by --enable-fuzzing and passing the -w [FILE] option when running zebra. File collection is stored in /var/run/frr/netlink_* where each number is just a counter to keep the files distinct. Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) (limited to 'zebra/kernel_netlink.c') diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8703b0131..4aed99506 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -20,6 +20,11 @@ #include +#if defined(HANDLE_ZAPI_FUZZING) +#include +#include +#endif + #ifdef HAVE_NETLINK #include "linklist.h" @@ -293,6 +298,97 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } +#if defined(HANDLE_ZAPI_FUZZING) +/* Using globals here to avoid adding function parameters */ + +/* Keep distinct filenames for netlink fuzzy collection */ +static unsigned int netlink_file_counter = 1; + +/* File name to read fuzzed netlink from */ +static char netlink_fuzz_file[MAXPATHLEN] = ""; + +/* Flag for whether to read from file or not */ +static int netlink_read = 0; + +/** + * netlink_set_read() - Sets the read flag + * @flag: Flag value. + * + */ +void set_netlink_read(int flag) +{ + netlink_read = flag; +} + +/** + * netlink_read_init() - Starts the message parser + * @fname: Filename to read. + */ +void netlink_read_init(const char *fname) +{ + snprintf(netlink_fuzz_file, MAXPATHLEN, "%s", fname); + /* Creating this fake socket for testing purposes */ + struct zebra_ns zns = { + .ns_id = 0, + .netlink_cmd = {.sock = -1, + .seq = -1, + .name = "fuzzer_command_channel"}, + .netlink = {.sock = -1, + .seq = -1, + .name = "fuzzer_kernel_message"} + }; + netlink_parse_info(netlink_information_fetch, &zns.netlink, &zns, 1, 0); +} + +/** + * netlink_write_incoming() - Writes all data received from netlink to a file + * @buf: Data from netlink. + * @size: Size of data. + * @counter: Counter for keeping filenames distinct. + */ +static void netlink_write_incoming(const char *buf, const unsigned int size, + unsigned int counter) +{ + char fname[MAXPATHLEN]; + FILE *f; + + zserv_privs.change(ZPRIVS_RAISE); + snprintf(fname, MAXPATHLEN, "%s/%s_%u", DAEMON_VTY_DIR, "netlink", + counter); + f = fopen(fname, "w"); + if (f) { + fwrite(buf, 1, size, f); + fclose(f); + } + zserv_privs.change(ZPRIVS_LOWER); +} + +/** + * netlink_read_file() - Reads netlink data from file + * @buf: Netlink buffer being overwritten. + * @fname: File name to read from. + * + * Return: Size of file. + */ +static long netlink_read_file(char *buf, const char *fname) +{ + FILE *f; + long file_bytes = -1; + zserv_privs.change(ZPRIVS_RAISE); + f = fopen(fname, "r"); + if (f) { + fseek(f, 0, SEEK_END); + file_bytes = ftell(f); + rewind(f); + fread(buf, file_bytes, 1, f); + fclose(f); + } + zserv_privs.change(ZPRIVS_LOWER); + return file_bytes; +} + +#endif + static int kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); @@ -602,7 +698,18 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (count && read_in >= count) return 0; +#if defined(HANDLE_ZAPI_FUZZING) + /* Check if reading and filename is set */ + if (netlink_read && '\0' != netlink_fuzz_file[0]) { + zlog_debug("Reading netlink fuzz file"); + status = netlink_read_file(buf, netlink_fuzz_file); + snl.nl_pid = 0; + } else { + status = recvmsg(nl->sock, &msg, 0); + } +#else status = recvmsg(nl->sock, &msg, 0); +#endif if (status < 0) { if (errno == EINTR) continue; @@ -636,6 +743,14 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), zlog_hexdump(buf, status); } +#if defined(HANDLE_ZAPI_FUZZING) + if (!netlink_read) { + zlog_debug("Writing incoming netlink message"); + netlink_write_incoming(buf, status, + netlink_file_counter++); + } +#endif + read_in++; for (h = (struct nlmsghdr *)buf; NLMSG_OK(h, (unsigned int)status); -- cgit v1.2.3 From bd7891fd70f041f1bc52f8aae538a33231c489e2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 23 Jul 2018 11:25:31 -0400 Subject: Style for Add code for fuzzing netlink Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'zebra/kernel_netlink.c') diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 4aed99506..8844e6697 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -308,7 +308,7 @@ static unsigned int netlink_file_counter = 1; static char netlink_fuzz_file[MAXPATHLEN] = ""; /* Flag for whether to read from file or not */ -static int netlink_read = 0; +int netlink_read; /** * netlink_set_read() - Sets the read flag @@ -374,6 +374,7 @@ static long netlink_read_file(char *buf, const char *fname) { FILE *f; long file_bytes = -1; + zserv_privs.change(ZPRIVS_RAISE); f = fopen(fname, "r"); if (f) { -- cgit v1.2.3 From acfa8927f933e42caf46602802ce298e18fc0c76 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 24 Jul 2018 13:39:25 -0400 Subject: Refactor code for new fuzzing netlink flag Changed the configure flag used by netlink fuzzing and refactored code accordingly. Signed-off-by: Stephen Worley --- configure.ac | 6 ++++++ zebra/kernel_netlink.c | 28 +++++++++------------------- zebra/kernel_netlink.h | 6 +++--- zebra/main.c | 35 +++++++++++++++++++++++------------ 4 files changed, 41 insertions(+), 34 deletions(-) (limited to 'zebra/kernel_netlink.c') diff --git a/configure.ac b/configure.ac index 8846fcdf7..f967fce8c 100755 --- a/configure.ac +++ b/configure.ac @@ -436,6 +436,8 @@ AC_ARG_ENABLE(datacenter, AS_HELP_STRING([--enable-datacenter], [enable Compilation for Data Center Extensions])) AC_ARG_ENABLE(fuzzing, AS_HELP_STRING([--enable-fuzzing], [enable ability to fuzz various parts of FRR])) +AC_ARG_ENABLE(netlink_fuzzing, + AS_HELP_STRING([--enable-netlink-fuzzing], [enable ability to fuzz netlink listening socket in zebra])) AC_ARG_ENABLE(rr-semantics, AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics])) AC_ARG_ENABLE([protobuf], @@ -501,6 +503,10 @@ if test "${enable_fuzzing}" = "yes" ; then AC_DEFINE(HANDLE_ZAPI_FUZZING,,Compile extensions to use with a fuzzer) fi +if test "${enable_netlink_fuzzing}" = "yes" ; then + AC_DEFINE(HANDLE_NETLINK_FUZZING,,Compile extensions to use with a fuzzer for netlink) +fi + if test "${enable_cumulus}" = "yes" ; then AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in) fi diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8844e6697..4d1991f09 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -20,10 +20,10 @@ #include -#if defined(HANDLE_ZAPI_FUZZING) +#if defined(HANDLE_NETLINK_FUZZING) #include #include -#endif +#endif /* HANDLE_NETLINK_FUZZING */ #ifdef HAVE_NETLINK @@ -298,7 +298,7 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } -#if defined(HANDLE_ZAPI_FUZZING) +#if defined(HANDLE_NETLINK_FUZZING) /* Using globals here to avoid adding function parameters */ /* Keep distinct filenames for netlink fuzzy collection */ @@ -308,17 +308,7 @@ static unsigned int netlink_file_counter = 1; static char netlink_fuzz_file[MAXPATHLEN] = ""; /* Flag for whether to read from file or not */ -int netlink_read; - -/** - * netlink_set_read() - Sets the read flag - * @flag: Flag value. - * - */ -void set_netlink_read(int flag) -{ - netlink_read = flag; -} +bool netlink_read = false; /** * netlink_read_init() - Starts the message parser @@ -388,7 +378,7 @@ static long netlink_read_file(char *buf, const char *fname) return file_bytes; } -#endif +#endif /* HANDLE_NETLINK_FUZZING */ static int kernel_read(struct thread *thread) { @@ -699,7 +689,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (count && read_in >= count) return 0; -#if defined(HANDLE_ZAPI_FUZZING) +#if defined(HANDLE_NETLINK_FUZZING) /* Check if reading and filename is set */ if (netlink_read && '\0' != netlink_fuzz_file[0]) { zlog_debug("Reading netlink fuzz file"); @@ -710,7 +700,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), } #else status = recvmsg(nl->sock, &msg, 0); -#endif +#endif /* HANDLE_NETLINK_FUZZING */ if (status < 0) { if (errno == EINTR) continue; @@ -744,13 +734,13 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), zlog_hexdump(buf, status); } -#if defined(HANDLE_ZAPI_FUZZING) +#if defined(HANDLE_NETLINK_FUZZING) if (!netlink_read) { zlog_debug("Writing incoming netlink message"); netlink_write_incoming(buf, status, netlink_file_counter++); } -#endif +#endif /* HANDLE_NETLINK_FUZZING */ read_in++; for (h = (struct nlmsghdr *)buf; diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 78bfdfa17..65df15599 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -45,10 +45,10 @@ extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); extern const char *nl_rttype_to_str(uint8_t rttype); -#if defined(HANDLE_ZAPI_FUZZING) -extern void set_netlink_read(int flag); +#if defined(HANDLE_NETLINK_FUZZING) +extern bool netlink_read; extern void netlink_read_init(const char *fname); -#endif +#endif /* HANDLE_NETLINK_FUZZING */ extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), struct nlsock *nl, struct zebra_ns *zns, int count, int startup); diff --git a/zebra/main.c b/zebra/main.c index a7bbbb9d4..0b8bc6a0a 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -54,9 +54,9 @@ #include "zebra/zebra_rnh.h" #include "zebra/zebra_pbr.h" -#if defined(HANDLE_ZAPI_FUZZING) +#if defined(HANDLE_NETLINK_FUZZING) #include "zebra/kernel_netlink.h" -#endif +#endif /* HANDLE_NETLINK_FUZZING */ #define ZEBRA_PTM_SUPPORT @@ -218,8 +218,10 @@ int main(int argc, char **argv) socklen_t dummylen; #if defined(HANDLE_ZAPI_FUZZING) char *zapi_fuzzing = NULL; +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) char *netlink_fuzzing = NULL; -#endif +#endif /* HANDLE_NETLINK_FUZZING */ vrf_configure_backend(VRF_BACKEND_VRF_LITE); logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); @@ -232,8 +234,11 @@ int main(int argc, char **argv) "s:n" #endif #if defined(HANDLE_ZAPI_FUZZING) - "c:w:" -#endif + "c:" +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + "w:" +#endif /* HANDLE_NETLINK_FUZZING */ , longopts, " -b, --batch Runs in batch mode\n" @@ -250,8 +255,10 @@ int main(int argc, char **argv) #endif /* HAVE_NETLINK */ #if defined(HANDLE_ZAPI_FUZZING) " -c Bypass normal startup and use this file for testing of zapi\n" - " -w Bypass normal startup and use this file for testing of netlink input" -#endif +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + " -w Bypass normal startup and use this file for testing of netlink input\n" +#endif /* HANDLE_NETLINK_FUZZING */ ); while (1) { @@ -313,17 +320,18 @@ int main(int argc, char **argv) #if defined(HANDLE_ZAPI_FUZZING) case 'c': zapi_fuzzing = optarg; - set_netlink_read(1); break; +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) case 'w': netlink_fuzzing = optarg; /* This ensures we are aren't writing any of the * startup netlink messages that happen when we * just want to read. */ - set_netlink_read(1); + netlink_read = true; break; -#endif +#endif /* HANDLE_NETLINK_FUZZING */ default: frr_help_exit(1); break; @@ -403,11 +411,14 @@ int main(int argc, char **argv) if (zapi_fuzzing) { zserv_read_file(zapi_fuzzing); exit(0); - } else if (netlink_fuzzing) { + } +#endif /* HANDLE_ZAPI_FUZZING */ +#if defined(HANDLE_NETLINK_FUZZING) + if (netlink_fuzzing) { netlink_read_init(netlink_fuzzing); exit(0); } -#endif +#endif /* HANDLE_NETLINK_FUZZING */ frr_run(zebrad.master); -- cgit v1.2.3 From ef593eff0084285280e754c4866eb1bec1e67008 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 26 Jul 2018 14:30:04 -0400 Subject: zebra: Make fuzzer code use default netlink socket Change the fuzzing code so that it fakes data from the listening socket rather than using its own pseudo one. Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'zebra/kernel_netlink.c') diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 4d1991f09..483aab027 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -318,16 +318,9 @@ void netlink_read_init(const char *fname) { snprintf(netlink_fuzz_file, MAXPATHLEN, "%s", fname); /* Creating this fake socket for testing purposes */ - struct zebra_ns zns = { - .ns_id = 0, - .netlink_cmd = {.sock = -1, - .seq = -1, - .name = "fuzzer_command_channel"}, - .netlink = {.sock = -1, - .seq = -1, - .name = "fuzzer_kernel_message"} - }; - netlink_parse_info(netlink_information_fetch, &zns.netlink, &zns, 1, 0); + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + + netlink_parse_info(netlink_information_fetch, &zns->netlink, zns, 1, 0); } /** @@ -371,7 +364,7 @@ static long netlink_read_file(char *buf, const char *fname) fseek(f, 0, SEEK_END); file_bytes = ftell(f); rewind(f); - fread(buf, file_bytes, 1, f); + fread(buf, NL_RCV_PKT_BUF_SIZE, 1, f); fclose(f); } zserv_privs.change(ZPRIVS_LOWER); -- cgit v1.2.3 From 29bf7b0b67d6ab8ed567f983834e7259082f8434 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 26 Jul 2018 14:34:28 -0400 Subject: Style, don't initialize netlink_read flag Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'zebra/kernel_netlink.c') diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 483aab027..bc2ed7f8f 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -308,7 +308,7 @@ static unsigned int netlink_file_counter = 1; static char netlink_fuzz_file[MAXPATHLEN] = ""; /* Flag for whether to read from file or not */ -bool netlink_read = false; +bool netlink_read; /** * netlink_read_init() - Starts the message parser -- cgit v1.2.3