Skip to content

Commit

Permalink
[Fuzzing] updates for oss-fuzz Ideal integration
Browse files Browse the repository at this point in the history
Signed-off-by: Arjun Singh <ajsinghyadav00@gmail.com>
  • Loading branch information
0x34d committed May 30, 2023
1 parent d339ab6 commit 261f3af
Show file tree
Hide file tree
Showing 23 changed files with 283 additions and 62 deletions.
58 changes: 41 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,28 +358,52 @@ To enable code coverage, use:

## 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

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ case "$enableval" in
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
])

Expand Down
5 changes: 5 additions & 0 deletions src/daemon/protocols/edp.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,14 @@ edp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardwar
}
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) {
Expand Down Expand Up @@ -345,6 +347,7 @@ edp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardwar
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",
Expand All @@ -353,6 +356,7 @@ edp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardwar
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",
Expand All @@ -363,6 +367,7 @@ edp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardwar
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) {
Expand Down
28 changes: 20 additions & 8 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ decode_SOURCES = decode.c \
$(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
Expand Down Expand Up @@ -70,4 +62,24 @@ check_PROGRAMS += $(TESTS)

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
47 changes: 10 additions & 37 deletions tests/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,31 +90,6 @@ decode(char *frame, int size, struct lldpd_hardware *hardware,
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)
{
Expand Down Expand Up @@ -191,7 +166,7 @@ main(int argc, char **argv)
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)");
Expand All @@ -204,15 +179,15 @@ main(int argc, char **argv)
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(" ID: %s\n", tohex(nport->p_id, nport->p_id_len));
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);
Expand All @@ -232,8 +207,8 @@ main(int argc, char **argv)
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;
Expand All @@ -259,8 +234,8 @@ main(int argc, char **argv)
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) {
Expand All @@ -275,8 +250,8 @@ main(int argc, char **argv)
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",
Expand All @@ -285,8 +260,6 @@ main(int argc, char **argv)
printf(" Custom info: %s\n",
tohex((char *)custom->oui_info, custom->oui_info_len));
}
# endif
#endif
exit(0);
}

#endif
54 changes: 54 additions & 0 deletions tests/fuzz_cdp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* -*- 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;
}
52 changes: 52 additions & 0 deletions tests/fuzz_edp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* -*- 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;
}
Loading

0 comments on commit 261f3af

Please sign in to comment.