This change introduces support for fuzzing daemons.
There are two types of changes included here:
* Code that implements shims, harnesses, entry points and other required
constructs to enable AFL and libFuzzer to attach to and run the target
daemons
* Code that tweaks daemon behavior to allow fuzzers to find more bugs,
cover more code, and work around certain fuzzer constraints; these are
things like disabling packet checksums, disabling the event loop,
removing i/o calls, etc.
Both types are usually wrapped by #ifdef FUZZER blocks just to mark them
for readers of the code.
Support for both AFL and libFuzzer is included.
Signed-off-by: Quentin Young <qlyoung@qlyoung.net>
Signed-off-by: Iggy Frankovic <iggyfran@amazon.com>
* From RFC1771 [A Border Gateway Protocol 4 (BGP-4)]
* Copyright (C) 1996, 97, 98 Kunihiro Ishiguro
*/
+#define FUZZING 1
#include <zebra.h>
structure. */
void bgp_timer_set(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
afi_t afi;
safi_t safi;
static uint16_t bgp_read(struct peer *peer, int *code_p);
static void bgp_process_writes(struct event *event);
static void bgp_process_reads(struct event *event);
-static bool validate_header(struct peer *);
+bool validate_header(struct peer *);
/* generic i/o status codes */
#define BGP_IO_TRANS_ERR (1 << 0) /* EAGAIN or similar occurred */
void bgp_writes_on(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
void bgp_writes_off(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
void bgp_reads_on(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
void bgp_reads_off(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
* Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input
* buffer.
*/
-static bool validate_header(struct peer *peer)
+bool validate_header(struct peer *peer)
{
uint16_t size;
uint8_t type;
#include "bgpd/bgpd.h"
#include "frr_pthread.h"
+bool validate_header(struct peer *p);
+
/**
* Start function for write thread.
*
void bgp_keepalives_on(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
return;
void bgp_keepalives_off(struct peer *peer)
{
+#ifdef FUZZING
+ return;
+#endif
if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
return;
#include "ns.h"
#include "bgpd/bgpd.h"
+#include "bgp_io.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_mplsvpn.h"
#define DEPRECATED_OPTIONS ""
+#ifdef FUZZING
+#include "lib/ringbuf.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static bool FuzzingInit(void) {
+ int bgp_port = BGP_PORT_DEFAULT;
+ struct list *addresses = list_new();
+ int no_fib_flag = 0;
+ int no_zebra_flag = 0;
+ int skip_runas = 0;
+ int instance = 0;
+ int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
+ struct listnode *node;
+
+ addresses->cmp = (int (*)(void *, void *))strcmp;
+
+ const char *name[] = { "bgpd" };
+
+ frr_preinit(&bgpd_di, 1, (char **) name);
+
+ /* Initialize basic BGP datastructures */
+ bgp_master_init(frr_init_fast(), buffer_size, addresses);
+ bm->port = bgp_port;
+ bgp_option_set(BGP_OPT_NO_LISTEN);
+
+ bgp_option_set(BGP_OPT_NO_FIB);
+ bgp_option_set(BGP_OPT_NO_ZEBRA);
+ bgp_error_init();
+ // bgp_vrf_init();
+ bgp_init((unsigned short)instance);
+
+
+ /* Create a default instance and peer */
+ struct bgp *b;
+ as_t as = 65001;
+ bgp_get(&b, &as, "default", BGP_INSTANCE_TYPE_DEFAULT, NULL,
+ ASNOTATION_UNDEFINED);
+
+ return true;
+}
+
+/*
+ * Create peer structure that we'll use as the receiver for fuzzed packets.
+ *
+ * state
+ * BGP FSM state to create the peer in
+ */
+static struct peer *FuzzingCreatePeer(int state)
+{
+ union sockunion su;
+ sockunion_init(&su);
+ inet_pton(AF_INET, "10.1.1.1", &su.sin.sin_addr);
+ su.sin.sin_family = AF_INET;
+ su.sin.sin_port = 2001;
+ struct peer *p = peer_create(&su, NULL, bgp_get_default(), 65000, 65001,
+ AS_UNSPECIFIED, NULL, 1, NULL);
+ p->bgp->rpkt_quanta = 1;
+ p->status = state;
+ p->as_type = AS_EXTERNAL;
+
+ /* set all flags */
+ afi_t afi;
+ safi_t safi;
+ p->cap |= 0xFFFF;
+ FOREACH_AFI_SAFI(afi, safi) {
+ SET_FLAG(p->af_cap[afi][safi], 0x3FFF);
+ }
+
+ peer_activate(p, AFI_L2VPN, SAFI_EVPN);
+ peer_activate(p, AFI_IP, SAFI_MPLS_VPN);
+
+ return p;
+}
+
+static struct peer *FuzzingPeer;
+
+static bool FuzzingInitialized;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (!FuzzingInitialized) {
+ FuzzingInit();
+ FuzzingInitialized = true;
+ /* See comment below */
+ FuzzingPeer = FuzzingCreatePeer(Established);
+ }
+ //make_route_maps();
+ /*
+ * In the AFL standalone case, the peer will already be created for us
+ * before __AFL_INIT() is called to speed things up. We can't pass it
+ * as an argument because the function signature must match libFuzzer's
+ * expectations, so it's saved in a global variable. Even though we'll
+ * be exiting the program after each run, we still destroy the peer
+ * because that increases our coverage and is likely to find memory
+ * leaks when pointers are nulled that would otherwise be "in-use at
+ * exit".
+ *
+ * In the libFuzzer case, we can either create and destroy it each time
+ * to fuzz single packet rx, or we can keep the peer around, which will
+ * fuzz a long lived session. Of course, as state accumulates over
+ * time, memory usage will grow, which imposes some resource
+ * constraints on the fuzzing host. In practice a reasonable server
+ * machine with 64gb of memory or so should be able to fuzz
+ * indefinitely; if bgpd consumes this much memory over time, that
+ * behavior should probably be considered a bug.
+ */
+ struct peer *p;
+#ifdef FUZZING_LIBFUZZER
+ /* For non-persistent mode */
+ // p = FuzzingCreatePeer();
+ /* For persistent mode */
+ p = FuzzingPeer;
+#else
+ p = FuzzingPeer;
+#endif /* FUZZING_LIBFUZZER */
+
+ ringbuf_reset(p->ibuf_work);
+ ringbuf_put(p->ibuf_work, data, size);
+
+ int result = 0;
+ unsigned char pktbuf[BGP_MAX_PACKET_SIZE];
+ uint16_t pktsize = 0;
+
+ /*
+ * Simulate the read process done by bgp_process_reads().
+ *
+ * The actual packet processing code assumes that the size field in the
+ * BGP message is correct, and this check is performed by the i/o code,
+ * so we need to make sure that remains true for fuzzed input.
+ *
+ * Also, validate_header() assumes that there is at least
+ * BGP_HEADER_SIZE bytes in ibuf_work.
+ */
+ if ((size < BGP_HEADER_SIZE) || !validate_header(p)) {
+ goto done;
+ }
+
+ ringbuf_peek(p->ibuf_work, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
+ pktsize = ntohs(pktsize);
+
+ assert(pktsize <= p->max_packet_size);
+
+ if (ringbuf_remain(p->ibuf_work) >= pktsize) {
+ struct stream *pkt = stream_new(pktsize);
+ ringbuf_get(p->ibuf_work, pktbuf, pktsize);
+ stream_put(pkt, pktbuf, pktsize);
+ p->curr = pkt;
+
+ struct event t = {};
+ t.arg = p;
+ bgp_process_packet(&t);
+ }
+
+done:
+ //peer_delete(p);
+
+ return 0;
+};
+#endif /* FUZZING */
+
+#ifndef FUZZING_LIBFUZZER
/* Main routine of bgpd. Treatment of argument and start bgp finite
state machine is handled at here. */
int main(int argc, char **argv)
int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
char *address;
struct listnode *node;
+ //char *bgp_address = NULL;
- addresses->cmp = (int (*)(void *, void *))strcmp;
+ //addresses->cmp = (int (*)(void *, void *))strcmp;
frr_preinit(&bgpd_di, argc, argv);
+
+#ifdef FUZZING
+ FuzzingInit();
+ FuzzingPeer = FuzzingCreatePeer(Established);
+ FuzzingInitialized = true;
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif /* __AFL_HAVE_MANUAL_CONTROL */
+ uint8_t *input;
+ int r = frrfuzz_read_input(&input);
+
+ if (!input)
+ return 0;
+
+ return LLVMFuzzerTestOneInput(input, r);
+#endif /* FUZZING */
+
frr_opt_add(
"p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts,
" -p, --bgp_port Set BGP listen port number (0 means do not listen).\n"
/* Not reached. */
return 0;
}
+#endif /* FUZZING_LIBFUZZER */
\ No newline at end of file
* Copyright (C) 2017 Cumulus Networks
* Copyright (C) 1999 Kunihiro Ishiguro
*/
+#define FUZZING 1
#include <zebra.h>
#include <sys/time.h>
* @param peer
* @return 0
*/
+#ifndef FUZZING
static void bgp_write_notify(struct peer *peer)
{
int ret, val;
stream_free(s);
}
+#endif
/*
* Encapsulate an original BGP CEASE Notification into Hard Reset
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
peer->bgp->peer);
+#ifndef FUZZING
bgp_write_notify(peer);
+#endif
}
/*
return BGP_Stop;
/* Get sockname. */
+#ifndef FUZZING
if (bgp_getsockname(peer) < 0) {
flog_err_sys(EC_LIB_SOCKET,
"%s: bgp_getsockname() failed for peer: %s",
__func__, peer->host);
return BGP_Stop;
}
+#endif
/* Set remote router-id */
peer->remote_id = remote_id;
#endif
}
}
+#ifndef FUZZING
peer->rtt = sockopt_tcp_rtt(peer->fd);
+#endif
return Receive_OPEN_message;
}
bgp_size_t size;
char notify_data_length[2];
+#ifndef FUZZING
frr_with_mutex (&peer->io_mtx) {
peer->curr = stream_fifo_pop(peer->ibuf);
}
-
+#endif
if (peer->curr == NULL) // no packets to process, hmm...
return;
/* delete processed packet */
stream_free(peer->curr);
peer->curr = NULL;
+#ifdef FUZZING
+ return;
+#endif
processed++;
/* Update FSM */
ringbuf_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE/2);
/* Get service port number. */
+#ifndef FUZZING
sp = getservbyname("bgp", "tcp");
+#else
+ sp = NULL;
+#endif
peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs(sp->s_port);
QOBJ_REG(peer, peer);
/* allocates some vital data structures used by peer commands in
* vty_init */
-
+#ifndef FUZZING
/* pre-init pthreads */
bgp_pthreads_init();
/* Init zebra. */
bgp_zebra_init(bm->master, instance);
-
+#endif
#ifdef ENABLE_BGP_VNC
vnc_zebra_init(bm->master);
#endif
/* BGP VTY commands installation. */
+#ifndef FUZZING
bgp_vty_init();
+#endif
/* BGP inits. */
bgp_attr_init();
- bgp_debug_init();
bgp_community_alias_init();
+#ifndef FUZZING
+ bgp_debug_init();
bgp_dump_init();
+#endif
bgp_route_init();
bgp_route_map_init();
+#ifndef FUZZING
bgp_scan_vty_init();
+#endif
bgp_mplsvpn_init();
+#ifndef FUZZING
#ifdef ENABLE_BGP_VNC
rfapi_init();
#endif
bgp_ethernetvpn_init();
bgp_flowspec_vty_init();
-
+#endif
/* Access list initialize. */
access_list_init();
access_list_add_hook(peer_distribute_update);
/* Community list initialize. */
bgp_clist = community_list_init();
+ bgp_label_per_nexthop_init();
+
+#ifndef FUZZING
/* BFD init */
bgp_bfd_init(bm->master);
-
bgp_lp_vty_init();
-
- bgp_label_per_nexthop_init();
-
cmd_variable_handler_register(bgp_viewvrf_var_handlers);
+#endif
}
void bgp_terminate(void)
bgpd_bgpd_SOURCES = bgpd/bgp_main.c
bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c
+bgpd_bgpd_LDFLAGS = $(AM_LDFLAGS) $(BGPD_SAN_FLAGS)
+bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS)
+bgpd_bgp_btoa_LDLAGS = $(AM_LDLAGS)
+
# RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am
bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBYANG_LIBS) $(LIBCAP) $(LIBM) $(UST_LIBS)
bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBYANG_LIBS) $(LIBCAP) $(LIBM) $(UST_LIBS)
])
AC_C_FLAG([-fno-omit-frame-pointer])
AC_C_FLAG([-funwind-tables])
-AC_C_FLAG([-Wall])
+#AC_C_FLAG([-Wall])
AC_C_FLAG([-Wextra])
AC_C_FLAG([-Wformat-nonliteral])
AC_C_FLAG([-Wformat-security])
SAN_FLAGS="$SAN_FLAGS -fsanitize=undefined"
])
fi
+if test "$enable_libfuzzer" = "yes"; then
+ AC_C_FLAG([-fsanitize=address,fuzzer], [
+ AC_MSG_ERROR([$CC does not support ASAN / libFuzzer.])
+ ], [
+ AC_MSG_NOTICE([WARNING - libFuzzer only enabled on supported daemons])
+ SAN_FLAGS="$SAN_FLAGS -fsanitize=fuzzer-no-link"
+ BGPD_SAN_FLAGS="-fsanitize=fuzzer"
+ ZEBRA_SAN_FLAGS="-fsanitize=fuzzer"
+ OSPFD_SAN_FLAGS="-fsanitize=fuzzer"
+ VRRPD_SAN_FLAGS="-fsanitize=fuzzer"
+ PIMD_SAN_FLAGS="-fsanitize=fuzzer"
+ AC_DEFINE([FUZZING_LIBFUZZER], [1], [Compiling and linking with libFuzzer])
+ ])
+fi
AC_SUBST([SAN_FLAGS])
+AC_SUBST([BGPD_SAN_FLAGS])
+AC_SUBST([ZEBRA_SAN_FLAGS])
+AC_SUBST([OSPFD_SAN_FLAGS])
+AC_SUBST([VRRPD_SAN_FLAGS])
+AC_SUBST([PIMD_SAN_FLAGS])
dnl frr-format.so
if test "$with_frr_format" != "no" -a "$with_frr_format" != "yes" -a -n "$with_frr_format"; then
AS_HELP_STRING([--enable-memory-sanitizer], [enable MemorySanitizer support for detecting uninitialized memory reads]))
AC_ARG_ENABLE([undefined-sanitizer],
AS_HELP_STRING([--enable-undefined-sanitizer], [enable UndefinedBehaviorSanitizer support for detecting undefined behavior]))
+AC_ARG_ENABLE([libfuzzer],
+ AS_HELP_STRING([--libfuzzer], [enable libFuzzer]))
AC_ARG_WITH([crypto],
AS_HELP_STRING([--with-crypto=<internal|openssl>], [choose between different implementations of cryptographic functions(default value is --with-crypto=internal)]))
AC_ARG_WITH([frr-format],
{
const struct iovec *iov_end;
uint32_t sum = 0;
+ register unsigned short answer; /* assumes unsigned short == 16 bits */
union {
uint8_t bytes[2];
sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
sum += (sum >> 16); /* add carry */
- return ~sum;
+ /* ones-complement, then truncate to 16 bits */
+ answer = (unsigned short)~sum;
+ return (answer);
}
/* Fletcher Checksum -- Refer to RFC1008. */
without modifying the buffer; a valid checksum returns 0 */
uint16_t fletcher_checksum(uint8_t *buffer, const size_t len,
const uint16_t offset)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
uint8_t *p;
int x, y, c0, c1;
* Copyright (C) 2013 by Open Source Routing.
* Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
*/
+#define FUZZING 1
#include <zebra.h>
#include <lib/version.h>
/* Install a command into a node. */
void _install_element(enum node_type ntype, const struct cmd_element *cmd)
{
+#ifdef FUZZING
+ return;
+#endif
struct cmd_node *cnode;
/* cmd_init hasn't been called */
_event_add_##addfn(&_xref, m, f, a, v, t); \
}) /* end */
+#ifndef FUZZING
+
#define event_add_read(m, f, a, v, t) _xref_t_a(read_write, READ, m, f, a, v, t)
#define event_add_write(m, f, a, v, t) \
_xref_t_a(read_write, WRITE, m, f, a, v, t)
XREF_LINK(_xref.xref); \
_event_execute(&_xref, m, f, a, v); \
}) /* end */
+#else
+
+#define event_add_read(m, f, a, v, t) 0
+#define event_add_write(m, f, a, v, t) 0
+#define event_add_timer(m, f, a, v, t) 0
+#define event_add_timer_msec(m, f, a, v, t) 0
+#define event_add_timer_tv(m, f, a, v, t) 0
+#define event_add_event(m, f, a, v, t) 0
+#define event_execute(m, f, a, v) 0
+#define event_execute_name(m, f, a, v, n) 0
+
+#endif
/* Prototypes. */
extern struct event_loop *event_master_create(const char *name);
--- /dev/null
+/*
+* Utilities for fuzzing frr.
+*/
+#ifndef __FUZZ_H__
+#define __FUZZ_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+static inline int frrfuzz_read_input(uint8_t **input)
+{
+ fseek(stdin, 0, SEEK_END);
+ long fsize = ftell(stdin);
+ if (fsize < 0)
+ return 0;
+
+ *input = (uint8_t *)malloc(fsize);
+
+ fseek(stdin, 0, SEEK_SET);
+ int r = fread(*input, 1, fsize, stdin);
+
+ return r;
+}
+
+#endif /* __FUZZ_H__ */
\ No newline at end of file
}
void graph_delete_graph(struct graph *graph)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
for (unsigned int i = vector_active(graph->nodes); i--; /**/)
graph_delete_node(graph, vector_slot(graph->nodes, i));
}
void graph_delete_node(struct graph *graph, struct graph_node *node)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
if (!node)
return;
}
void graph_remove_edge(struct graph_node *from, struct graph_node *to)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
// remove from from to->from
for (unsigned int i = vector_active(to->from); i--; /**/)
}
struct graph_node *graph_find_node(struct graph *graph, void *data)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
struct graph_node *g;
}
bool graph_has_edge(struct graph_node *from, struct graph_node *to)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
for (unsigned int i = vector_active(from->to); i--; /**/)
if (vector_slot(from->to, i) == to)
static void _graph_dfs(struct graph *graph, struct graph_node *start,
vector visited,
void (*dfs_cb)(struct graph_node *, void *), void *arg)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
/* check that we have not visited this node */
for (unsigned int i = 0; i < vector_active(visited); i++) {
(*ifp_master.down_hook)(ifp);
}
-static struct interface *if_create_name(const char *name, struct vrf *vrf)
+#ifndef FUZZING
+static
+#endif
+struct interface *if_create_name(const char *name, struct vrf *vrf)
{
struct interface *ifp;
extern const struct frr_yang_module_info frr_interface_info;
+#ifdef FUZZING
+struct interface *if_create_name(const char *name, struct vrf *vrf);
+#endif
+
#ifdef __cplusplus
}
#endif
* the input key.
*/
uint32_t jhash(const void *key, uint32_t length, uint32_t initval)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
uint32_t a, b, c, len;
const uint8_t *k = key;
* The length parameter here is the number of uint32_ts in the key.
*/
uint32_t jhash2(const uint32_t *k, uint32_t length, uint32_t initval)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
uint32_t a, b, c, len;
* done at the end is not done here.
*/
uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
#include "frrscript.h"
#include "systemd.h"
+#if defined(FUZZING) && defined(FUZZING_LIBFUZZER) && !defined(FUZZING_OVERRIDE_LLVMFuzzerTestOneInput)
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ return 0;
+}
+#endif /* lol */
+
DEFINE_HOOK(frr_early_init, (struct event_loop * tm), (tm));
DEFINE_HOOK(frr_late_init, (struct event_loop * tm), (tm));
DEFINE_HOOK(frr_config_pre, (struct event_loop * tm), (tm));
return master;
}
+#ifdef FUZZING
+static struct event_loop *master;
+struct event_loop *frr_init_fast(void)
+{
+ struct log_arg *log_arg;
+#if 0
+ struct option_chain *oc;
+ struct frrmod_runtime *module;
+ char moderr[256];
+ const char *dir;
+ dir = di->module_path ? di->module_path : frr_moduledir;
+#endif
+#if 0
+#ifdef HAVE_SQLITE3
+ snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s%s%s.db",
+ frr_dbdir, p_pathspace, di->name, p_instance);
+#endif
+#endif
+ struct zprivs_ids_t ids;
+
+ zprivs_preinit(di->privs);
+ zprivs_get_ids(&ids);
+
+ zlog_init(di->progname, di->logname, di->instance,
+ ids.uid_normal, ids.gid_normal);
+ zlog_tls_buffer_init();
+
+ while ((log_arg = log_args_pop(di->early_logging))) {
+ command_setup_early_logging(log_arg->target,
+ di->early_loglevel);
+ /* this is a bit of a hack,
+ but need to notice when
+ the target is stdout */
+ if (strcmp(log_arg->target, "stdout") == 0)
+ logging_to_stdout = true;
+ XFREE(MTYPE_TMP, log_arg);
+ }
+
+#if 0
+ if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
+ frr_zclientpath)) {
+ fprintf(stderr, "Invalid zserv socket path: %s\n",
+ frr_zclientpath);
+ exit(1);
+ }
+
+ /* don't mkdir these as root... */
+ if (!(di->flags & FRR_NO_PRIVSEP)) {
+ if (!di->pid_file || !di->vty_path)
+ frr_mkdir(frr_vtydir, false);
+ if (di->pid_file)
+ frr_mkdir(di->pid_file, true);
+ if (di->vty_path)
+ frr_mkdir(di->vty_path, true);
+ }
+#endif
+
+#if 0
+ frrmod_init(di->module);
+ while (modules) {
+ modules = (oc = modules)->next;
+ module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
+ if (!module) {
+ fprintf(stderr, "%s\n", moderr);
+ exit(1);
+ }
+ XFREE(MTYPE_TMP, oc);
+ }
+
+#endif
+
+ zprivs_init(di->privs);
+ master = event_master_create(NULL);
+
+/* We don't want signal handlers for fuzzing, libFuzzer uses signals for
+ * process control */
+#if 0
+ signal_init(master, di->n_signals, di->signals);
+#endif
+
+#if 0
+#ifdef HAVE_SQLITE3
+ if (!di->db_file)
+ di->db_file = dbfile_default;
+ db_init(di->db_file);
+#endif
+
+#endif
+ if (di->flags & FRR_LIMITED_CLI)
+ cmd_init(-1);
+ else
+ cmd_init(1);
+
+ vty_init(master, di->log_always);
+
+#if 0
+ log_filter_cmd_init();
+#endif
+
+#if 0
+ frr_pthread_init();
+#endif
+
+ log_ref_init();
+#if 0
+ log_ref_vty_init();
+#endif
+ lib_error_init();
+
+#if 0
+ yang_init();
+
+ debug_init_cli();
+
+ nb_init(master, di->yang_modules, di->n_yang_modules);
+ if (nb_db_init() != NB_OK)
+ flog_warn(EC_LIB_NB_DATABASE,
+ "%s: failed to initialize northbound database",
+ __func__);
+#endif
+
+ return master;
+}
+#endif
+
const char *frr_get_progname(void)
{
return di ? di->progname : NULL;
extern __attribute__((__noreturn__)) void frr_help_exit(int status);
+/* FOR FUZZING */
+extern struct event_loop *frr_init_fast(void);
+
extern struct event_loop *frr_init(void);
extern const char *frr_get_progname(void);
extern enum frr_cli_mode frr_get_cli_mode(void);
DEFINE_MTYPE(LIB, TMP, "Temporary memory");
DEFINE_MTYPE(LIB, BITFIELD, "Bitfield memory");
+#ifdef FUZZING
+#undef HAVE_MALLOC_USABLE_SIZE
+#endif
+
static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
size_t current;
extern "C" {
#endif
+#define FUZZING 1
+#ifdef FUZZING
+#undef HAVE_MALLOC_USABLE_SIZE
+#undef HAVE_MALLOC_SIZE
+#endif
+
#if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE)
#define malloc_usable_size(x) malloc_size(x)
#define HAVE_MALLOC_USABLE_SIZE
* has defined behaviour for << 32 (or has a 64-bit left shift) */
if (sizeof(unsigned long long) > 4)
- netmask->s_addr = htonl(0xffffffffULL << (32 - masklen));
+ netmask->s_addr =
+ htonl((uint32_t)(0xffffffffULL << (32 - masklen)));
else
netmask->s_addr =
htonl(masklen ? 0xffffffffU << (32 - masklen) : 0);
/*
* Non-MT-safe version
*/
-ssize_t
-vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
+ssize_t vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
{
const char *fmt; /* format string */
int ch; /* character from fmt */
if (flags & INTMAX_SIZE)
ujval = SJARG();
else
- ulval = SARG();
+ ulval = (u_long)SARG();
if (printfrr_ext_char(fmt[0])) {
struct printfrr_eargs ea = {
}
} else {
if ((long)ulval < 0) {
- ulval = -ulval;
+ ulval = (~ulval) + 1;
sign = '-';
}
}
/* we have caps, we have no need to ever change back the original user
*/
/* only change uid if we don't have the correct one */
+#ifndef FUZZING
if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {
if (setreuid(zprivs_state.zuid, zprivs_state.zuid)) {
fprintf(stderr,
exit(1);
}
}
-
+#endif
if (!(zprivs_state.caps = cap_init())) {
fprintf(stderr, "privs_init: failed to cap_init, %s\n",
safe_strerror(errno));
/* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as
* and when, and only when, they are needed.
*/
+#ifndef FUZZING
if (cap_set_proc(zprivs_state.caps)) {
cap_t current_caps;
char *current_caps_text = NULL;
exit(1);
}
-
+#endif
/* set methods for the caller to use */
zprivs->change = zprivs_change_caps;
zprivs->current_state = zprivs_state_caps;
struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
const char *funcname)
{
+#ifdef FUZZING
+ return NULL;
+#endif
int save_errno = errno;
struct zebra_privs_refs_t *refs;
void _zprivs_lower(struct zebra_privs_t **privs)
{
+#ifdef FUZZING
+ return;
+#endif
int save_errno = errno;
struct zebra_privs_refs_t *refs;
zprivs->process_refs.raised_in_funcname = NULL;
STAILQ_INIT(&zprivs->thread_refs);
+#ifdef FUZZING
+ zprivs->user = NULL;
+ zprivs->group = NULL;
+ zprivs->vty_group = NULL;
+#endif
+
if (zprivs->vty_group) {
/* in a "NULL" setup, this is allowed to fail too, but still
* try. */
zprivs_state.zsuid = geteuid(); /* initial uid */
/* add groups only if we changed uid - otherwise skip */
+#ifndef FUZZING
if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid)) {
if (setgroups(ngroups, groups)) {
fprintf(stderr, "privs_init: could not setgroups, %s\n",
exit(1);
}
}
+#endif
#ifdef HAVE_CAPABILITIES
zprivs_caps_init(zprivs);
exit(1);
}
}
-
+#ifndef FUZZING
zprivs->change = zprivs_change_uid;
zprivs->current_state = zprivs_state_uid;
+#endif
#endif /* HAVE_CAPABILITIES */
}
[ZEBRA_INTERFACE_BFD_DEST_UPDATE] = zclient_bfd_session_update,
};
+#ifdef FUZZING
+int zclient_read_fuzz(struct zclient *zclient, const uint8_t *data, size_t len)
+{
+ uint16_t length, command;
+ uint8_t marker, version;
+ vrf_id_t vrf_id;
+
+ /* Length check. */
+ if (len > STREAM_SIZE(zclient->ibuf)) {
+ struct stream *ns;
+ flog_err(
+ EC_LIB_ZAPI_ENCODE,
+ "%s: message size %zu exceeds buffer size %lu, expanding...",
+ __func__, len,
+ (unsigned long)STREAM_SIZE(zclient->ibuf));
+ ns = stream_new(len);
+ stream_free(zclient->ibuf);
+ zclient->ibuf = ns;
+ }
+
+ if (len < ZEBRA_HEADER_SIZE) {
+ flog_err(EC_LIB_ZAPI_MISSMATCH,
+ "%s: socket %d message length %zu is less than %d ",
+ __func__, zclient->sock, len, ZEBRA_HEADER_SIZE);
+ return -1;
+ }
+
+ stream_reset(zclient->ibuf);
+ stream_put(zclient->ibuf, data, len);
+
+ length = stream_getw(zclient->ibuf);
+ marker = stream_getc(zclient->ibuf);
+ version = stream_getc(zclient->ibuf);
+ vrf_id = stream_getl(zclient->ibuf);
+ command = stream_getw(zclient->ibuf);
+
+ if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
+ flog_err(
+ EC_LIB_ZAPI_MISSMATCH,
+ "%s: socket %d version mismatch, marker %d, version %d",
+ __func__, zclient->sock, marker, version);
+ return -1;
+ }
+
+ length -= ZEBRA_HEADER_SIZE;
+
+ if (zclient_debug)
+ zlog_debug("zclient %p command %s VRF %u", zclient,
+ zserv_command_string(command), vrf_id);
+
+ if (command < array_size(lib_handlers) && lib_handlers[command])
+ lib_handlers[command](command, zclient, length, vrf_id);
+ if (command < zclient->n_handlers && zclient->handlers[command])
+ zclient->handlers[command](command, zclient, length, vrf_id);
+
+ if (zclient->sock < 0)
+ /* Connection was closed during packet processing. */
+ return -1;
+
+ /* Register read thread. */
+ stream_reset(zclient->ibuf);
+ zclient_event(ZCLIENT_READ, zclient);
+
+ return 0;
+}
+#endif
+
/* Zebra client message read function. */
static void zclient_read(struct event *thread)
{
#define _ZEBRA_ZCLIENT_H
struct zclient;
+#define FUZZING 1
/* For struct zapi_route. */
#include "prefix.h"
uint32_t session_id;
};
+#ifdef FUZZING
+int zclient_read_fuzz(struct zclient *zclient, const uint8_t *data, size_t len);
+#endif
+
/* Decode incoming client close notify */
extern int zapi_client_close_notify_decode(struct stream *s,
struct zapi_client_close_info *info);
#ifndef _ZEBRA_H
#define _ZEBRA_H
+#define FUZZING 1
+
+#define ZAPI_FUZZING 1
+#define NETLINK_FUZZING 2
+
+#define FUZZING_MODE ZAPI_FUZZING
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <endian.h>
#endif
+#ifdef FUZZING
+#include "fuzz.h"
+#endif
+
/* misc include group */
#include <stdarg.h>
zlog_ref(&_xref, (msg), ##__VA_ARGS__); \
} while (0)
+#ifndef FUZZING
+
#define zlog_err(...) _zlog_ecref(0, LOG_ERR, __VA_ARGS__)
#define zlog_warn(...) _zlog_ecref(0, LOG_WARNING, __VA_ARGS__)
#define zlog_info(...) _zlog_ecref(0, LOG_INFO, __VA_ARGS__)
#define flog_err_sys(ferr_id, format, ...) \
_zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
+#else
+
+#define zlog_err(...) 0
+#define zlog_warn(...) 0
+#define zlog_info(...) 0
+#define zlog_notice(...) 0
+#define zlog_debug(...) 0
+
+#define flog_err(ferr_id, format, ...) 0
+#define flog_warn(ferr_id, format, ...) 0
+#define flog_err_sys(ferr_id, format, ...) 0
+
+#endif
+
extern void zlog_sigsafe(const char *text, size_t len);
/* extra priority value to disable a target without deleting it */
can be originated. "
*/
- if (ntohl(lsa->data->ls_seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) {
+ if (ntohl(lsa->data->ls_seqnum) != 0
+ && ntohl(lsa->data->ls_seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) {
if (ospf_lsa_is_self_originated(ospf, lsa)) {
lsa->data->ls_seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER);
data->lsa = ospf_lsa_lock(lsa); /* Message / Flood area */
event_add_event(master, ospf_lsa_action, data, 0, NULL);
+#ifdef FUZZING
+ XFREE(MTYPE_OSPF_MESSAGE, data);
+#endif
}
void ospf_schedule_lsa_flush_area(struct ospf_area *area, struct ospf_lsa *lsa)
data->lsa = ospf_lsa_lock(lsa); /* Message / Flush area */
event_add_event(master, ospf_lsa_action, data, 0, NULL);
+#ifdef FUZZING
+ XFREE(MTYPE_OSPF_MESSAGE, data);
+#endif
}
#include "libfrr.h"
#include "routemap.h"
+#ifdef FUZZING
+#include "sockopt.h"
+#include <netinet/ip.h>
+#endif
+
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_asbr.h"
.n_yang_modules = array_size(ospfd_yang_modules),
);
+#ifdef FUZZING
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static bool FuzzingInit(void)
+{
+ unsigned short instance = 0;
+ bool created = false;
+
+ const char *name[] = { "ospfd" };
+
+ frr_preinit(&ospfd_di, 1, (char **) &name);
+
+
+ /* INIT */
+ ospf_master_init(frr_init_fast());
+ ospf_debug_init();
+ ospf_vrf_init();
+ access_list_init();
+ prefix_list_init();
+ ospf_if_init();
+ ospf_zebra_init(master, instance);
+ ospf_bfd_init(master);
+ ospf_route_map_init();
+ ospf_opaque_init();
+ ospf_error_init();
+
+ return true;
+}
+
+static struct ospf *FuzzingCreateOspf(void)
+{
+ struct prefix p;
+ struct interface *ifp = if_get_by_name("fuzziface", 0, "default");
+ ifp->mtu = 68;
+ str2prefix("11.0.2.0/24", &p);
+
+ bool created;
+ struct ospf *o = ospf_get(0, "omgwtfbbq", &created);
+ o->fd = 69;
+
+ struct in_addr in;
+ inet_pton(AF_INET, "0.0.0.0", &in);
+ struct ospf_area *a = ospf_area_new(o, in);
+
+ struct connected *c = connected_add_by_prefix(ifp, &p, NULL);
+ add_ospf_interface(c, a);
+
+ struct ospf_interface *oi = listhead(a->oiflist)->data;
+ oi->state = 7; // ISM_DR
+
+ o->fuzzing_packet_ifp = ifp;
+
+ return o;
+}
+
+static struct ospf *FuzzingOspf;
+static bool FuzzingInitialized;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (!FuzzingInitialized) {
+ FuzzingInit();
+ FuzzingInitialized = true;
+ FuzzingOspf = FuzzingCreateOspf();
+ }
+
+ struct ospf *o;
+
+#ifdef FUZZING_LIBFUZZER
+ o = FuzzingOspf;
+#else
+ o = FuzzingOspf;
+#endif
+
+ /* Simulate the read process done by ospf_recv_packet */
+ stream_free(o->ibuf);
+ o->ibuf = stream_new(MAX(1, size));
+
+ stream_put(o->ibuf, data, size);
+ {
+ struct ip *iph;
+ unsigned short ip_len = 0;
+
+ if (size < sizeof(struct ip))
+ goto done;
+
+ iph = (struct ip *)STREAM_DATA(o->ibuf);
+ sockopt_iphdrincl_swab_systoh(iph);
+ ip_len = iph->ip_len;
+
+ // skipping platform #ifdefs as I test on linux right now
+ // skipping ifindex lookup as it will fail anyway
+
+ if (size != ip_len)
+ goto done;
+ }
+
+ ospf_read_helper(o);
+
+done:
+ return 0;
+}
+#endif
+
+#ifndef FUZZING_LIBFUZZER
/* OSPFd main routine. */
int main(int argc, char **argv)
{
+#ifdef FUZZING
+
+ FuzzingInitialized = FuzzingInit();
+ FuzzingOspf = FuzzingCreateOspf();
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif
+ uint8_t *input = NULL;
+ int r = frrfuzz_read_input(&input);
+
+ if (r < 0 || !input)
+ goto done;
+
+ LLVMFuzzerTestOneInput(input, r);
+
+ free(input);
+done:
+ return 0;
+#endif
+
#ifdef SUPPORT_OSPF_API
/* OSPF apiserver is disabled by default. */
ospf_apiserver_enable = 0;
/* Not reached. */
return 0;
}
+#endif
\ No newline at end of file
if (IPV4_ADDR_SAME(&nbr_nbma->addr, &nbr->src)) {
nbr_nbma->nbr = nbr;
nbr->nbr_nbma = nbr_nbma;
-
+#ifndef FUZZING
if (nbr_nbma->t_poll)
EVENT_OFF(nbr_nbma->t_poll);
-
+#endif
nbr->state_change = nbr_nbma->state_change + 1;
}
}
}
/* New nbr, save the crypto sequence number if necessary */
+#ifndef FUZZING
if (ntohs(ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
-
+#endif
/* Configure BFD if interface has it. */
ospf_neighbor_bfd_apply(nbr);
int ospf_sock_init(struct ospf *ospf)
{
+#ifdef FUZZING
+ return 0;
+#endif
int ret;
/* silently ignore. already done */
#define OSPF_NSM_EVENT_SCHEDULE(N, E) \
event_add_event(master, ospf_nsm_event, (N), (E), NULL)
+#ifdef FUZZING
+#undef OSPF_NSM_EVENT_SCHEDULE
+#define OSPF_NSM_EVENT_SCHEDULE(N, E)
+#endif
+
/* Macro for OSPF NSM execute event. */
#define OSPF_NSM_EVENT_EXECUTE(N, E) \
event_execute(master, ospf_nsm_event, (N), (E))
/* Search proper LSA in LSDB. */
find = ospf_lsa_lookup(oi->ospf, oi->area, ls_type, ls_id,
adv_router);
+#ifndef FUZZING
if (find == NULL) {
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_BadLSReq);
list_delete(&ls_upd);
/* Append LSA to update list. */
listnode_add(ls_upd, find);
length += ntohs(find->data->length);
-
+#endif
size -= OSPF_LSA_KEY_SIZE;
}
+#ifdef FUZZING
+ list_delete(&ls_upd);
+ return;
+#endif
/* Send rest of Link State Update. */
if (listcount(ls_upd) > 0) {
msgh.msg_control = (caddr_t)buff;
msgh.msg_controllen = sizeof(buff);
+#ifndef FUZZING
ret = stream_recvmsg(ibuf, fd, &msgh, MSG_DONTWAIT,
OSPF_MAX_PACKET_SIZE + 1);
+#endif
+
if (ret < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK)
flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s",
lookup_msg(ospf_auth_type_str,
iface_auth_type, NULL),
&ospfh->router_id);
+#ifndef FUZZING
return 0;
+#endif
}
if (!ospf_check_sum(ospfh)) {
if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
"interface %s: Null auth OK, but checksum error, Router-ID %pI4",
IF_NAME(oi),
&ospfh->router_id);
+#ifndef FUZZING
return 0;
+#endif
}
return 1;
case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */
return 0;
}
-enum ospf_read_return_enum {
- OSPF_READ_ERROR,
- OSPF_READ_CONTINUE,
-};
-
-static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
+enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
{
int ret;
struct stream *ibuf;
struct connected *c;
struct interface *ifp = NULL;
+#ifndef FUZZING
stream_reset(ospf->ibuf);
ibuf = ospf_recv_packet(ospf, ospf->fd, &ifp, ospf->ibuf);
+#else
+ ibuf = ospf->ibuf;
+ ifp = ospf->fuzzing_packet_ifp;
+#endif
if (ibuf == NULL)
return OSPF_READ_ERROR;
/* Adjust size to message length. */
length = ntohs(ospfh->length) - OSPF_HEADER_SIZE;
+#ifdef FUZZING
+ /*
+ * Everything except hellos returns early with no neighbor found, so we
+ * need to make a neighbor
+ */
+ struct prefix p;
+ p.family = AF_INET;
+ p.prefixlen = 24;
+ p.u.prefix4 = iph->ip_src;
+
+ struct ospf_neighbor *n = ospf_nbr_get(oi, ospfh, iph, &p);
+ n->state = NSM_Exchange;
+#endif
+
/* Read rest of the packet and call each sort of packet routine.
*/
switch (ospfh->type) {
extern void ospf_proactively_arp(struct ospf_neighbor *);
+#ifdef FUZZING
+enum ospf_read_return_enum {
+ OSPF_READ_ERROR,
+ OSPF_READ_CONTINUE,
+};
+
+enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf);
+#endif
+
#endif /* _ZEBRA_OSPF_PACKET_H */
* config. */
uint8_t oi_running;
+#ifdef FUZZING
+ struct interface *fuzzing_packet_ifp;
+#endif
+
/* OSPF instance ID */
unsigned short instance;
ospfd/ospf_zebra.h \
# end
+ospfd_ospfd_LDFLAGS = $(AM_LDFLAGS) $(OSPFD_SAN_FLAGS)
ospfd_ospfd_LDADD = ospfd/libfrrospf.a ospfd/libfrrospfclient.a lib/libfrr.la $(LIBCAP) $(LIBM)
ospfd_ospfd_SOURCES = ospfd/ospf_main.c
return count;
}
-
-static int pim_ifp_create(struct interface *ifp)
+#ifndef FUZZING
+static
+#endif
+int pim_ifp_create(struct interface *ifp)
{
struct pim_instance *pim;
return 0;
}
-static int pim_ifp_up(struct interface *ifp)
+#ifndef FUZZING
+static
+#endif
+int pim_ifp_up(struct interface *ifp)
{
uint32_t table_id;
struct pim_interface *pim_ifp;
return 0;
}
-static int pim_ifp_down(struct interface *ifp)
+#ifndef FUZZING
+static
+#endif
+int pim_ifp_down(struct interface *ifp)
{
if (PIM_DEBUG_ZEBRA) {
zlog_debug(
return 0;
}
-
-static int pim_ifp_destroy(struct interface *ifp)
+#ifndef FUZZING
+static
+#endif
+int pim_ifp_destroy(struct interface *ifp)
{
if (PIM_DEBUG_ZEBRA) {
zlog_debug(
void pim_iface_init(void);
+#ifdef FUZZING
+int pim_ifp_create(struct interface *ifp);
+int pim_ifp_up(struct interface *ifp);
+int pim_ifp_down(struct interface *ifp);
+int pim_ifp_destroy(struct interface *ifp);
+#endif
+
#endif /* PIM_IFACE_H */
*/
#define PIM_IF_FLAG_MASK_COULD_ASSERT (1 << 0)
#define PIM_IF_FLAG_TEST_COULD_ASSERT(flags) ((flags) & PIM_IF_FLAG_MASK_COULD_ASSERT)
-#define PIM_IF_FLAG_SET_COULD_ASSERT(flags) ((flags) |= PIM_IF_FLAG_MASK_COULD_ASSERT)
-#define PIM_IF_FLAG_UNSET_COULD_ASSERT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_COULD_ASSERT)
+#define PIM_IF_FLAG_SET_COULD_ASSERT(flags) \
+ ((flags) |= (typeof((flags)))PIM_IF_FLAG_MASK_COULD_ASSERT)
+#define PIM_IF_FLAG_UNSET_COULD_ASSERT(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_IF_FLAG_MASK_COULD_ASSERT)
/*
Flag to detect change in AssertTrackingDesired(S,G,I)
*/
#define PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED (1 << 1)
#define PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(flags) ((flags) & PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
-#define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
-#define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
+#define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) \
+ ((flags) |= (typeof((flags)))PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
+#define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
/*
* Flag to tell us if the ifchannel is (S,G,rpt)
*/
#define PIM_IF_FLAG_MASK_S_G_RPT (1 << 2)
#define PIM_IF_FLAG_TEST_S_G_RPT(flags) ((flags) & PIM_IF_FLAG_MASK_S_G_RPT)
-#define PIM_IF_FLAG_SET_S_G_RPT(flags) ((flags) |= PIM_IF_FLAG_MASK_S_G_RPT)
-#define PIM_IF_FLAG_UNSET_S_G_RPT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_S_G_RPT)
+#define PIM_IF_FLAG_SET_S_G_RPT(flags) \
+ ((flags) |= (typeof((flags)))PIM_IF_FLAG_MASK_S_G_RPT)
+#define PIM_IF_FLAG_UNSET_S_G_RPT(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_IF_FLAG_MASK_S_G_RPT)
/*
* Flag to tell us if the ifchannel is proto PIM
*/
#define PIM_IF_FLAG_MASK_PROTO_PIM (1 << 3)
#define PIM_IF_FLAG_TEST_PROTO_PIM(flags) ((flags)&PIM_IF_FLAG_MASK_PROTO_PIM)
-#define PIM_IF_FLAG_SET_PROTO_PIM(flags) ((flags) |= PIM_IF_FLAG_MASK_PROTO_PIM)
+#define PIM_IF_FLAG_SET_PROTO_PIM(flags) \
+ ((flags) |= (typeof((flags)))PIM_IF_FLAG_MASK_PROTO_PIM)
#define PIM_IF_FLAG_UNSET_PROTO_PIM(flags) \
((flags) &= ~PIM_IF_FLAG_MASK_PROTO_PIM)
/*
#define PIM_IF_FLAG_MASK_PROTO_IGMP (1 << 4)
#define PIM_IF_FLAG_TEST_PROTO_IGMP(flags) ((flags)&PIM_IF_FLAG_MASK_PROTO_IGMP)
#define PIM_IF_FLAG_SET_PROTO_IGMP(flags) \
- ((flags) |= PIM_IF_FLAG_MASK_PROTO_IGMP)
+ ((flags) |= (typeof((flags)))PIM_IF_FLAG_MASK_PROTO_IGMP)
#define PIM_IF_FLAG_UNSET_PROTO_IGMP(flags) \
- ((flags) &= ~PIM_IF_FLAG_MASK_PROTO_IGMP)
+ ((flags) &= (typeof((flags))) ~PIM_IF_FLAG_MASK_PROTO_IGMP)
/*
Per-interface (S,G) state
*/
struct sockaddr_in sin;
int fd;
+#ifndef FUZZING
fd = igmp_sock_open(ifaddr, ifp);
if (fd < 0) {
zlog_warn("Could not open IGMP socket for %pI4 on %s",
&ifaddr, ifp->name);
return NULL;
}
+#else
+ fd = 69;
+#endif
sin.sin_family = AF_INET;
sin.sin_addr = ifaddr;
void igmp_source_free(struct gm_source *source)
{
/* make sure there is no source timer running */
+#ifndef FUZZING
assert(!source->t_source_timer);
-
+#endif
XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source);
}
* (A-X-Y) */
assert(!source->t_source_timer); /* timer == 0 */
igmp_source_reset_gmi(group, source);
+#ifndef FUZZING
assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+#endif
}
} /* scan received sources */
} else {
/* I.4: if not found, create source with timer=0 (B-A)
*/
+#ifndef FUZZING
assert(!source->t_source_timer); /* (B-A) timer=0 */
+#endif
}
} /* scan received sources */
/* and set SEND flag (A*B) */
IGMP_SOURCE_DO_SEND(source->source_flags);
++num_sources_tosend;
+#ifndef FUZZING
+ assert(!source->t_source_timer); /* (B-A) timer=0 */
+#endif
}
} /* Scan received sources (B) */
assert(!source->t_source_timer); /* timer == 0 */
group_timer_msec = igmp_group_timer_remain_msec(group);
igmp_source_timer_on(group, source, group_timer_msec);
+#ifndef FUZZING
assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
-
+#endif
/* make sure source is created with DELETE flag unset */
assert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
}
assert(!source->t_source_timer); /* timer == 0 */
group_timer_msec = igmp_group_timer_remain_msec(group);
igmp_source_timer_on(group, source, group_timer_msec);
+#ifndef FUZZING
assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+#endif
}
if (source->t_source_timer) {
if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) {
zlog_warn(
- "Recv IGMPv3 report from %s on %s with invalid checksum",
- from_str, ifp->name);
+ "Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
+ from_str, ifp->name, recv_checksum, checksum);
+#ifndef FUZZING
return -1;
+#endif
}
/* Collecting IGMP Rx stats */
pim->last_route_change_time = -1;
+#ifndef FUZZING
pim->reg_sock = pim_reg_sock();
if (pim->reg_sock < 0)
assert(0);
+#endif
/* MSDP global timer defaults. */
pim->msdp.hold_time = PIM_MSDP_PEER_HOLD_TIME;
return 0;
}
-static int pim_vrf_config_write(struct vty *vty)
+static int __attribute__((unused)) pim_vrf_config_write(struct vty *vty)
{
struct vrf *vrf;
struct pim_instance *pim;
void pim_vrf_init(void)
{
vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete);
-
+#ifndef FUZZING
vrf_cmd_init(pim_vrf_config_write);
+#endif
}
void pim_vrf_terminate(void)
struct in_addr anycast_vtep_ip;
struct in_addr local_vtep_ip;
struct pim_mlag_stats mlag_stats;
- enum pim_mlag_flags mlag_flags;
+ uint8_t mlag_flags;
char peerlink_rif[INTERFACE_NAMSIZ];
struct interface *peerlink_rif_p;
};
#include "pim_errors.h"
#include "pim_nb.h"
+#define FUZZING 1
+#ifdef FUZZING
+#include "fuzz.h"
+#include "pim_pim.h"
+#include "pim_mroute.h"
+#include "pim_tlv.h"
+#include "pim_neighbor.h"
+#endif
+
extern struct host host;
struct option longopts[] = {{0}};
.n_yang_modules = array_size(pimd_yang_modules),
);
+#ifdef FUZZING
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static struct interface *FuzzingIfp;
+static struct in_addr FuzzingSrc = { .s_addr = 0x0900001b };
+
+static bool FuzzingInit(void)
+{
+ vrf_configure_backend(VRF_BACKEND_VRF_LITE);
+
+ const char *name[] = {"pimd"};
+
+ frr_preinit(&pimd_di, 1, (char **)name);
+ pim_router_init();
+
+ /*
+ * Initializations
+ */
+ pim_error_init();
+ pim_vrf_init();
+ access_list_init();
+ prefix_list_init();
+ prefix_list_add_hook(pim_prefix_list_update);
+ prefix_list_delete_hook(pim_prefix_list_update);
+
+ pim_route_map_init();
+ pim_init();
+
+ /*
+ * Initialize zclient "update" and "lookup" sockets
+ */
+ if_zapi_callbacks(pim_ifp_create, pim_ifp_up,
+ pim_ifp_down, pim_ifp_destroy);
+ pim_zebra_init();
+ pim_bfd_init();
+ pim_mlag_init();
+
+ /* Create some fake interface */
+
+ /* Source address stuff */
+ struct prefix p;
+ str2prefix("27.0.0.9/24", &p);
+
+ /* Create system interface */
+ FuzzingIfp = if_get_by_name("fuzziface", VRF_DEFAULT, "default");
+ if_set_index(FuzzingIfp, 69);
+ connected_add_by_prefix(FuzzingIfp, &p, NULL);
+
+ return true;
+}
+
+static struct pim_instance *FuzzingCreatePimInstance(void)
+{
+ /* Create pim stuff */
+ fprintf(stderr, ">>>>>>>>> %p\n", FuzzingIfp);
+ struct pim_interface *pim_ifp = pim_if_new(FuzzingIfp, true, true, false, false);
+ pim_igmp_sock_add(pim_ifp->gm_socket_list, FuzzingSrc, FuzzingIfp, false);
+
+ struct pim_instance *pim = vrf_lookup_by_id(VRF_DEFAULT)->info;
+ pim_if_create_pimreg(pim);
+ pim_hello_options ho = 0;
+ pim_neighbor_add(FuzzingIfp, FuzzingSrc, ho, 210, 1, 1, 30, 20, NULL, 0);
+
+ return pim;
+}
+
+static bool FuzzingInitialized;
+
+static struct pim_instance *FuzzingPim;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (!FuzzingInitialized) {
+ FuzzingInit();
+ FuzzingInitialized = true;
+ FuzzingPim = FuzzingCreatePimInstance();
+ }
+
+ struct pim_instance *pim;
+#ifdef FUZZING_LIBFUZZER
+ pim = FuzzingPim;
+#else
+ pim = FuzzingPim;
+#endif
+
+ int result;
+
+ uint8_t *input = malloc(size);
+ memcpy(input, data, size);
+
+#ifdef KERNEL_IFACE
+ result = pim_mroute_msg(pim, (const char *) input, size, 69);
+#else
+ int retval;
+ struct in_addr src;
+ struct in_addr grp;
+
+ memset(&src, '\0', sizeof(src));
+ memset(&grp, '\0', sizeof(grp));
+
+ retval = inet_aton("10.1.1.1", &src);
+ retval = inet_aton("10.1.1.2", &grp);
+
+ pim_sgaddr sg;
+ sg.src = src;
+ sg.grp = grp;
+ result = pim_pim_packet(FuzzingIfp, input, size, sg);
+
+#endif /* KERNEL_IFACE */
+
+ free(input);
+
+ return result;
+}
+#endif /* FUZZING */
+
+#ifndef FUZZING_LIBFUZZER
int main(int argc, char **argv, char **envp)
{
frr_preinit(&pimd_di, argc, argv);
+
+#ifdef FUZZING
+ FuzzingInit();
+ FuzzingInitialized = true;
+ FuzzingPim = FuzzingCreatePimInstance();
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif /* __AFL_HAVE_MANUAL_CONTROL */
+
+ uint8_t *input = NULL;
+ int r = frrfuzz_read_input(&input);
+
+ int ret = LLVMFuzzerTestOneInput(input, r);
+
+ return ret;
+#endif /* FUZZING */
+
frr_opt_add("", longopts, "");
/* this while just reads the options */
break;
default:
frr_help_exit(1);
+ break;
}
}
/* never reached */
return 0;
}
+#endif /* FUZZING_LIBFUZZER */
\ No newline at end of file
static void pim_mlag_param_reset(void)
{
/* reset the cached params and stats */
- router->mlag_flags &= ~(PIM_MLAGF_STATUS_RXED |
- PIM_MLAGF_LOCAL_CONN_UP |
- PIM_MLAGF_PEER_CONN_UP |
- PIM_MLAGF_PEER_ZEBRA_UP);
+ router->mlag_flags &=
+ (uint8_t) ~(PIM_MLAGF_STATUS_RXED | PIM_MLAGF_LOCAL_CONN_UP
+ | PIM_MLAGF_PEER_CONN_UP | PIM_MLAGF_PEER_ZEBRA_UP);
router->local_vtep_ip.s_addr = INADDR_ANY;
router->anycast_vtep_ip.s_addr = INADDR_ANY;
router->mlag_role = MLAG_ROLE_NONE;
frr_with_privs(&pimd_privs) {
+#ifndef FUZZING
#if PIM_IPV == 4
fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
#else
safe_strerror(errno));
return -2;
}
+#else
+ fd = 69;
+#endif
+#ifndef FUZZING
#if PIM_IPV == 6
struct icmp6_filter filter[1];
int ret;
"(VRF %s) failed to set mroute control filter: %m",
pim->vrf->name);
#endif
+#else
+ fd = 69;
+#endif
#ifdef SO_BINDTODEVICE
if (pim->vrf->vrf_id != VRF_DEFAULT
}
pim->mroute_socket = fd;
+#ifndef FUZZING
if (pim_mroute_set(pim, 1)) {
zlog_warn(
"Could not enable mroute on socket fd=%d: errno=%d: %s",
pim->mroute_socket_creation = pim_time_monotonic_sec();
mroute_read_on(pim);
+#endif
return 0;
}
#endif
#endif
+#ifndef FUZZING
err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
(void *)&vc, sizeof(vc));
+#else
+ err = 0;
+#endif
+
if (err) {
zlog_warn(
"%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
#define MRT6MSG_WRMIFWHOLE 4 /* For PIM processing */
#endif
+#include "lib/if.h"
+
#ifndef GMMSG_NOCACHE
#define GMMSG_NOCACHE MRT6MSG_NOCACHE /* For PIM processing */
#define GMMSG_WHOLEPKT MRT6MSG_WHOLEPKT /* For PIM processing */
/*
Above: from <linux/mroute.h>
*/
-
struct channel_oil;
struct pim_instance;
PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
/* update num. of neighbors without hello option lan_delay */
- --pim_ifp->pim_number_of_nonlandelay_neighbors;
+ pim_ifp->pim_number_of_nonlandelay_neighbors = MAX(
+ pim_ifp->pim_number_of_nonlandelay_neighbors - 1, 0);
}
if (!PIM_OPTION_IS_SET(neigh->hello_options,
PIM_OPTION_MASK_DR_PRIORITY)) {
/* update num. of neighbors without dr_pri */
- --pim_ifp->pim_dr_num_nondrpri_neighbors;
+ pim_ifp->pim_dr_num_nondrpri_neighbors =
+ MAX(pim_ifp->pim_dr_num_nondrpri_neighbors - 1, 0);
}
assert(neigh->propagation_delay_msec
}
ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
+#ifdef FUZZING
+ /*
+ * Ensure that the header length is 20 or 24 bytes as is appropriate
+ * The kernel typically ensures that the passed up ip header meets
+ * standards, and would actually drop the packet if it didn't meet
+ * them. So since we are fuzzing and faking the header bits/bobs
+ * then let's ensure that we don't get into a weird situation
+ * where a bad ip_hlen here causes pim_msg_len to wrap around into
+ * the high billions and then we have an issue later
+ */
+ if (ip_hlen != 20 && ip_hlen != 24)
+ return -1;
+#endif
sg = pim_sgaddr_from_iphdr(ip_hdr);
pim_msg = buf + ip_hlen;
"Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
ifp->name, pim_checksum,
checksum);
-
+#ifndef FUZZING
return -1;
+#endif
}
}
} else {
zlog_debug(
"Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
ifp->name, pim_checksum, checksum);
-
+#ifndef FUZZING
return -1;
+#endif
}
}
}
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
+
+ if (tlv_buf_size
+ < (int)(PIM_MSG_REGISTER_BIT_RESERVED_LEN + sizeof(struct ip))) {
+ return 0;
+ }
ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) {
pim_addr_to_prefix(&grp, up->sg.grp);
trp_info = pim_rp_find_match_group(pim, &grp);
+ if (!trp_info)
+ continue;
+
/* RP not found for the group grp */
if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) {
pim_upstream_rpf_clear(pim, up);
#define PIM_RPT_BIT_MASK (1 << 0)
#define PIM_WILDCARD_BIT_MASK (1 << 1)
-#define PIM_OPTION_SET(options, option_mask) ((options) |= (option_mask))
-#define PIM_OPTION_UNSET(options, option_mask) ((options) &= ~(option_mask))
+#define PIM_OPTION_SET(options, option_mask) \
+ ((options) |= (typeof((options)))(option_mask))
+#define PIM_OPTION_UNSET(options, option_mask) \
+ ((options) &= (typeof((options))) ~(option_mask))
#define PIM_OPTION_IS_SET(options, option_mask) ((options) & (option_mask))
#define PIM_TLV_GET_UINT16(buf) \
#define PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_IGMP | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM))
#define PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(flags) ((flags)&PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
-#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
-#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
-#define PIM_UPSTREAM_FLAG_SET_FHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_FHR)
-#define PIM_UPSTREAM_FLAG_SET_SRC_IGMP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
-#define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
-#define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
-#define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
-#define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
-#define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
-#define PIM_UPSTREAM_FLAG_SET_DISABLE_KAT_EXPIRY(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
-#define PIM_UPSTREAM_FLAG_SET_STATIC_IIF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
-#define PIM_UPSTREAM_FLAG_SET_ALLOW_IIF_IN_OIL(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
-#define PIM_UPSTREAM_FLAG_SET_NO_PIMREG_DATA(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
-#define PIM_UPSTREAM_FLAG_SET_FORCE_PIMREG(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
-#define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_ORIG(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
-#define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
-#define PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
-#define PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
-#define PIM_UPSTREAM_FLAG_SET_MLAG_PEER(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
-#define PIM_UPSTREAM_FLAG_SET_USE_RPT(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_USE_RPT)
-#define PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
-
-#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
-#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
-#define PIM_UPSTREAM_FLAG_UNSET_FHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_FHR)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
-#define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
-#define PIM_UPSTREAM_FLAG_UNSET_DISABLE_KAT_EXPIRY(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
-#define PIM_UPSTREAM_FLAG_UNSET_STATIC_IIF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
-#define PIM_UPSTREAM_FLAG_UNSET_ALLOW_IIF_IN_OIL(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
-#define PIM_UPSTREAM_FLAG_UNSET_NO_PIMREG_DATA(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
-#define PIM_UPSTREAM_FLAG_UNSET_FORCE_PIMREG(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_ORIG(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
-#define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
-#define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
-#define PIM_UPSTREAM_FLAG_UNSET_MLAG_PEER(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
-#define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE)
-#define PIM_UPSTREAM_FLAG_UNSET_USE_RPT(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_USE_RPT)
-#define PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
+#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
+#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) \
+ ((flags) |= \
+ (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
+#define PIM_UPSTREAM_FLAG_SET_FHR(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_FHR)
+#define PIM_UPSTREAM_FLAG_SET_SRC_IGMP(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+#define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+#define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
+#define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+#define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
+#define PIM_UPSTREAM_FLAG_SET_DISABLE_KAT_EXPIRY(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
+#define PIM_UPSTREAM_FLAG_SET_STATIC_IIF(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
+#define PIM_UPSTREAM_FLAG_SET_ALLOW_IIF_IN_OIL(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
+#define PIM_UPSTREAM_FLAG_SET_NO_PIMREG_DATA(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
+#define PIM_UPSTREAM_FLAG_SET_FORCE_PIMREG(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
+#define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_ORIG(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
+#define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
+#define PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
+#define PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
+#define PIM_UPSTREAM_FLAG_SET_MLAG_PEER(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
+#define PIM_UPSTREAM_FLAG_SET_USE_RPT(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_USE_RPT)
+#define PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(flags) \
+ ((flags) |= (typeof((flags)))PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
+
+#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
+#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) \
+ ((flags) &= \
+ (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
+#define PIM_UPSTREAM_FLAG_UNSET_FHR(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_FHR)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+#define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
+#define PIM_UPSTREAM_FLAG_UNSET_DISABLE_KAT_EXPIRY(flags) \
+ ((flags) &= \
+ (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
+#define PIM_UPSTREAM_FLAG_UNSET_STATIC_IIF(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
+#define PIM_UPSTREAM_FLAG_UNSET_ALLOW_IIF_IN_OIL(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
+#define PIM_UPSTREAM_FLAG_UNSET_NO_PIMREG_DATA(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
+#define PIM_UPSTREAM_FLAG_UNSET_FORCE_PIMREG(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_ORIG(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
+#define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
+#define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
+#define PIM_UPSTREAM_FLAG_UNSET_MLAG_PEER(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE)
+#define PIM_UPSTREAM_FLAG_UNSET_USE_RPT(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_USE_RPT)
+#define PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(flags) \
+ ((flags) &= (typeof((flags))) ~PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
+
/* The RPF cost is incremented by 10 if the RPF interface is the peerlink-rif.
* This is used to force the MLAG switch with the lowest cost to the RPF
router = XCALLOC(MTYPE_ROUTER, sizeof(*router));
router->debugs = 0;
- router->master = frr_init();
+ router->master = frr_init_fast();
router->t_periodic = PIM_DEFAULT_T_PERIODIC;
router->multipath = MULTIPATH_NUM;
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP)
+pimd_pimd_LDFLAGS = $(AM_LDFLAGS) $(PIMD_SAN_FLAGS)
if PIM6D
sbin_PROGRAMS += pimd/pim6d
pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP)
+pimd_pimd6d_LDFLAGS = $(AM_LDFLAGS) $(PIMD_SAN_FLAGS)
endif
pimd_test_igmpv3_join_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
# end
vrrpd_vrrpd_LDADD = lib/libfrr.la @LIBCAP@
+vrrpd_vrrpd_LDFLAGS = $(AM_CFLAGS) $(VRRPD_SAN_FLAGS)
nodist_vrrpd_vrrpd_SOURCES = \
yang/frr-vrrpd.yang.c \
# end
/*
* Read and process next IPvX datagram.
*/
-static void vrrp_read(struct event *thread)
+#ifndef FUZZING
+static
+#endif
+void vrrp_read(struct event *thread)
{
struct vrrp_router *r = EVENT_ARG(thread);
m.msg_control = control;
m.msg_controllen = sizeof(control);
+#ifndef FUZZING
nbytes = recvmsg(r->sock_rx, &m, MSG_DONTWAIT);
if ((nbytes < 0 && ERRNO_IO_RETRY(errno))) {
resched = false;
goto done;
}
+#else
+ nbytes = r->fuzzing_input_size;
+ m.msg_name = &r->fuzzing_sa;
+#endif
if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt, DEBUG_MODE_ALL)) {
DEBUGD(&vrrp_dbg_pkt,
done:
memset(r->ibuf, 0x00, sizeof(r->ibuf));
-
+#ifndef FUZZING
if (resched)
event_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
+#endif
}
/*
struct ipaddr src;
/* Socket read buffer */
+#ifdef FUZZING
+ size_t fuzzing_input_size;
+ struct sockaddr_in fuzzing_sa;
+#endif
uint8_t ibuf[IP_MAXPACKET];
/*
*/
int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6);
+#ifdef FUZZING
+void vrrp_read(struct event *thread);
+#endif
+
/* State machine ----------------------------------------------------------- */
#define VRRP_STATE_INITIALIZE 0
.n_yang_modules = array_size(vrrp_yang_modules),
);
+#ifdef FUZZING
+
+int LLVMFuzzerTestOneInput(uint8_t *data, size_t size);
+
+static bool FuzzingInit(void)
+{
+ const char *name[] = { "vrrpd" };
+
+ frr_preinit(&vrrpd_di, 1, (char **) name);
+
+ master = frr_init();
+
+ access_list_init();
+ vrrp_debug_init();
+ vrrp_zebra_init();
+ vrrp_vty_init();
+ vrrp_init();
+
+
+ return true;
+}
+
+static struct vrrp_vrouter *FuzzingCreateVr(void)
+{
+ struct interface *ifp;
+ struct prefix p;
+
+ ifp = if_get_by_name("fuzziface", VRF_DEFAULT, "default");
+ ifp->mtu = 68;
+ str2prefix("11.0.2.1/24", &p);
+ connected_add_by_prefix(ifp, &p, NULL);
+
+ struct vrrp_vrouter *vr = vrrp_vrouter_create(ifp, 10, 3);
+ vr->v4->fsm.state = VRRP_STATE_MASTER;
+ vr->v6->fsm.state = VRRP_STATE_MASTER;
+
+ vrrp_debug_set(NULL, 0, CONFIG_NODE, 1, 1, 1, 1, 1, 1, 1, 1);
+
+ return vr;
+}
+
+bool FuzzingInitialized;
+struct vrrp_vrouter *FuzzingVr;
+
+int LLVMFuzzerTestOneInput(uint8_t *data, size_t size)
+{
+ if (!FuzzingInitialized) {
+ FuzzingInit();
+ FuzzingInitialized = true;
+ FuzzingVr = FuzzingCreateVr();
+ }
+
+ struct event t;
+ struct vrrp_vrouter *vr;
+
+#ifdef FUZZING_LIBFUZZER
+ vr = FuzzingVr;
+#else
+ vr = FuzzingVr;
+#endif
+
+#define FUZZING_ZAPI 0
+
+#if !FUZZING_ZAPI
+ /* set input size */
+ vr->v4->fuzzing_input_size = size;
+ /* some info to fake msghdr with */
+ memcpy(vr->v4->ibuf, data, MIN(size, sizeof(vr->v4->ibuf)));
+ vr->v4->fuzzing_sa.sin_family = AF_INET;
+ inet_pton(AF_INET, "11.0.2.3", &vr->v4->fuzzing_sa.sin_addr);
+
+ t.arg = vr->v4;
+
+ vrrp_read(&t);
+#else
+ zclient_read_fuzz(zclient, data, size);
+#endif
+
+ return 0;
+}
+
+#endif
+
+#ifndef FUZZING_LIBFUZZER
int main(int argc, char **argv, char **envp)
{
+#ifdef FUZZING
+ FuzzingInit();
+ FuzzingInitialized = true;
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif /* AFL_HAVE_MANUAL_CONTROL */
+
+ uint8_t *input;
+ int r = frrfuzz_read_input(&input);
+
+ if (r < 0)
+ return 0;
+
+ return LLVMFuzzerTestOneInput(input, r);
+#endif
frr_preinit(&vrrpd_di, argc, argv);
frr_opt_add("", longopts, "");
/* Not reached. */
return 0;
}
+#endif
\ No newline at end of file
/* Checksum check */
uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph);
+#ifndef FUZZING
VRRP_PKT_VCHECK((*pkt)->hdr.chksum == chksum,
"Bad VRRP checksum %hx; should be %hx",
(*pkt)->hdr.chksum, chksum);
-
+#endif
/* Type check */
VRRP_PKT_VCHECK(((*pkt)->hdr.vertype & 0x0F) == 1, "Bad type %u",
(*pkt)->hdr.vertype & 0x0f);
#define VRRP_LOGPFX "[ZEBRA] "
+#ifndef FUZZING
static struct zclient *zclient;
+#else
+struct zclient *zclient;
+#endif
static void vrrp_zebra_debug_if_state(struct interface *ifp, const char *func)
{
void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable)
{
+#ifdef FUZZING
+ if (!r)
+ return;
+#endif
DEBUGD(&vrrp_dbg_zebra,
VRRP_LOGPFX VRRP_LOGPFX_VRID
"Requesting Zebra to turn router advertisements %s for %s",
#include "lib/if.h"
+#ifdef FUZZING
+#include "lib/zclient.h"
+extern struct zclient *zclient;
+#endif
+
extern void vrrp_zebra_init(void);
extern void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable);
extern void vrrp_zclient_send_interface_protodown(struct interface *ifp,
#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"
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 void kernel_read(struct event *thread)
{
struct zebra_ns *zns = (struct zebra_ns *)EVENT_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);
- /*
- * status == -1 is a full on failure somewhere
- * since we don't know where the problem happened
- * we must mark all as failed
- *
- * Else we mark everything as worked
- *
- */
- if (status == -1 || status == 0) {
- while ((ctx = dplane_ctx_dequeue(&(bth->ctx_list))) !=
- NULL) {
- if (status == -1)
- dplane_ctx_set_status(
- ctx,
- ZEBRA_DPLANE_REQUEST_FAILURE);
- dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx);
- }
- return status;
- }
+ status = netlink_recv_msg(nl, &msg);
+ if (status == -1 || status == 0)
+ return status;
+
+ for (h = (struct nlmsghdr *)nl->buf;
+ (status >= 0 && NLMSG_OK(h, (unsigned int)status));
+ h = NLMSG_NEXT(h, status)) {
- h = (struct nlmsghdr *)nl->buf;
ignore_msg = false;
seq = h->nlmsg_seq;
/*
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
zns->netlink.sock = -1;
+#ifndef FUZZING
if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id) <
0) {
zlog_err("Failure to create %s socket",
}
kernel_netlink_nlsock_insert(&zns->netlink);
-
+#endif
snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name),
"netlink-cmd (NS %u)", zns->ns_id);
zns->netlink_cmd.sock = -1;
+#ifndef FUZZING
if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id) < 0) {
zlog_err("Failure to create %s socket",
zns->netlink_cmd.name);
}
kernel_netlink_nlsock_insert(&zns->netlink_cmd);
-
+#endif
/* Outbound socket for dplane programming of the host OS. */
snprintf(zns->netlink_dplane_out.name,
sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)",
zns->ns_id);
zns->netlink_dplane_out.sock = -1;
+#ifndef FUZZING
if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id) < 0) {
zlog_err("Failure to create %s socket",
zns->netlink_dplane_out.name);
}
kernel_netlink_nlsock_insert(&zns->netlink_dplane_in);
-
+#endif
+#ifndef FUZZING
/*
* SOL_NETLINK is not available on all platforms yet
* apparently. It's in bits/socket.h which I am not
/* Set receive buffer size if it's set from command line */
if (rcvbufsize) {
netlink_recvbuf(&zns->netlink, rcvbufsize);
+#ifndef FUZZING
netlink_recvbuf(&zns->netlink_cmd, rcvbufsize);
netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize);
netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize);
+#endif
}
/* Set filter for inbound sockets, to exclude events we've generated
zns->netlink_cmd.snl.nl_pid,
zns->netlink_dplane_out.snl.nl_pid);
+#endif /* FUZZING */
zns->t_netlink = NULL;
event_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock,
nlsock_hash = NULL;
}
+#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 */
bool set);
extern struct nlsock *kernel_netlink_nlsock_lookup(int sock);
+
+#ifdef FUZZING
+void netlink_fuzz(const uint8_t *data, size_t size);
+#endif
+
+
#endif /* HAVE_NETLINK */
#ifdef __cplusplus
#include "routemap.h"
#include "routing_nb.h"
+#include "fuzz.h"
+#include "frr_pthread.h"
+
#include "zebra/zebra_router.h"
#include "zebra/zebra_errors.h"
#include "zebra/rib.h"
#include "zebra/zebra_srte.h"
#include "zebra/zebra_srv6.h"
#include "zebra/zebra_srv6_vty.h"
+#include "zebra/zapi_msg.h"
+
+#ifdef FUZZING
+#include "zebra/kernel_netlink.h"
+#endif /* FUZZING */
#define ZEBRA_PTM_SUPPORT
.n_yang_modules = array_size(zebra_yang_modules),
);
+#ifdef FUZZING
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static bool FuzzingInit(void)
+{
+ graceful_restart = 0;
+ vrf_configure_backend(VRF_BACKEND_VRF_LITE);
+
+ const char *name[] = { "zebra" };
+
+ frr_preinit(&zebra_di, 1, (char **) name);
+
+ /* Zebra related initialize. */
+ zrouter.master = frr_init_fast();
+
+ zebra_router_init(false, true);
+ zserv_init();
+ rib_init();
+ zebra_if_init();
+ zebra_debug_init();
+ router_id_cmd_init();
+ zebra_ns_init();
+ zebra_vty_init();
+ access_list_init();
+ prefix_list_init();
+ zebra_mpls_init();
+ zebra_mpls_vty_init();
+ zebra_pw_vty_init();
+ zebra_pbr_init();
+ zrouter.startup_time = monotime(NULL);
+ label_manager_init();
+ zebra_rnh_init();
+ zebra_evpn_init();
+ zebra_error_init();
+ frr_pthread_init();
+
+ return true;
+}
+
+#ifndef FUZZING_LIBFUZZER
+static struct zserv *FuzzingZc;
+#endif /* FUZZING_LIBFUZZER */
+
+static struct stream_fifo *fifo;
+
+static bool FuzzingInitialized;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (!FuzzingInitialized) {
+ FuzzingInit();
+ FuzzingInitialized = true;
+ fifo = stream_fifo_new();
+ }
+
+ /*
+ * In the AFL standalone case, the client will already be created for
+ * us before __AFL_INIT() is called to speed things up. We can't pass
+ * it as an argument because the function signature must match
+ * libFuzzer's expectations.
+ *
+ * In the libFuzzer case, we need to create it each time.
+ *
+ * In both cases the client must be destroyed before we return..
+ */
+ struct zserv *zc;
+#ifdef FUZZING_LIBFUZZER
+ zc = zserv_client_create(69);
+#else
+ 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);
+
+ return 0;
+}
+#endif /* FUZZING */
+
+#ifndef FUZZING_LIBFUZZER
+
+CPP_NOTICE("Not using LibFuzzer, compiling in main symbol!")
+
/* Main startup routine. */
int main(int argc, char **argv)
{
bool asic_offload = false;
bool notify_on_ack = true;
+#ifdef FUZZING
+ FuzzingInit();
+ FuzzingZc = zserv_client_create(69);
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif /* __AFL_HAVE_MANUAL_CONTROL */
+
+ uint8_t *input = NULL;
+ int r = frrfuzz_read_input(&input);
+
+ int ret = LLVMFuzzerTestOneInput(input, r);
+
+ if (r > 0 && input) {
+ free(input);
+ }
+
+ return ret;
+#endif /* FUZZING */
+
graceful_restart = 0;
vrf_configure_backend(VRF_BACKEND_VRF_LITE);
/* Not reached... */
return 0;
}
+#endif /* FUZZING_LIBFUZZER */
\ No newline at end of file
## endif ZEBRA
endif
+zebra_zebra_LDFLAGS = $(AM_LDFLAGS) $(ZEBRA_SAN_FLAGS)
zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) $(UST_LIBS)
if HAVE_PROTOBUF3
zebra_zebra_LDADD += mlag/libmlag_pb.la $(PROTOBUF_C_LIBS)
STREAM_GETL(s, size);
STREAM_GETL(s, base);
+#ifndef FUZZING
assert(proto == client->proto && instance == client->instance);
+#endif
/* call hook to get a chunk using wrapper */
lm_get_chunk_call(&lmc, client, keep, size, base, vrf_id);
STREAM_GETL(s, start);
STREAM_GETL(s, end);
+#ifndef FUZZING
assert(proto == client->proto && instance == client->instance);
-
+#endif
/* call hook to release a chunk using wrapper */
lm_release_chunk_call(client, start, end);
ZEBRA_MAX_PACKET_SIZ);
goto continue_loop;
}
-
+#ifdef FUZZING
+ /*
+ * The stream read over in zserv_read
+ * already guarantees this conditional
+ * when we read actual packets from clients
+ * but since we are cheating there is no
+ * point in allowing a crash in the fuzzing
+ * here. So let's prevent it.
+ */
+ if (STREAM_READABLE(msg) < ZEBRA_HEADER_SIZE)
+ goto continue_loop;
+#endif
zapi_parse_header(msg, &hdr);
+#ifdef FUZZING
+ /*
+ * The stream read over in zserv_read
+ * already guarantees the sizing of the packet
+ * before it can even be enqueued but FUZZING
+ * is cheating and calling this function directly
+ * Let's cut to the chase and prevent a crash
+ * because we have a funny header size -vs-
+ * what we can read.
+ */
+ if (STREAM_SIZE(msg) != hdr.length)
+ goto continue_loop;
+#endif
+
if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV
&& IS_ZEBRA_DEBUG_DETAIL)
if (stale_client) {
LOG_GR("%s: Stale client %s exist, we should not be here!",
__func__, zebra_route_string(client->proto));
+#ifndef FUZZING
assert(0);
+#endif
}
client->restart_time = monotime(&tv);
/* For all the GR instance start the stale removal timer. */
+#ifdef FUZZING
+ struct client_gr_info dupinfo = {};
+#endif
TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)
&& (info->t_stale_removal == NULL)) {
__func__, zebra_route_string(client->proto),
VRF_LOGNAME(vrf), info->vrf_id,
info->stale_removal_time);
+
+ dupinfo = *info;
+#ifdef FUZZING
+ // yeah, that thread will never execute...clean it up now
+ //struct thread t = {};
+ struct event t = {};
+ t.arg = info;
+ info->t_stale_removal = &t;
+ zebra_gr_route_stale_delete_timer_expiry(&t);
+ info = &dupinfo;
+#endif
}
}
-
+#ifndef FUZZING
listnode_add(zrouter.stale_client_list, client);
-
+#endif
return 0;
}
static void zebra_mlag_spawn_pthread(void)
{
/* Start MLAG write pthread */
+#ifdef FUZZING
+ return;
+#endif
struct frr_pthread_attr pattr = {.start =
frr_pthread_attr_default.start,
if (IS_ZEBRA_DEBUG_MLAG)
zlog_debug(
"First client, opening the channel with MLAG");
-
+#ifndef FUZZING
zebra_mlag_spawn_pthread();
+#endif
rc = hook_call(zebra_mlag_private_open_channel);
if (rc < 0) {
/*
static void zserv_client_event(struct zserv *client,
enum zserv_client_event event)
{
+#ifdef FUZZING
+ return;
+#endif
switch (event) {
case ZSERV_CLIENT_READ:
event_add_read(client->pthread->master, zserv_read, client,
int zserv_send_message(struct zserv *client, struct stream *msg)
{
+#ifdef FUZZING
+ stream_free(msg);
+ return 0;
+#endif
frr_with_mutex (&client->obuf_mtx) {
stream_fifo_push(client->obuf_fifo, msg);
}
unsigned long nroutes;
unsigned long nnhgs;
+#ifndef FUZZING
close(client->sock);
+#endif
if (DYNAMIC_CLIENT_GR_DISABLED(client)) {
zebra_mpls_client_cleanup_vrf_label(client->proto);
if (client->wb)
buffer_free(client->wb);
+#ifndef FUZZING
/* Free buffer mutexes */
pthread_mutex_destroy(&client->stats_mtx);
pthread_mutex_destroy(&client->obuf_mtx);
pthread_mutex_destroy(&client->ibuf_mtx);
+#endif
/* Free bitmaps. */
for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
bool free_p = true;
if (client->pthread) {
+#ifndef FUZZING
/* synchronously stop and join pthread */
frr_pthread_stop(client->pthread, NULL);
/* destroy pthread */
frr_pthread_destroy(client->pthread);
client->pthread = NULL;
+#endif
}
/*
* sock
* client's socket file descriptor
*/
-static struct zserv *zserv_client_create(int sock)
+struct zserv *zserv_client_create(int sock)
{
struct zserv *client;
size_t stream_size =
client->ibuf_work = stream_new(stream_size);
client->obuf_work = stream_new(stream_size);
client->connect_time = monotime(NULL);
+#ifndef FUZZING
pthread_mutex_init(&client->ibuf_mtx, NULL);
pthread_mutex_init(&client->obuf_mtx, NULL);
pthread_mutex_init(&client->stats_mtx, NULL);
+#endif
client->wb = buffer_new(0);
TAILQ_INIT(&(client->gr_info_queue));
listnode_add(zrouter.client_list, client);
}
+#ifndef FUZZING
struct frr_pthread_attr zclient_pthr_attrs = {
.start = frr_pthread_attr_default.start,
.stop = frr_pthread_attr_default.stop
/* start read loop */
zserv_client_event(client, ZSERV_CLIENT_READ);
+#endif
/* call callbacks */
hook_call(zserv_client_connect, client);
/* start pthread */
+#ifndef FUZZING
frr_pthread_run(client->pthread, NULL);
+#endif
return client;
}
void zserv_event(struct zserv *client, enum zserv_event event)
{
+#ifdef FUZZING
+ return;
+#endif
switch (event) {
case ZSERV_ACCEPT:
event_add_read(zrouter.master, zserv_accept, NULL, zsock, NULL);
struct stream *msg,
struct zebra_vrf *zvrf);
+#ifdef FUZZING
+struct zserv *zserv_client_create(int sock);
+#endif
+
+
+
#ifdef __cplusplus
}
#endif