Merge pull request #2696 from sworleys/Netlink-Fuzz

zebra: Add code for fuzzing netlink
This commit is contained in:
Russ White 2018-07-29 08:33:43 -04:00 committed by GitHub
commit 155d6d4415
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 10 deletions

View File

@ -436,6 +436,8 @@ AC_ARG_ENABLE(datacenter,
AS_HELP_STRING([--enable-datacenter], [enable Compilation for Data Center Extensions]))
AC_ARG_ENABLE(fuzzing,
AS_HELP_STRING([--enable-fuzzing], [enable ability to fuzz various parts of FRR]))
AC_ARG_ENABLE(netlink_fuzzing,
AS_HELP_STRING([--enable-netlink-fuzzing], [enable ability to fuzz netlink listening socket in zebra]))
AC_ARG_ENABLE(rr-semantics,
AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics]))
AC_ARG_ENABLE([protobuf],
@ -501,6 +503,10 @@ if test "${enable_fuzzing}" = "yes" ; then
AC_DEFINE(HANDLE_ZAPI_FUZZING,,Compile extensions to use with a fuzzer)
fi
if test "${enable_netlink_fuzzing}" = "yes" ; then
AC_DEFINE(HANDLE_NETLINK_FUZZING,,Compile extensions to use with a fuzzer for netlink)
fi
if test "${enable_cumulus}" = "yes" ; then
AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in)
fi

View File

@ -20,6 +20,11 @@
#include <zebra.h>
#if defined(HANDLE_NETLINK_FUZZING)
#include <stdio.h>
#include <string.h>
#endif /* HANDLE_NETLINK_FUZZING */
#ifdef HAVE_NETLINK
#include "linklist.h"
@ -293,6 +298,81 @@ static int 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;
/* File name to read fuzzed netlink from */
static char netlink_fuzz_file[MAXPATHLEN] = "";
/* Flag for whether to read from file or not */
bool netlink_read;
/**
* 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 = zebra_ns_lookup(NS_DEFAULT);
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, NL_RCV_PKT_BUF_SIZE, 1, f);
fclose(f);
}
zserv_privs.change(ZPRIVS_LOWER);
return file_bytes;
}
#endif /* HANDLE_NETLINK_FUZZING */
static int kernel_read(struct thread *thread)
{
struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread);
@ -602,7 +682,18 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
if (count && read_in >= count)
return 0;
#if defined(HANDLE_NETLINK_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 /* HANDLE_NETLINK_FUZZING */
if (status < 0) {
if (errno == EINTR)
continue;
@ -636,6 +727,14 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
zlog_hexdump(buf, status);
}
#if defined(HANDLE_NETLINK_FUZZING)
if (!netlink_read) {
zlog_debug("Writing incoming netlink message");
netlink_write_incoming(buf, status,
netlink_file_counter++);
}
#endif /* HANDLE_NETLINK_FUZZING */
read_in++;
for (h = (struct nlmsghdr *)buf;
(status >= 0 && NLMSG_OK(h, (unsigned int)status));

View 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_NETLINK_FUZZING)
extern bool netlink_read;
extern void netlink_read_init(const char *fname);
#endif /* HANDLE_NETLINK_FUZZING */
extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
struct nlsock *nl, struct zebra_ns *zns,
int count, int startup);

View File

@ -54,6 +54,10 @@
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_pbr.h"
#if defined(HANDLE_NETLINK_FUZZING)
#include "zebra/kernel_netlink.h"
#endif /* HANDLE_NETLINK_FUZZING */
#define ZEBRA_PTM_SUPPORT
/* Zebra instance */
@ -213,8 +217,11 @@ int main(int argc, char **argv)
struct sockaddr_storage dummy;
socklen_t dummylen;
#if defined(HANDLE_ZAPI_FUZZING)
char *fuzzing = NULL;
#endif
char *zapi_fuzzing = NULL;
#endif /* HANDLE_ZAPI_FUZZING */
#if defined(HANDLE_NETLINK_FUZZING)
char *netlink_fuzzing = NULL;
#endif /* HANDLE_NETLINK_FUZZING */
vrf_configure_backend(VRF_BACKEND_VRF_LITE);
logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS);
@ -228,7 +235,10 @@ int main(int argc, char **argv)
#endif
#if defined(HANDLE_ZAPI_FUZZING)
"c:"
#endif
#endif /* HANDLE_ZAPI_FUZZING */
#if defined(HANDLE_NETLINK_FUZZING)
"w:"
#endif /* HANDLE_NETLINK_FUZZING */
,
longopts,
" -b, --batch Runs in batch mode\n"
@ -244,8 +254,11 @@ 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"
#endif
" -c <file> Bypass normal startup and use this file for testing of zapi\n"
#endif /* HANDLE_ZAPI_FUZZING */
#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) {
@ -306,9 +319,19 @@ int main(int argc, char **argv)
#endif /* HAVE_NETLINK */
#if defined(HANDLE_ZAPI_FUZZING)
case 'c':
fuzzing = optarg;
zapi_fuzzing = optarg;
break;
#endif
#endif /* HANDLE_ZAPI_FUZZING */
#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);
break;
@ -385,11 +408,17 @@ 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);
}
#endif
#endif /* HANDLE_ZAPI_FUZZING */
#if defined(HANDLE_NETLINK_FUZZING)
if (netlink_fuzzing) {
netlink_read_init(netlink_fuzzing);
exit(0);
}
#endif /* HANDLE_NETLINK_FUZZING */
frr_run(zebrad.master);