#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"},
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);
#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;
}
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;
/*
/* 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
}
}
}
+
+#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 */
#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. */
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);
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();
#ifdef HAVE_NETLINK
"s:n"
#endif
-#if defined(HANDLE_NETLINK_FUZZING)
- "w:"
-#endif /* HANDLE_NETLINK_FUZZING */
,
longopts,
" -b, --batch Runs in batch mode\n"
" -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) {
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);
}
/* 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... */