## Fuzzing
-### With libfuzzer
+### With [libfuzzer](https://llvm.org/docs/LibFuzzer.html)
-Build with `--enable-fuzzer` and `--enable-sanitizers`, then run `./fuzz-decode fuzzer/corpus
-fuzzer/seed-corpus` in `tests` folder. For example:
+using address sanitizer:
+```bash
+export CC=clang
+export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link"
+export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
+```
-- using address sanitizer: `./configure --enable-fuzzer --enable-sanitizers=address CFLAGS="-O1 -fsanitize-address-use-after-scope" CC=clang`
-- using undefined-behaviour sanitizer: `./configure --enable-fuzzer --enable-sanitizers=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unsigned-integer-overflow,unreachable,vla-bound,vptr CFLAGS="-O1 -fno-sanitize-recover=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr" CC=clang`
-- using memory sanitizer : `./configure --enable-fuzzer --enable-sanitizers=memory CFLAGS="-O1 -fsanitize-memory-track-origins" CC=clang`
+using undefined-behaviour sanitizer:
+```bash
+export CC=clang
+export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unsigned-integer-overflow,unreachable,vla-bound,vptr -fno-sanitize-recover=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr -fsanitize=fuzzer-no-link"
+export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
+```
-### With AFL
+using memory sanitizer:
+```bash
+export CC=clang
+export CFLAGS="-O1 -fno-omit-frame-pointer -gline-tables-only -fsanitize=memory -fsanitize-memory-track-origins -fsanitize=fuzzer-no-link"
+export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
+```
-You can use [afl](http://lcamtuf.coredump.cx/afl/) to test some
-aspects of lldpd. To test frame decoding, you can do something like
-that:
+build and run:
+```
+./configure --disable-shared --enable-pie --enable-fuzzer=$LIB_FUZZING_ENGINE
+make
+cd tests/
+./fuzz_cdp fuzzing_seed_corpus/fuzz_cdp_seed_corpus
+./fuzz_edp fuzzing_seed_corpus/fuzz_edp_seed_corpus
+./fuzz_lldp fuzzing_seed_corpus/fuzz_lldp_seed_corpus
+./fuzz_sonmp fuzzing_seed_corpus/fuzz_sonmp_seed_corpus
+```
- export AFL_USE_ASAN=1 # only on 32bit arch
- ./configure CC=afl-gcc
- make clean check
- cd tests
- mkdir inputs
- mv *.pcap inputs
- afl-fuzz -i inputs -o outputs ./decode @@
+### With [AFL++](https://aflplus.plus)
+
+You can use AFL++ to test some other aspects of lldpd. To test frame decoding:
+```bash
+export CC=afl-clang-fast
+./configure --disable-shared --enable-pie
+make clean check
+cd tests
+mkdir inputs
+mv *.pcap inputs
+afl-fuzz -i inputs -o outputs ./decode @@
+```
## Embedding
esac
if test x"$fuzzer" != x; then
AC_SUBST([FUZZ_DECODE_ENGINE], ["$fuzzer"])
+ AX_CFLAGS_GCC_OPTION([-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION], [LLDP_CFLAGS])
fi
])
}
PEEK_BYTES(chassis->c_id, ETHER_ADDR_LEN);
+# ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
/* Let's check checksum */
if (frame_checksum(pos_edp, edp_len, 0) != 0) {
log_warnx("edp", "incorrect EDP checksum for frame received on %s",
hardware->h_ifname);
goto malformed;
}
+# endif
while (length && !gotend) {
if (length < 4) {
port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
edp_slot = PEEK_UINT16;
edp_port = PEEK_UINT16;
+ free(port->p_id);
if (asprintf(&port->p_id, "%d/%d", edp_slot + 1,
edp_port + 1) == -1) {
log_warn("edp",
goto malformed;
}
port->p_id_len = strlen(port->p_id);
+ free(port->p_descr);
if (asprintf(&port->p_descr, "Slot %d / Port %d", edp_slot + 1,
edp_port + 1) == -1) {
log_warn("edp",
PEEK_DISCARD_UINT16; /* vchassis */
PEEK_DISCARD(6); /* Reserved */
PEEK_BYTES(version, 4);
+ free(chassis->c_descr);
if (asprintf(&chassis->c_descr,
"EDP enabled device, version %d.%d.%d.%d", version[0],
version[1], version[2], version[3]) == -1) {
$(top_srcdir)/src/daemon/lldpd.h \
pcap-hdr.h
-if ENABLE_FUZZ_DECODE
-noinst_PROGRAMS = fuzz-decode
-fuzz_decode_CFLAGS = $(AM_CFLAGS) -DFUZZ_DECODE
-fuzz_decode_LDADD = $(FUZZ_DECODE_ENGINE) $(LDADD)
-fuzz_decode_SOURCES = decode.c \
- $(top_srcdir)/src/daemon/lldpd.h
-endif
-
LDADD = $(top_builddir)/src/daemon/liblldpd.la @libevent_LDFLAGS@
if ENABLE_SYSTEMTAP
LDADD += $(top_builddir)/src/daemon/probes.o
endif
+if ENABLE_FUZZ_DECODE
+noinst_PROGRAMS = fuzz_lldp fuzz_cdp fuzz_sonmp fuzz_edp
+
+fuzz_lldp_SOURCES = fuzz_lldp.c \
+ $(top_srcdir)/src/daemon/lldpd.h
+fuzz_lldp_LDADD = $(top_builddir)/src/daemon/liblldpd.la $(LDADD) $(FUZZ_DECODE_ENGINE)
+
+fuzz_cdp_SOURCES = fuzz_cdp.c \
+ $(top_srcdir)/src/daemon/lldpd.h
+fuzz_cdp_LDADD = $(top_builddir)/src/daemon/liblldpd.la $(LDADD) $(FUZZ_DECODE_ENGINE)
+
+fuzz_sonmp_SOURCES = fuzz_sonmp.c \
+ $(top_srcdir)/src/daemon/lldpd.h
+fuzz_sonmp_LDADD = $(top_builddir)/src/daemon/liblldpd.la $(LDADD) $(FUZZ_DECODE_ENGINE)
+
+fuzz_edp_SOURCES = fuzz_edp.c \
+ $(top_srcdir)/src/daemon/lldpd.h
+fuzz_edp_LDADD = $(top_builddir)/src/daemon/liblldpd.la $(LDADD) $(FUZZ_DECODE_ENGINE)
+endif
+
MOSTLYCLEANFILES = *.pcap
return decoded;
}
-#ifdef FUZZ_DECODE
-
-# define kMinInputLength 30
-# define kMaxInputLength 1500
-
-extern int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- if (size < kMinInputLength || size > kMaxInputLength) {
- return 0;
- }
- struct lldpd_hardware hardware;
- struct lldpd_chassis *nchassis = NULL;
- struct lldpd_port *nport = NULL;
- if (!decode((char *)data, (int)size, &hardware, &nchassis, &nport)) {
- return -1;
- }
- lldpd_port_cleanup(nport, 1);
- free(nport);
- lldpd_chassis_cleanup(nchassis, 1);
- return 0;
-}
-
-#else
-
static void
usage(void)
{
if (inet_ntop(af, &mgmt->m_addr, ipaddress, alen) == NULL) break;
printf(" mgmt: %s\n", ipaddress);
}
-# ifdef ENABLE_LLDPMED
+#ifdef ENABLE_LLDPMED
printf(" MED cap: %" PRIu16 "\n", nchassis->c_med_cap_available);
printf(" MED type: %" PRIu8 "\n", nchassis->c_med_type);
printf(" MED HW: %s\n", nchassis->c_med_hw ? nchassis->c_med_hw : "(null)");
nchassis->c_med_model ? nchassis->c_med_model : "(null)");
printf(" MED asset: %s\n",
nchassis->c_med_asset ? nchassis->c_med_asset : "(null)");
-# endif
+#endif
printf("Port:\n");
printf(" ID subtype: %" PRIu8 "\n", nport->p_id_subtype);
printf(" Description: %s\n", nport->p_descr ? nport->p_descr : "(null)");
printf(" MFS: %" PRIu16 "\n", nport->p_mfs);
printf(" TTL: %" PRIu16 "\n", nport->p_ttl);
-# ifdef ENABLE_DOT3
+#ifdef ENABLE_DOT3
printf(" Dot3 aggrID: %" PRIu32 "\n", nport->p_aggregid);
printf(" Dot3 MAC/phy autoneg supported: %" PRIu8 "\n",
nport->p_macphy.autoneg_support);
printf(" Dot3 power priority: %" PRIu8 "\n", nport->p_power.priority);
printf(" Dot3 power requested: %" PRIu16 "\n", nport->p_power.requested);
printf(" Dot3 power allocated: %" PRIu16 "\n", nport->p_power.allocated);
-# endif
-# ifdef ENABLE_LLDPMED
+#endif
+#ifdef ENABLE_LLDPMED
printf(" MED cap: %" PRIu16 "\n", nport->p_med_cap_enabled);
for (int i = 0; i < LLDP_MED_APPTYPE_LAST; i++) {
if (nport->p_med_policy[i].type == 0) continue;
printf(" MED power source: %" PRIu8 "\n", nport->p_med_power.source);
printf(" MED power priority: %" PRIu8 "\n", nport->p_med_power.priority);
printf(" MED power value: %" PRIu16 "\n", nport->p_med_power.val);
-# endif
-# ifdef ENABLE_DOT1
+#endif
+#ifdef ENABLE_DOT1
printf(" Dot1 PVID: %" PRIu16 "\n", nport->p_pvid);
struct lldpd_vlan *vlan;
TAILQ_FOREACH (vlan, &nport->p_vlans, v_entries) {
TAILQ_FOREACH (pid, &nport->p_pids, p_entries) {
printf(" Dot1 PI: %s\n", tohex(pid->p_pi, pid->p_pi_len));
}
-# endif
-# ifdef ENABLE_CUSTOM
+#endif
+#ifdef ENABLE_CUSTOM
struct lldpd_custom *custom;
TAILQ_FOREACH (custom, &nport->p_custom_list, next) {
printf(" Custom OUI: %s\n",
printf(" Custom info: %s\n",
tohex((char *)custom->oui_info, custom->oui_info_len));
}
-# endif
+#endif
exit(0);
}
-
-#endif
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2023 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../src/daemon/lldpd.h"
+
+#define kMinInputLength 5
+#define kMaxInputLength 2048
+
+/* Use this callback to avoid some logs */
+void donothing(int pri, const char *msg) {};
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+ if (Size < kMinInputLength || Size > kMaxInputLength) {
+ return 1;
+ }
+
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ struct lldpd_hardware hardware;
+
+ log_register(donothing);
+
+ if (!cdpv2_guess((char *)Data, Size)) {
+ return 1;
+ }
+
+ cdp_decode(NULL, (char *)Data, Size, &hardware, &nchassis, &nport);
+
+ if (!nchassis || !nport) {
+ return 1;
+ }
+
+ lldpd_port_cleanup(nport, 1);
+ free(nport);
+ lldpd_chassis_cleanup(nchassis, 1);
+
+ return 0;
+}
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2023 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../src/daemon/lldpd.h"
+
+#define kMinInputLength 5
+#define kMaxInputLength 2048
+
+/* Use this callback to avoid some logs */
+void donothing(int pri, const char *msg) {};
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+ if (Size < kMinInputLength || Size > kMaxInputLength) {
+ return 1;
+ }
+
+ struct lldpd cfg;
+ cfg.g_config.c_mgmt_pattern = NULL;
+
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ struct lldpd_hardware hardware;
+ log_register(donothing);
+
+ edp_decode(&cfg, (char *)Data, Size, &hardware, &nchassis, &nport);
+
+ if (!nchassis || !nport) {
+ return 1;
+ }
+
+ lldpd_port_cleanup(nport, 1);
+ free(nport);
+ lldpd_chassis_cleanup(nchassis, 1);
+
+ return 0;
+}
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2023 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../src/daemon/lldpd.h"
+
+#define kMinInputLength 5
+#define kMaxInputLength 2048
+
+/* Use this callback to avoid some logs */
+void donothing(int pri, const char *msg) {};
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+ if (Size < kMinInputLength || Size > kMaxInputLength) {
+ return 1;
+ }
+
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ struct lldpd_hardware hardware;
+
+ log_register(donothing);
+
+ lldp_decode(NULL, (char *)Data, Size, &hardware, &nchassis, &nport);
+
+ if (!nchassis || !nport) {
+ return 1;
+ }
+
+ lldpd_port_cleanup(nport, 1);
+ free(nport);
+ lldpd_chassis_cleanup(nchassis, 1);
+
+ return 0;
+}
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2023 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../src/daemon/lldpd.h"
+
+#define kMinInputLength 5
+#define kMaxInputLength 2048
+
+/* Use this callback to avoid some logs */
+void donothing(int pri, const char *msg) {};
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+ if (Size < kMinInputLength || Size > kMaxInputLength) {
+ return 1;
+ }
+
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ struct lldpd_hardware hardware;
+
+ log_register(donothing);
+
+ sonmp_decode(NULL, (char *)Data, Size, &hardware, &nchassis, &nport);
+
+ if (!nchassis || !nport) {
+ return 1;
+ }
+
+ lldpd_port_cleanup(nport, 1);
+ free(nport);
+ lldpd_chassis_cleanup(nchassis, 1);
+
+ return 0;
+}