diff options
| author | Stephen Worley <sworley@cumulusnetworks.com> | 2018-07-19 15:21:29 -0400 |
|---|---|---|
| committer | Stephen Worley <sworley@cumulusnetworks.com> | 2018-07-21 00:06:38 -0400 |
| commit | 81a2f870dda76dd2fca64fea159ba05e41981d7f (patch) | |
| tree | f6209133d66370d8ebe993fb74e6ec9898370fe9 /zebra/kernel_netlink.c | |
| parent | 7087ced7add0978047fa9df0ad62f47134109a69 (diff) | |
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 <sworley@cumulusnetworks.com>
Diffstat (limited to 'zebra/kernel_netlink.c')
| -rw-r--r-- | zebra/kernel_netlink.c | 115 |
1 files changed, 115 insertions, 0 deletions
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 <zebra.h> +#if defined(HANDLE_ZAPI_FUZZING) +#include <stdio.h> +#include <string.h> +#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); |
