From: Stephen Worley Date: Thu, 19 Jul 2018 19:21:29 +0000 (-0400) Subject: zebra: Add code for fuzzing netlink X-Git-Tag: frr-6.1-dev~121^2~5 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=81a2f870dda76dd2fca64fea159ba05e41981d7f;p=matthieu%2Ffrr.git 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 --- diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8703b01319..4aed995060 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); diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 80bb876e0b..78bfdfa178 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -45,6 +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); +extern void netlink_read_init(const char *fname); +#endif 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 3e44a41707..01466d3fb0 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -54,6 +54,10 @@ #include "zebra/zebra_rnh.h" #include "zebra/zebra_pbr.h" +#if defined(HANDLE_ZAPI_FUZZING) +#include "zebra/kernel_netlink.h" +#endif + #define ZEBRA_PTM_SUPPORT /* Zebra instance */ @@ -213,7 +217,8 @@ int main(int argc, char **argv) struct sockaddr_storage dummy; socklen_t dummylen; #if defined(HANDLE_ZAPI_FUZZING) - char *fuzzing = NULL; + char *zapi_fuzzing = NULL; + char *netlink_fuzzing = NULL; #endif vrf_configure_backend(VRF_BACKEND_VRF_LITE); @@ -227,7 +232,7 @@ int main(int argc, char **argv) "s:n" #endif #if defined(HANDLE_ZAPI_FUZZING) - "c:" + "c:w:" #endif , longopts, @@ -244,7 +249,8 @@ int main(int argc, char **argv) " --v6-rr-semantics Use v6 RR semantics\n" #endif /* HAVE_NETLINK */ #if defined(HANDLE_ZAPI_FUZZING) - " -c Bypass normal startup and use this file for testing of zapi" + " -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 ); @@ -306,7 +312,16 @@ int main(int argc, char **argv) #endif /* HAVE_NETLINK */ #if defined(HANDLE_ZAPI_FUZZING) case 'c': - fuzzing = optarg; + zapi_fuzzing = optarg; + set_netlink_read(1); + break; + 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); break; #endif default: @@ -349,6 +364,7 @@ int main(int argc, char **argv) /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ + /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in @@ -385,8 +401,11 @@ int main(int argc, char **argv) zebra_rnh_init(); #if defined(HANDLE_ZAPI_FUZZING) - if (fuzzing) { - zserv_read_file(fuzzing); + if (zapi_fuzzing) { + zserv_read_file(zapi_fuzzing); + exit(0); + } else if (netlink_fuzzing) { + netlink_read_init(netlink_fuzzing); exit(0); } #endif