#include <zebra.h>
+#if defined(HANDLE_ZAPI_FUZZING)
+#include <stdio.h>
+#include <string.h>
+#endif
+
#ifdef HAVE_NETLINK
#include "linklist.h"
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);
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;
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);
#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 */
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);
"s:n"
#endif
#if defined(HANDLE_ZAPI_FUZZING)
- "c:"
+ "c:w:"
#endif
,
longopts,
" --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
);
#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:
/* 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
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