From: Jakub Urbańczyk Date: Fri, 21 Aug 2020 16:24:40 +0000 (+0200) Subject: zebra: refactor netlink fuzzing X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=4cfdbe2940ca50da47ab6c92914fceb07ea601c5;p=mirror%2Ffrr.git zebra: refactor netlink fuzzing Signed-off-by: Jakub Urbańczyk --- diff --git a/lib/zebra.h b/lib/zebra.h index 332a8bd758..5213e1ca7e 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -23,6 +23,11 @@ #define FUZZING 1 +#define ZAPI_FUZZING 1 +#define NETLINK_FUZZING 2 + +#define FUZZING_MODE NETLINK_FUZZING + #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8b58f90406..cdb6abfe3e 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -20,6 +20,12 @@ #include +#if defined(HANDLE_NETLINK_FUZZING) +#include +#include +#include "libfrr.h" +#endif /* HANDLE_NETLINK_FUZZING */ + #ifdef HAVE_NETLINK #include "linklist.h" @@ -89,7 +95,14 @@ */ #define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE) -#define NL_BATCH_RX_BUFSIZE NL_RCV_PKT_BUF_SIZE +/* + * For every request sent to the kernel that has failed we get an error message, + * which contains a standard netlink message header and the payload consisting + * of an error code and the original netlink mesage. So the receiving buffer + * must be at least as big as the transmitting buffer increased by some space + * for headers. + */ +#define NL_BATCH_RX_BUFSIZE (NL_DEFAULT_BATCH_BUFSIZE + NL_PKT_BUF_SIZE) static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_DELROUTE, "RTM_DELROUTE"}, @@ -410,6 +423,36 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } +#if defined(HANDLE_NETLINK_FUZZING) +/* Using globals here to avoid adding function parameters */ + +/* Keep distinct filenames for netlink fuzzy collection */ +static unsigned int netlink_file_counter = 1; + +/** + * 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; + + snprintf(fname, MAXPATHLEN, "%s/%s_%u", frr_vtydir, "netlink", counter); + frr_with_privs(&zserv_privs) { + f = fopen(fname, "w"); + } + if (f) { + fwrite(buf, 1, size, f); + fclose(f); + } +} + +#endif /* HANDLE_NETLINK_FUZZING */ + static int kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); @@ -832,6 +875,11 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, #endif /* NETLINK_DEBUG */ } +#if defined(HANDLE_NETLINK_FUZZING) + zlog_debug("Writing incoming netlink message"); + netlink_write_incoming(buf, status, netlink_file_counter++); +#endif /* HANDLE_NETLINK_FUZZING */ + return status; } @@ -1121,17 +1169,14 @@ static int nl_batch_read_resp(struct nl_batch *bth) msg.msg_name = (void *)&snl; msg.msg_namelen = sizeof(snl); - /* - * The responses are not batched, so we need to read and process one - * message at a time. - */ - while (true) { - status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, - sizeof(nl_batch_rx_buf)); - if (status == -1 || status == 0) - return status; + status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, + sizeof(nl_batch_rx_buf)); + if (status == -1 || status == 0) + return status; - h = (struct nlmsghdr *)nl_batch_rx_buf; + for (h = (struct nlmsghdr *)nl_batch_rx_buf; + (status >= 0 && NLMSG_OK(h, (unsigned int)status)); + h = NLMSG_NEXT(h, status)) { ignore_msg = false; seq = h->nlmsg_seq; /* @@ -1591,9 +1636,11 @@ void kernel_init(struct zebra_ns *zns) /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) { netlink_recvbuf(&zns->netlink, nl_rcvbufsize); +#ifndef FUZZING netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize); +#endif } /* Set filter for inbound sockets, to exclude events we've generated @@ -1644,4 +1691,18 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) } } } + +#ifdef FUZZING +void netlink_fuzz(const uint8_t *data, size_t size) +{ + struct nlmsghdr *h = (struct nlmsghdr *)data; + + if (!NLMSG_OK(h, size)) + return; + + netlink_information_fetch(h, NS_DEFAULT, 0); +} +#endif /* FUZZING */ + + #endif /* HAVE_NETLINK */ diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index cf8b8c785e..5592ffa0eb 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -146,6 +146,10 @@ extern int netlink_config_write_helper(struct vty *vty); extern void netlink_set_batch_buffer_size(uint32_t size, uint32_t threshold, bool set); +#ifdef FUZZING +void netlink_fuzz(const uint8_t *data, size_t size); +#endif + #endif /* HAVE_NETLINK */ #ifdef __cplusplus diff --git a/zebra/main.c b/zebra/main.c index e9192aa6b1..9d4bfc903e 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -63,6 +63,10 @@ #include "zebra/zebra_srv6_vty.h" #include "zebra/zapi_msg.h" +#ifdef FUZZING +#include "zebra/kernel_netlink.h" +#endif /* FUZZING */ + #define ZEBRA_PTM_SUPPORT /* process id. */ @@ -352,11 +356,16 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) zc = FuzzingZc; #endif /* FUZZING_LIBFUZZER */ + +#if (FUZZING_MODE == ZAPI_FUZZING) struct stream *s = stream_new(size + 1); stream_put(s, data, size); stream_fifo_push(fifo, s); zserv_handle_commands(zc, fifo); +#elif (FUZZING_MODE == NETLINK_FUZZING) + netlink_fuzz(data, size); +#endif done: zserv_close_client(zc); @@ -377,9 +386,6 @@ int main(int argc, char **argv) char *vrf_default_name_configured = NULL; struct sockaddr_storage dummy; socklen_t dummylen; -#if defined(HANDLE_NETLINK_FUZZING) - char *netlink_fuzzing = NULL; -#endif /* HANDLE_NETLINK_FUZZING */ #ifdef FUZZING FuzzingInit(); @@ -412,9 +418,6 @@ int main(int argc, char **argv) #ifdef HAVE_NETLINK "s:n" #endif -#if defined(HANDLE_NETLINK_FUZZING) - "w:" -#endif /* HANDLE_NETLINK_FUZZING */ , longopts, " -b, --batch Runs in batch mode\n" @@ -430,9 +433,6 @@ int main(int argc, char **argv) " -s, --nl-bufsize Set netlink receive buffer size\n" " --v6-rr-semantics Use v6 RR semantics\n" #endif /* HAVE_NETLINK */ -#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) { @@ -501,16 +501,6 @@ int main(int argc, char **argv) asic_offload = true; break; #endif /* HAVE_NETLINK */ -#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. - */ - netlink_read = true; - break; -#endif /* HANDLE_NETLINK_FUZZING */ default: frr_help_exit(1); } @@ -598,14 +588,6 @@ int main(int argc, char **argv) /* Error init */ zebra_error_init(); -#if defined(HANDLE_NETLINK_FUZZING) - if (netlink_fuzzing) { - netlink_read_init(netlink_fuzzing); - exit(0); - } -#endif /* HANDLE_NETLINK_FUZZING */ - - frr_run(zrouter.master); /* Not reached... */