]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: refactor netlink fuzzing
authorJakub Urbańczyk <xthaid@gmail.com>
Fri, 21 Aug 2020 16:24:40 +0000 (18:24 +0200)
committerQuentin Young <qlyoung@nvidia.com>
Mon, 15 Nov 2021 22:12:33 +0000 (17:12 -0500)
Signed-off-by: Jakub Urbańczyk <xthaid@gmail.com>
lib/zebra.h
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/main.c

index 332a8bd75804ace39862a2a808ac921b8a45657a..5213e1ca7e90b4e4f3286df612197ba2895135d9 100644 (file)
 
 #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 */
index 8b58f90406c5a1031b9bd66952efdbb21e160329..cdb6abfe3e9fc19652ff96bc16c90ae0907680e0 100644 (file)
 
 #include <zebra.h>
 
+#if defined(HANDLE_NETLINK_FUZZING)
+#include <stdio.h>
+#include <string.h>
+#include "libfrr.h"
+#endif /* HANDLE_NETLINK_FUZZING */
+
 #ifdef HAVE_NETLINK
 
 #include "linklist.h"
  */
 #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 */
index cf8b8c785e630ae17cd2198e07506775ecbc2255..5592ffa0eb4851691f3ab164d65be0ad325ab5c7 100644 (file)
@@ -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
index e9192aa6b1eaffa4df2edf213eaedb2fc2c13623..9d4bfc903e7c3bb957c9dc1e49fd598d8c0c0ff3 100644 (file)
 #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 <file>                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... */