summaryrefslogtreecommitdiff
path: root/zebra/kernel_netlink.c
diff options
context:
space:
mode:
authorStephen Worley <sworley@cumulusnetworks.com>2018-07-19 15:21:29 -0400
committerStephen Worley <sworley@cumulusnetworks.com>2018-07-21 00:06:38 -0400
commit81a2f870dda76dd2fca64fea159ba05e41981d7f (patch)
treef6209133d66370d8ebe993fb74e6ec9898370fe9 /zebra/kernel_netlink.c
parent7087ced7add0978047fa9df0ad62f47134109a69 (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.c115
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);