mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 04:36:45 +00:00
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>
This commit is contained in:
parent
7087ced7ad
commit
81a2f870dd
@ -20,6 +20,11 @@
|
|||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
|
||||||
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NETLINK
|
#ifdef HAVE_NETLINK
|
||||||
|
|
||||||
#include "linklist.h"
|
#include "linklist.h"
|
||||||
@ -293,6 +298,97 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
|
|||||||
return 0;
|
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)
|
static int kernel_read(struct thread *thread)
|
||||||
{
|
{
|
||||||
struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(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)
|
if (count && read_in >= count)
|
||||||
return 0;
|
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);
|
status = recvmsg(nl->sock, &msg, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
status = recvmsg(nl->sock, &msg, 0);
|
||||||
|
#endif
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
@ -636,6 +743,14 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
|
|||||||
zlog_hexdump(buf, status);
|
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++;
|
read_in++;
|
||||||
for (h = (struct nlmsghdr *)buf;
|
for (h = (struct nlmsghdr *)buf;
|
||||||
NLMSG_OK(h, (unsigned int)status);
|
NLMSG_OK(h, (unsigned int)status);
|
||||||
|
@ -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_family_to_str(uint8_t family);
|
||||||
extern const char *nl_rttype_to_str(uint8_t rttype);
|
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),
|
extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
|
||||||
struct nlsock *nl, struct zebra_ns *zns,
|
struct nlsock *nl, struct zebra_ns *zns,
|
||||||
int count, int startup);
|
int count, int startup);
|
||||||
|
31
zebra/main.c
31
zebra/main.c
@ -54,6 +54,10 @@
|
|||||||
#include "zebra/zebra_rnh.h"
|
#include "zebra/zebra_rnh.h"
|
||||||
#include "zebra/zebra_pbr.h"
|
#include "zebra/zebra_pbr.h"
|
||||||
|
|
||||||
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
|
#include "zebra/kernel_netlink.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ZEBRA_PTM_SUPPORT
|
#define ZEBRA_PTM_SUPPORT
|
||||||
|
|
||||||
/* Zebra instance */
|
/* Zebra instance */
|
||||||
@ -213,7 +217,8 @@ int main(int argc, char **argv)
|
|||||||
struct sockaddr_storage dummy;
|
struct sockaddr_storage dummy;
|
||||||
socklen_t dummylen;
|
socklen_t dummylen;
|
||||||
#if defined(HANDLE_ZAPI_FUZZING)
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
char *fuzzing = NULL;
|
char *zapi_fuzzing = NULL;
|
||||||
|
char *netlink_fuzzing = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vrf_configure_backend(VRF_BACKEND_VRF_LITE);
|
vrf_configure_backend(VRF_BACKEND_VRF_LITE);
|
||||||
@ -227,7 +232,7 @@ int main(int argc, char **argv)
|
|||||||
"s:n"
|
"s:n"
|
||||||
#endif
|
#endif
|
||||||
#if defined(HANDLE_ZAPI_FUZZING)
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
"c:"
|
"c:w:"
|
||||||
#endif
|
#endif
|
||||||
,
|
,
|
||||||
longopts,
|
longopts,
|
||||||
@ -244,7 +249,8 @@ int main(int argc, char **argv)
|
|||||||
" --v6-rr-semantics Use v6 RR semantics\n"
|
" --v6-rr-semantics Use v6 RR semantics\n"
|
||||||
#endif /* HAVE_NETLINK */
|
#endif /* HAVE_NETLINK */
|
||||||
#if defined(HANDLE_ZAPI_FUZZING)
|
#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
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -306,7 +312,16 @@ int main(int argc, char **argv)
|
|||||||
#endif /* HAVE_NETLINK */
|
#endif /* HAVE_NETLINK */
|
||||||
#if defined(HANDLE_ZAPI_FUZZING)
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
case 'c':
|
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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -349,6 +364,7 @@ int main(int argc, char **argv)
|
|||||||
/* For debug purpose. */
|
/* For debug purpose. */
|
||||||
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
||||||
|
|
||||||
|
|
||||||
/* Process the configuration file. Among other configuration
|
/* Process the configuration file. Among other configuration
|
||||||
* directives we can meet those installing static routes. Such
|
* directives we can meet those installing static routes. Such
|
||||||
* requests will not be executed immediately, but queued in
|
* requests will not be executed immediately, but queued in
|
||||||
@ -385,8 +401,11 @@ int main(int argc, char **argv)
|
|||||||
zebra_rnh_init();
|
zebra_rnh_init();
|
||||||
|
|
||||||
#if defined(HANDLE_ZAPI_FUZZING)
|
#if defined(HANDLE_ZAPI_FUZZING)
|
||||||
if (fuzzing) {
|
if (zapi_fuzzing) {
|
||||||
zserv_read_file(fuzzing);
|
zserv_read_file(zapi_fuzzing);
|
||||||
|
exit(0);
|
||||||
|
} else if (netlink_fuzzing) {
|
||||||
|
netlink_read_init(netlink_fuzzing);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user