]> git.puffer.fish Git - matthieu/frr.git/commitdiff
*: enable fuzzing
authorIggy Frankovic <iggyfran@amazon.com>
Fri, 25 Aug 2023 15:38:49 +0000 (08:38 -0700)
committerDonald Sharp <sharpd@nvidia.com>
Mon, 11 Sep 2023 11:51:29 +0000 (07:51 -0400)
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>
72 files changed:
bgpd/bgp_fsm.c
bgpd/bgp_io.c
bgpd/bgp_io.h
bgpd/bgp_keepalives.c
bgpd/bgp_main.c
bgpd/bgp_packet.c
bgpd/bgpd.c
bgpd/subdir.am
configure.ac
lib/checksum.c
lib/command.c
lib/frrevent.h
lib/fuzz.h [new file with mode: 0644]
lib/graph.c
lib/if.c
lib/if.h
lib/jhash.c
lib/libfrr.c
lib/libfrr.h
lib/memory.c
lib/memory.h
lib/prefix.c
lib/printf/vfprintf.c
lib/privs.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
lib/zlog.h
ospfd/ospf_lsa.c
ospfd/ospf_main.c
ospfd/ospf_neighbor.c
ospfd/ospf_network.c
ospfd/ospf_nsm.h
ospfd/ospf_packet.c
ospfd/ospf_packet.h
ospfd/ospfd.h
ospfd/subdir.am
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_ifchannel.h
pimd/pim_igmp.c
pimd/pim_igmpv3.c
pimd/pim_instance.c
pimd/pim_instance.h
pimd/pim_main.c
pimd/pim_mlag.c
pimd/pim_mroute.c
pimd/pim_mroute.h
pimd/pim_neighbor.c
pimd/pim_pim.c
pimd/pim_register.c
pimd/pim_rp.c
pimd/pim_tlv.h
pimd/pim_upstream.h
pimd/pimd.c
pimd/subdir.am
vrrpd/subdir.am
vrrpd/vrrp.c
vrrpd/vrrp.h
vrrpd/vrrp_main.c
vrrpd/vrrp_packet.c
vrrpd/vrrp_zebra.c
vrrpd/vrrp_zebra.h
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/main.c
zebra/subdir.am
zebra/zapi_msg.c
zebra/zebra_gr.c
zebra/zebra_mlag.c
zebra/zserv.c
zebra/zserv.h

index cdb3ead16093be3bae8fba72ddad442edbca8e32..efec39151313d37dbc6326623e9fad89fc1394f0 100644 (file)
@@ -3,6 +3,7 @@
  * From RFC1771 [A Border Gateway Protocol 4 (BGP-4)]
  * Copyright (C) 1996, 97, 98 Kunihiro Ishiguro
  */
+#define FUZZING 1
 
 #include <zebra.h>
 
@@ -354,6 +355,9 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
    structure. */
 void bgp_timer_set(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        afi_t afi;
        safi_t safi;
 
index a375bd6005889adeb431cadce66b8622b0a91664..90bf7f115d16a6fcbb600186f0333a14b872c265 100644 (file)
@@ -33,7 +33,7 @@ static uint16_t bgp_write(struct peer *);
 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 */
@@ -44,6 +44,9 @@ static bool validate_header(struct peer *);
 
 void bgp_writes_on(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        struct frr_pthread *fpt = bgp_pth_io;
        assert(fpt->running);
 
@@ -62,6 +65,9 @@ void bgp_writes_on(struct peer *peer)
 
 void bgp_writes_off(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        struct frr_pthread *fpt = bgp_pth_io;
        assert(fpt->running);
 
@@ -73,6 +79,9 @@ void bgp_writes_off(struct peer *peer)
 
 void bgp_reads_on(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        struct frr_pthread *fpt = bgp_pth_io;
        assert(fpt->running);
 
@@ -93,6 +102,9 @@ void bgp_reads_on(struct peer *peer)
 
 void bgp_reads_off(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        struct frr_pthread *fpt = bgp_pth_io;
        assert(fpt->running);
 
@@ -546,7 +558,7 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
  * 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;
index 4c92373c2db4b808e05c9146fe29bd06ba267eb2..ce398ddf6836e7d3ecb3dbb6bddd57f207daad4e 100644 (file)
@@ -14,6 +14,8 @@
 #include "bgpd/bgpd.h"
 #include "frr_pthread.h"
 
+bool validate_header(struct peer *p);
+
 /**
  * Start function for write thread.
  *
index 48bde1220d6c5abfae774d43c72ce03d0f5d2546..ed5eda61d96ef128238c439c9da938f42a96fc7e 100644 (file)
@@ -231,6 +231,9 @@ void *bgp_keepalives_start(void *arg)
 
 void bgp_keepalives_on(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
                return;
 
@@ -260,6 +263,9 @@ void bgp_keepalives_on(struct peer *peer)
 
 void bgp_keepalives_off(struct peer *peer)
 {
+#ifdef FUZZING
+       return;
+#endif
        if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
                return;
 
index 074059c1461d4ce965474944f81ba66548788b3e..72722b19da938dc8eae402ae42ff9e47c999fd42 100644 (file)
@@ -28,6 +28,7 @@
 #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"
@@ -367,6 +368,168 @@ FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT,
 
 #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)
@@ -383,10 +546,29 @@ 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"
@@ -507,3 +689,4 @@ int main(int argc, char **argv)
        /* Not reached. */
        return 0;
 }
+#endif /* FUZZING_LIBFUZZER */
\ No newline at end of file
index ec692277b26be363d73171f31710a74c23dfe2d3..8fd262fd97b5fcb2e03129933cf5bf6b352dbdc6 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2017 Cumulus Networks
  * Copyright (C) 1999 Kunihiro Ishiguro
  */
+#define FUZZING 1
 
 #include <zebra.h>
 #include <sys/time.h>
@@ -721,6 +722,7 @@ void bgp_open_send(struct peer *peer)
  * @param peer
  * @return 0
  */
+#ifndef FUZZING
 static void bgp_write_notify(struct peer *peer)
 {
        int ret, val;
@@ -780,6 +782,7 @@ static void bgp_write_notify(struct peer *peer)
 
        stream_free(s);
 }
+#endif
 
 /*
  * Encapsulate an original BGP CEASE Notification into Hard Reset
@@ -1034,7 +1037,9 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
        BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
                                                          peer->bgp->peer);
 
+#ifndef FUZZING
        bgp_write_notify(peer);
+#endif
 }
 
 /*
@@ -1608,12 +1613,14 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
                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;
@@ -1741,7 +1748,9 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
 #endif
                }
        }
+#ifndef FUZZING
        peer->rtt = sockopt_tcp_rtt(peer->fd);
+#endif
 
        return Receive_OPEN_message;
 }
@@ -2893,10 +2902,11 @@ void bgp_process_packet(struct event *thread)
                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;
 
@@ -3001,6 +3011,9 @@ void bgp_process_packet(struct event *thread)
                /* delete processed packet */
                stream_free(peer->curr);
                peer->curr = NULL;
+#ifdef FUZZING
+               return;
+#endif
                processed++;
 
                /* Update FSM */
index 0c72b2fb303c202516e183bd70f9101b9e72b585..c4225cd550c468c586a4c832860375a91d327564 100644 (file)
@@ -1419,7 +1419,11 @@ struct peer *peer_new(struct bgp *bgp)
                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);
@@ -8248,35 +8252,42 @@ void bgp_init(unsigned short instance)
 
        /* 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);
@@ -8295,14 +8306,14 @@ void bgp_init(unsigned short instance)
        /* 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)
index c2dd207a49d19471a59fbc3b55366075306e1b3b..1e166943da99f137ff044c77eaca117d887e3e50 100644 (file)
@@ -186,6 +186,10 @@ noinst_HEADERS += \
 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)
index a0819a1f221f65e77d04ec7b4ad243d408e7ecb8..7cbfa65fc19a8c7a7e076b7cbeab5d6151959de7 100644 (file)
@@ -353,7 +353,7 @@ AC_C_FLAG([-fms-extensions], [
 ])
 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])
@@ -423,7 +423,26 @@ if test "$enable_undefined_sanitizer" = "yes"; then
     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
@@ -763,6 +782,8 @@ AC_ARG_ENABLE([memory-sanitizer],
   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],
index 6c5f06de458a4f7e0c411d9a1036db46378fd4df..bead7999698800358e994c6caae6f33af8c21c4c 100644 (file)
@@ -21,6 +21,7 @@ uint16_t in_cksumv(const struct iovec *iov, size_t iov_len)
 {
        const struct iovec *iov_end;
        uint32_t sum = 0;
+       register unsigned short answer; /* assumes unsigned short == 16 bits */
 
        union {
                uint8_t bytes[2];
@@ -78,7 +79,9 @@ uint16_t in_cksumv(const struct iovec *iov, size_t iov_len)
 
        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. */
@@ -90,6 +93,7 @@ uint16_t in_cksumv(const struct iovec *iov, size_t iov_len)
    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;
index 8025ab534fcfb012e9587dac0089195f295f4cd6..edc964b9d5a01c48de0bf85497ddff9dc60631ec 100644 (file)
@@ -8,6 +8,7 @@
  * 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>
@@ -284,6 +285,9 @@ void cmd_defer_tree(bool val)
 /* 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 */
index 2b0c52bb51eb75d8673f2f85727be949dc212ac6..16ed12038f6a7e1ab4f2de7be7d60d5f57ee074b 100644 (file)
@@ -185,6 +185,8 @@ struct cpu_event_history {
                _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)
@@ -207,6 +209,18 @@ struct cpu_event_history {
                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);
diff --git a/lib/fuzz.h b/lib/fuzz.h
new file mode 100644 (file)
index 0000000..5a80430
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+* 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
index e6c2386d7537ed51356b66a2e38ea8f01edf2fb2..fc1c5853a023b2e4ba98a464dbbf1cb5630a3f1e 100644 (file)
@@ -21,6 +21,7 @@ struct graph *graph_new(void)
 }
 
 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));
@@ -60,6 +61,7 @@ static void graph_vector_remove(vector v, unsigned int ix)
 }
 
 void graph_delete_node(struct graph *graph, struct graph_node *node)
+       __attribute__((no_sanitize("unsigned-integer-overflow")))
 {
        if (!node)
                return;
@@ -107,6 +109,7 @@ struct graph_node *graph_add_edge(struct graph_node *from,
 }
 
 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--; /**/)
@@ -123,6 +126,7 @@ void graph_remove_edge(struct graph_node *from, struct graph_node *to)
 }
 
 struct graph_node *graph_find_node(struct graph *graph, void *data)
+       __attribute__((no_sanitize("unsigned-integer-overflow")))
 {
        struct graph_node *g;
 
@@ -136,6 +140,7 @@ struct graph_node *graph_find_node(struct graph *graph, void *data)
 }
 
 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)
@@ -147,6 +152,7 @@ bool graph_has_edge(struct graph_node *from, struct graph_node *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++) {
index 6f567861d19ca9d7d8de97eb46c5568438b2ab24..aad2da744a764f8244104c1861a2d91747782e95 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -208,7 +208,10 @@ void if_down_via_zapi(struct interface *ifp)
                (*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;
 
index c6b4fd216a371252c9391c0bccab48d17c9d7373..c74d450f2a11f0bc827bedd43706ee17b84b373a 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -619,6 +619,10 @@ extern void if_destroy_via_zapi(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
index 0d561ef3a4f25db2b60725e9fdb63a0ff2b6af45..2627d6bfa9232b3c4f93889e326282930d7ef97a 100644 (file)
@@ -60,6 +60,7 @@
  * 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;
@@ -127,6 +128,7 @@ uint32_t jhash(const void *key, uint32_t length, uint32_t initval)
  * 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;
 
@@ -166,6 +168,7 @@ uint32_t jhash2(const uint32_t *k, uint32_t length, uint32_t initval)
  *       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;
index 33237df5fca3a28b3f3bc6ba138d4f7c254407a7..34216cb2811f23a061acf2404aed368986644432 100644 (file)
 #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));
@@ -813,6 +821,131 @@ struct event_loop *frr_init(void)
        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;
index b260a54dfeb1e2e8896129583b9aa1a96093b5ab..a881d7bd05e596e38de19bc236688d59b18340f2 100644 (file)
@@ -138,6 +138,9 @@ extern int frr_getopt(int argc, char *const argv[], int *longindex);
 
 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);
index 8fbe5c4093660aa50add589b1de92bd20f3e4c8d..4fb7746b6d358722bd91ed02b116b32c090157fb 100644 (file)
@@ -27,6 +27,10 @@ DEFINE_MGROUP(LIB, "libfrr");
 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;
index ba437ebd0ed92ffe422ae278cb1fc4539e9a87db..87d04eede3f301c04c2977dbb8c26dd87c4cdfae 100644 (file)
 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
index b8cad910f423e825b65add7138c78839380a2f44..4ecf0e934456d9ac315dcf1e1ac15c20c4f59e27 100644 (file)
@@ -677,7 +677,8 @@ void masklen2ip(const int masklen, struct in_addr *netmask)
         * 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);
index cc886834faf65ccb83a141d4374e08002b02ffb4..40bad6b00f9d2b8ab53f7967957b63c056754805 100644 (file)
@@ -146,8 +146,8 @@ __wcsconv(wchar_t *wcsarg, int prec)
 /*
  * 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 */
@@ -453,7 +453,7 @@ reswitch:   switch (ch) {
                        if (flags & INTMAX_SIZE)
                                ujval = SJARG();
                        else
-                               ulval = SARG();
+                               ulval = (u_long)SARG();
 
                        if (printfrr_ext_char(fmt[0])) {
                                struct printfrr_eargs ea = {
@@ -483,7 +483,7 @@ reswitch:   switch (ch) {
                                }
                        } else {
                                if ((long)ulval < 0) {
-                                       ulval = -ulval;
+                                       ulval = (~ulval) + 1;
                                        sign = '-';
                                }
                        }
index accd9895ffec5fea65a93745429836a05639f94c..ccba48e5bd5651cc9deadd94a0df713b195b3968 100644 (file)
@@ -288,6 +288,7 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
        /* 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,
@@ -296,7 +297,7 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
                        exit(1);
                }
        }
-
+#endif
        if (!(zprivs_state.caps = cap_init())) {
                fprintf(stderr, "privs_init: failed to cap_init, %s\n",
                        safe_strerror(errno));
@@ -326,6 +327,7 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
        /* 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;
@@ -352,7 +354,7 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
 
                exit(1);
        }
-
+#endif
        /* set methods for the caller to use */
        zprivs->change = zprivs_change_caps;
        zprivs->current_state = zprivs_state_caps;
@@ -478,6 +480,9 @@ static struct zebra_privs_refs_t *get_privs_refs(struct zebra_privs_t *privs)
 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;
 
@@ -508,6 +513,9 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
 
 void _zprivs_lower(struct zebra_privs_t **privs)
 {
+#ifdef FUZZING
+       return;
+#endif
        int save_errno = errno;
        struct zebra_privs_refs_t *refs;
 
@@ -550,6 +558,12 @@ void zprivs_preinit(struct zebra_privs_t *zprivs)
        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. */
@@ -652,6 +666,7 @@ void zprivs_init(struct zebra_privs_t *zprivs)
 
        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",
@@ -669,6 +684,7 @@ void zprivs_init(struct zebra_privs_t *zprivs)
                        exit(1);
                }
        }
+#endif
 
 #ifdef HAVE_CAPABILITIES
        zprivs_caps_init(zprivs);
@@ -702,9 +718,10 @@ void zprivs_init(struct zebra_privs_t *zprivs)
                        exit(1);
                }
        }
-
+#ifndef FUZZING
        zprivs->change = zprivs_change_uid;
        zprivs->current_state = zprivs_state_uid;
+#endif
 #endif /* HAVE_CAPABILITIES */
 }
 
index 8526cbfaa1cea424f956fa2d36b581cb0f318232..34595b5e38b9e7428e11a62784b65e05a07c9ee2 100644 (file)
@@ -4030,6 +4030,73 @@ static zclient_handler *const lib_handlers[] = {
        [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)
 {
index e43393fd70e741431078f2e743e17bb025acd386..fdd61831dd7b7ae5355b852b387cf5f38f86c83c 100644 (file)
@@ -7,6 +7,7 @@
 #define _ZEBRA_ZCLIENT_H
 
 struct zclient;
+#define FUZZING 1
 
 /* For struct zapi_route. */
 #include "prefix.h"
@@ -1251,6 +1252,10 @@ struct zapi_client_close_info {
        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);
index ecc87f58f10fab7214721c3c366f13794a41c91a..1b2b3c8a92b5ad53a2e78cca30ae548fdd0ffeb5 100644 (file)
@@ -6,6 +6,13 @@
 #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>
 
index a207b29a3b6daa40b773ec73362f31c6e31601e3..3a1c4329e068d7a06ad04534b69364641c74e6ef 100644 (file)
@@ -109,6 +109,8 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
                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__)
@@ -123,6 +125,20 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
 #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 */
index 67f1faf8a9abf948afbec5595f63bf2446f4b21e..8fb271d16c04d39d6d75fd92a8d97ab27bb730fd 100644 (file)
@@ -3003,7 +3003,8 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi,
            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);
 
@@ -3969,6 +3970,9 @@ void ospf_schedule_lsa_flood_area(struct ospf_area *area, struct ospf_lsa *lsa)
        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)
@@ -3981,6 +3985,9 @@ 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
 }
 
 
index 1f476a7e3d63651114c282af7e60d369643c4e24..9d57007ca6111e6627fddddfe029106a10f274f1 100644 (file)
 #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"
@@ -134,9 +139,136 @@ FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT,
                .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;
@@ -222,3 +354,4 @@ int main(int argc, char **argv)
        /* Not reached. */
        return 0;
 }
+#endif
\ No newline at end of file
index c238f051dfeb754d2963fceface4e9f58aab6927..61faedc5ad8e0a24c5309f589659f9d8806eb400 100644 (file)
@@ -439,19 +439,20 @@ static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi,
                        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);
 
index aff8ed05c723542ed1118ce70c20799695ace683..157f45b069659ffcb4d9464b79dc933cdc111220 100644 (file)
@@ -238,6 +238,9 @@ void ospf_sock_bufsize_update(const struct ospf *ospf, int sock,
 
 int ospf_sock_init(struct ospf *ospf)
 {
+#ifdef FUZZING
+       return 0;
+#endif
        int ret;
 
        /* silently ignore. already done */
index 9973b4870d335a8c1890226816e1253938204a74..d2d49a6dafcad88afc587998d7f05b59218f31ed 100644 (file)
 #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))
index d010b8b6e60bd820d9b5aee3ef020d34e1f6aaeb..6097bffc8f40a0e40366361db4a306da019d13b4 100644 (file)
@@ -1644,6 +1644,7 @@ static void ospf_ls_req(struct ip *iph, struct ospf_header *ospfh,
                /* 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);
@@ -1668,9 +1669,13 @@ static void ospf_ls_req(struct ip *iph, struct ospf_header *ospfh,
                /* 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) {
@@ -2316,8 +2321,11 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd,
        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",
@@ -2493,7 +2501,9 @@ static int ospf_check_auth(struct ospf_interface *oi, struct ospf_header *ospfh)
                                        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))
@@ -2502,7 +2512,9 @@ static int ospf_check_auth(struct ospf_interface *oi, struct ospf_header *ospfh)
                                        "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 */
@@ -2956,12 +2968,7 @@ static int ospf_verify_header(struct stream *ibuf, struct ospf_interface *oi,
        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;
@@ -2972,8 +2979,13 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
        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;
 
@@ -3182,6 +3194,20 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
        /* 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) {
index 234738979e95852213ec6204b18a1cec21f4ac39..6044c93d86471b5dc87c831c7a20f4f81892710d 100644 (file)
@@ -150,4 +150,13 @@ extern const size_t ospf_packet_type_str_max;
 
 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 */
index 36936b16f4ab7f82a27ff33ab59bd2e179d5335c..c16f649faa2b64dd9ae80edf691b74314cd981e6 100644 (file)
@@ -159,6 +159,10 @@ struct ospf {
         * config. */
        uint8_t oi_running;
 
+#ifdef FUZZING
+       struct interface *fuzzing_packet_ifp;
+#endif
+
        /* OSPF instance ID  */
        unsigned short instance;
 
index 44ee3b0f13a957320bff37b98a9b7afd38cf82ba..976e4b25290913a4a5611b11882c2b75ab4095d1 100644 (file)
@@ -108,6 +108,7 @@ noinst_HEADERS += \
        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
 
index cc1ca77d65d6044a274bf035c7b27a94e2566d54..2f5e2efe377d26b364f2aab3c52c88ff15e2c6f1 100644 (file)
@@ -1549,8 +1549,10 @@ int pim_if_ifchannel_count(struct pim_interface *pim_ifp)
 
        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;
 
@@ -1620,7 +1622,10 @@ static int pim_ifp_create(struct interface *ifp)
        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;
@@ -1676,7 +1681,10 @@ static int pim_ifp_up(struct interface *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(
@@ -1711,8 +1719,10 @@ static int pim_ifp_down(struct interface *ifp)
 
        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(
index 973840a75385e326876e7532152410134b8fd098..58888eb17aa7f60b6eb5268b1d1cd1e1f9b8312a 100644 (file)
@@ -244,4 +244,11 @@ int pim_if_ifchannel_count(struct pim_interface *pim_ifp);
 
 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 */
index 4b0ff955f9d8ac820f88e49ebfe16d4a73cfae25..10520410bf5e79badf1be01545fb46280e8989a8 100644 (file)
@@ -33,30 +33,37 @@ enum pim_ifjoin_state {
 */
 #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)
 /*
@@ -65,9 +72,9 @@ enum pim_ifjoin_state {
 #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
 */
index 063ba6edd2754d8a784f633fa34b579ecf5e20e4..6d66a7944a8ffe49113594f9e25effc4d2125faa 100644 (file)
@@ -1255,12 +1255,16 @@ struct gm_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
        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;
index 15078dd1ecd2bde09039315422bcb0db74baa0d3..92e27675029a4379dea1f396337a12ff9eb8f26f 100644 (file)
@@ -314,8 +314,9 @@ static void group_exclude_fwd_anysrc_ifempty(struct gm_group *group)
 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);
 }
 
@@ -580,7 +581,9 @@ static void isex_excl(struct gm_group *group, int num_sources,
                         * (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 */
@@ -633,7 +636,9 @@ static void isex_incl(struct gm_group *group, int num_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 */
@@ -831,6 +836,9 @@ static void toex_incl(struct gm_group *group, int num_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) */
@@ -896,8 +904,9 @@ static void toex_excl(struct gm_group *group, int num_sources,
                        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));
                }
@@ -1399,7 +1408,9 @@ static void block_excl(struct gm_group *group, int num_sources,
                        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) {
@@ -1892,9 +1903,11 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
 
        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 */
index 6f33af06011e80681c0091c9c80161efb354b261..12cb9506378d3fc17596b7d4e5028732258146cd 100644 (file)
@@ -116,9 +116,11 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf)
 
        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;
@@ -197,7 +199,7 @@ static int pim_vrf_disable(struct vrf *vrf)
        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;
@@ -223,8 +225,9 @@ static int pim_vrf_config_write(struct vty *vty)
 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)
index 11577ae46d01cead5e588f670f13497c79d03e98..e114ecd26a8a605cb7daf98360b4102f50452580 100644 (file)
@@ -96,7 +96,7 @@ struct pim_router {
        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;
 };
index 7db0a7676b2ec84e2b666d5585c2840903b27e54..228e96e937386e12d1f2565c459974c640372900 100644 (file)
 #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}};
@@ -81,10 +90,146 @@ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT,
                .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 */
@@ -101,6 +246,7 @@ int main(int argc, char **argv, char **envp)
                        break;
                default:
                        frr_help_exit(1);
+                       break;
                }
        }
 
@@ -164,3 +310,4 @@ int main(int argc, char **argv, char **envp)
        /* never reached */
        return 0;
 }
+#endif /* FUZZING_LIBFUZZER */
\ No newline at end of file
index 5d72eb65813c7b7d1a5273b331e20a82a433c97e..a557f1137a2444811acc09945290d72a86876227 100644 (file)
@@ -887,10 +887,9 @@ int pim_zebra_mlag_process_up(ZAPI_CALLBACK_ARGS)
 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;
index b64fcdeb87237a14aadcda71c5c9544f13ae3543..73a7d8de548a72846c6c7661cb80456ed1e47224 100644 (file)
@@ -824,6 +824,7 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
 
        frr_with_privs(&pimd_privs) {
 
+#ifndef FUZZING
 #if PIM_IPV == 4
                fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
 #else
@@ -835,7 +836,11 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
                                  safe_strerror(errno));
                        return -2;
                }
+#else
+               fd = 69;
+#endif
 
+#ifndef FUZZING
 #if PIM_IPV == 6
                struct icmp6_filter filter[1];
                int ret;
@@ -856,6 +861,9 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
                                "(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
@@ -871,6 +879,7 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
        }
 
        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",
@@ -883,6 +892,7 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
        pim->mroute_socket_creation = pim_time_monotonic_sec();
 
        mroute_read_on(pim);
+#endif
 
        return 0;
 }
@@ -955,8 +965,13 @@ int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
 #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",
index 8706f42206bd23d52ec88373d15d3b737ca88e34..124a15d9857c75f82d7960b5b66225a221a0a668 100644 (file)
@@ -100,6 +100,8 @@ typedef struct sioc_sg_req pim_sioc_sg_req;
 #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 */
@@ -134,7 +136,6 @@ typedef struct sioc_sg_req6 pim_sioc_sg_req;
 /*
   Above: from <linux/mroute.h>
 */
-
 struct channel_oil;
 struct pim_instance;
 
index 1cd7cce086fb6680f3ac59d78a54ee763f55732d..5e9689b6b97f280e2ef2e9eb974eb354fedbe503 100644 (file)
@@ -589,14 +589,16 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
                               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
index a4c9178bb9fc998721387c2de775e28b8cedb7ce..e3ce8be1a8003485ff261d2d8ab977df20bd63fd 100644 (file)
@@ -164,6 +164,19 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
        }
 
        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;
@@ -241,8 +254,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
                                                "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
                                                ifp->name, pim_checksum,
                                                checksum);
-
+#ifndef FUZZING
                                return -1;
+#endif
                        }
                }
        } else {
@@ -252,8 +266,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
                                zlog_debug(
                                        "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
                                        ifp->name, pim_checksum, checksum);
-
+#ifndef FUZZING
                        return -1;
+#endif
                }
        }
 
index 9696a76fc5aea0d28530fa3cf9d739dcaa9832ce..6b058beeda07613d1e82f2713c5e9fa7e610d1d2 100644 (file)
@@ -505,6 +505,11 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
        }
 
 #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)) {
index c7516242f5ca3482deeba0b924799e592c0d92b6..27b7044a04d4c37b88bdb0bc151ba9ffe85e8ee2 100644 (file)
@@ -804,6 +804,9 @@ int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
                        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);
index ea2af6457dde5de7aa5a8b750ed7d9582ade78e3..28c802f3c0443f28430c2451fa62e331a30e37b1 100644 (file)
@@ -31,8 +31,10 @@ typedef uint32_t pim_hello_options;
 #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)                                                \
index 4e0926e29483370308394b9bf4bb0eaa1e20ce97..4debad1be97215f4009d3bd0c5db376a23b43706 100644 (file)
 #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
index db619748000ee3ddb95f2bff2402e859ae87ec77..977c8a9c644648cd76d7578e8e2a19df045fe2c0 100644 (file)
@@ -85,7 +85,7 @@ void pim_router_init(void)
        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;
 
index 9a7901ec3fbf572230778c0ea29cec1d0f5ac007..c50c81d0e75e0c47a498564a8ab1ec5696eb98ef 100644 (file)
@@ -162,11 +162,13 @@ clippy_scan += \
 
 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
index 03b404261197d1edddcac80a875fb36b874e8479..2303e4d956b178c602d6521b19e00650d0447a35 100644 (file)
@@ -35,6 +35,7 @@ clippy_scan += \
        # 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
index 7a779307d94c89865835bfa2e73b356aa1939ed9..d2369c85d75c5b0b2ec5374ae54eef7518e1032d 100644 (file)
@@ -976,7 +976,10 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
 /*
  * 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);
 
@@ -1001,6 +1004,7 @@ static void vrrp_read(struct event *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))) {
@@ -1011,6 +1015,10 @@ static void vrrp_read(struct event *thread)
                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,
@@ -1037,9 +1045,10 @@ static void vrrp_read(struct event *thread)
 
 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
 }
 
 /*
index 0ac9b1f49c1a0ec9fb95bf136dd26263ecc43833..8d9190743cd45b5639e33c38c559867f4477bc96 100644 (file)
@@ -100,6 +100,10 @@ struct vrrp_router {
        struct ipaddr src;
 
        /* Socket read buffer */
+#ifdef FUZZING
+       size_t fuzzing_input_size;
+       struct sockaddr_in fuzzing_sa;
+#endif
        uint8_t ibuf[IP_MAXPACKET];
 
        /*
@@ -461,6 +465,10 @@ int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4);
  */
 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
index 5245c74689241fb1d4180fd69184115674043f46..06a33adc3aa9a450d0556700e2b0bc2a0b6b745a 100644 (file)
@@ -118,8 +118,108 @@ FRR_DAEMON_INFO(vrrpd, VRRP, .vty_port = VRRP_VTY_PORT,
                .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, "");
 
@@ -157,3 +257,4 @@ int main(int argc, char **argv, char **envp)
        /* Not reached. */
        return 0;
 }
+#endif
\ No newline at end of file
index 36494c7df8b704ed536277ee281f0049aa2d3dcf..e1e203b007cf1bc475f20e20489a50eb920c02de 100644 (file)
@@ -281,10 +281,11 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
        /* 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);
index 6d753d2e47649178fc21fd8e312ed7011c5b38fd..2bf6ddefe086df074e90d3c3ef629f10a47387e9 100644 (file)
 
 #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)
 {
@@ -157,6 +161,10 @@ static int vrrp_zebra_if_address_del(int command, struct zclient *client,
 
 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",
index 5e59256e1d87f2c82309971b308644402734d606..e4537d3f8510e5302e8b4b754957653eb07fb38b 100644 (file)
 
 #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,
index 78b1dfe27633039f3c515d01883d42abb49f587b..8864685a02b0d0073385392fc48f74edd87c5f08 100644 (file)
@@ -5,6 +5,12 @@
 
 #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"
@@ -482,6 +488,36 @@ static int dplane_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;
+
+/**
+ * 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);
@@ -998,6 +1034,11 @@ static int netlink_recv_msg(struct nlsock *nl, struct msghdr *msg)
 #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;
 }
 
@@ -1304,33 +1345,14 @@ static int nl_batch_read_resp(struct nl_batch *bth)
        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;
                /*
@@ -1802,6 +1824,7 @@ void kernel_init(struct zebra_ns *zns)
        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",
@@ -1810,10 +1833,11 @@ void kernel_init(struct zebra_ns *zns)
        }
 
        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);
@@ -1821,12 +1845,13 @@ void kernel_init(struct zebra_ns *zns)
        }
 
        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);
@@ -1848,7 +1873,8 @@ void kernel_init(struct zebra_ns *zns)
        }
 
        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
@@ -1922,9 +1948,11 @@ void kernel_init(struct zebra_ns *zns)
        /* 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
@@ -1937,6 +1965,7 @@ void kernel_init(struct zebra_ns *zns)
                               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,
@@ -1997,4 +2026,18 @@ void kernel_router_terminate(void)
        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 */
index 446c860327028198957b17a425cfb1d378a07918..74110cad8c39cc602c4126ed0ebd337c1717bb7c 100644 (file)
@@ -171,6 +171,12 @@ extern void netlink_set_batch_buffer_size(uint32_t size, uint32_t threshold,
                                          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
index bd4623be555607ef0105a7f3d765f2270e6fd73a..e62614751c882254edb476e3fe13a83f6189893e 100644 (file)
@@ -22,6 +22,9 @@
 #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
 
@@ -279,6 +287,101 @@ FRR_DAEMON_INFO(
        .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)
 {
@@ -289,6 +392,26 @@ 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);
 
@@ -474,3 +597,4 @@ int main(int argc, char **argv)
        /* Not reached... */
        return 0;
 }
+#endif /* FUZZING_LIBFUZZER */
\ No newline at end of file
index 1060e38785326aa911a1815fcfa4d5a6917f5134..d19aa65fd99d9f4c5f0521b6fa6d1b76d7328790 100644 (file)
@@ -28,6 +28,7 @@ man8 += $(MANBUILD)/frr-zebra.8
 ## 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)
index 1d0984323915d5240575340f71c7324d69896509..60a331f53154f4ad87bff32ee4daa29e549cd63a 100644 (file)
@@ -2806,7 +2806,9 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
        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);
@@ -2831,8 +2833,9 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg)
        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);
 
@@ -3961,8 +3964,33 @@ void zserv_handle_commands(struct zserv *client, struct stream_fifo *fifo)
                                        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)
index cf2056b7acfd1cfd89088417bc2bddaab818da8d..032541d8b7be46e902902274f305b01b828dc5ea 100644 (file)
@@ -148,12 +148,17 @@ int32_t zebra_gr_client_disconnect(struct zserv *client)
        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)) {
@@ -170,11 +175,22 @@ int32_t zebra_gr_client_disconnect(struct zserv *client)
                               __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;
 }
 
index 7715eab0a8d6dfaa31a6e87ac77b5f7c5acb0a87..3b7cf0eb7dfd239698d9bcb3378144278a97359f 100644 (file)
@@ -353,6 +353,9 @@ stream_failure:
 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,
@@ -453,8 +456,9 @@ void zebra_mlag_client_register(ZAPI_HANDLER_ARGS)
                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) {
                        /*
index d2367007cf6c2df61492c8c7f084a556b9753a3f..22a19e3a3b126d5aa05cd4554847f5463d9601b3 100644 (file)
@@ -460,6 +460,9 @@ zread_fail:
 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,
@@ -527,6 +530,10 @@ static void zserv_process_messages(struct event *thread)
 
 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);
        }
@@ -584,7 +591,9 @@ static void zserv_client_free(struct zserv *client)
                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);
@@ -618,10 +627,12 @@ static void zserv_client_free(struct zserv *client)
        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++) {
@@ -661,6 +672,7 @@ void zserv_close_client(struct zserv *client)
        bool free_p = true;
 
        if (client->pthread) {
+#ifndef FUZZING
                /* synchronously stop and join pthread */
                frr_pthread_stop(client->pthread, NULL);
 
@@ -675,6 +687,7 @@ void zserv_close_client(struct zserv *client)
                /* destroy pthread */
                frr_pthread_destroy(client->pthread);
                client->pthread = NULL;
+#endif
        }
 
        /*
@@ -724,7 +737,7 @@ static void zserv_handle_client_fail(struct event *thread)
  * 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 =
@@ -741,9 +754,11 @@ static struct zserv *zserv_client_create(int sock)
        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));
 
@@ -761,6 +776,7 @@ static struct zserv *zserv_client_create(int sock)
                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
@@ -771,12 +787,15 @@ static struct zserv *zserv_client_create(int sock)
 
        /* 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;
 }
@@ -949,6 +968,9 @@ void zserv_start(char *path)
 
 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);
index 90aa4d53f46d647e02c7c530b9d1b00fb96bc3cc..2c610f25ba9275ae8fc2c3d2c64b9ecdd4e479b1 100644 (file)
@@ -386,6 +386,12 @@ extern void zread_client_capabilities(struct zserv *client, struct zmsghdr *hdr,
                                      struct stream *msg,
                                      struct zebra_vrf *zvrf);
 
+#ifdef FUZZING
+struct zserv *zserv_client_create(int sock);
+#endif
+
+
+
 #ifdef __cplusplus
 }
 #endif