]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Add code for fuzzing netlink
authorStephen Worley <sworley@cumulusnetworks.com>
Thu, 19 Jul 2018 19:21:29 +0000 (15:21 -0400)
committerStephen Worley <sworley@cumulusnetworks.com>
Sat, 21 Jul 2018 04:06:38 +0000 (00:06 -0400)
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>
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/main.c

index 8703b013191f8a94edf3355a8bcaf1d300df274a..4aed99506031d56131188013bffc4575cdbef8d5 100644 (file)
 
 #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);
index 80bb876e0bc328736d5a40bf6c0c6ecdace70a81..78bfdfa178a7dac5d495c39f0508aa03cb11f2ab 100644 (file)
@@ -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);
index 3e44a4170759cf0a4e5e8a6938ae97c589c9336a..01466d3fb0e60983309b4db60104f3bd9ed65059 100644 (file)
 #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 <file>             Bypass normal startup and use this file for testing of zapi"
+               "  -c <file>             Bypass normal startup and use this file for testing of zapi\n"
+               "  -w <file>             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