diff --git a/fuzzing/gcoap/Makefile b/fuzzing/gcoap/Makefile new file mode 100644 index 0000000000..51e6a9c4ca --- /dev/null +++ b/fuzzing/gcoap/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.fuzzing_common + +USEMODULE += gnrc_ipv6 +USEMODULE += gcoap + +include $(RIOTBASE)/Makefile.include diff --git a/fuzzing/gcoap/input/confirmable-get.dat b/fuzzing/gcoap/input/confirmable-get.dat new file mode 100644 index 0000000000..ede38e5814 --- /dev/null +++ b/fuzzing/gcoap/input/confirmable-get.dat @@ -0,0 +1 @@ +@¹'=fe80::8813:2ff:fec1:98ef%tap0‹.well-knowncore \ No newline at end of file diff --git a/fuzzing/gcoap/input/confirmable-post.dat b/fuzzing/gcoap/input/confirmable-post.dat new file mode 100644 index 0000000000..a024b378fc --- /dev/null +++ b/fuzzing/gcoap/input/confirmable-post.dat @@ -0,0 +1 @@ +@¹'=fe80::8813:2ff:fec1:98ef%tap0„riotvalueÿfoo diff --git a/fuzzing/gcoap/input/non-confirmable-get.dat b/fuzzing/gcoap/input/non-confirmable-get.dat new file mode 100644 index 0000000000..fb2260ceda --- /dev/null +++ b/fuzzing/gcoap/input/non-confirmable-get.dat @@ -0,0 +1 @@ +P¹'=fe80::8813:2ff:fec1:98ef%tap0„riotboard \ No newline at end of file diff --git a/fuzzing/gcoap/main.c b/fuzzing/gcoap/main.c new file mode 100644 index 0000000000..6aebc0872c --- /dev/null +++ b/fuzzing/gcoap/main.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 Sören Tempel + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include + +#include "thread.h" +#include "fuzzing.h" +#include "kernel_types.h" + +#include "net/gcoap.h" +#include "net/gnrc/udp.h" +#include "net/gnrc/pkt.h" +#include "net/ipv6/addr.h" +#include "net/gnrc/nettype.h" +#include "net/gnrc/ipv6/hdr.h" + +static uint32_t demux = COAP_PORT; +static gnrc_nettype_t ntype = GNRC_NETTYPE_UDP; + +void initialize(void) +{ + if (fuzzing_init(NULL, 0)) { + errx(EXIT_FAILURE, "fuzzing_init failed"); + } + + gcoap_init(); +} + +int main(void) +{ + gnrc_pktsnip_t *ipkt, *upkt, *cpkt; + + initialize(); + if (!(ipkt = gnrc_ipv6_hdr_build(NULL, NULL, &ipv6_addr_loopback))) { + errx(EXIT_FAILURE, "gnrc_ipv6_hdr_build failed"); + } + if (!(upkt = gnrc_udp_hdr_build(ipkt, 2342, COAP_PORT))) { + errx(EXIT_FAILURE, "gnrc_udp_hdr_build failed"); + } + + if (!(cpkt = gnrc_pktbuf_add(upkt, NULL, 0, GNRC_NETTYPE_UNDEF))) { + errx(EXIT_FAILURE, "gnrc_pktbuf_add failed"); + } + if (fuzzing_read_packet(STDIN_FILENO, cpkt)) { + errx(EXIT_FAILURE, "fuzzing_read_packet failed"); + } + + if (!gnrc_netapi_dispatch_receive(ntype, demux, cpkt)) { + errx(EXIT_FAILURE, "couldn't find any subscriber"); + } + + return EXIT_SUCCESS; +} diff --git a/sys/net/gnrc/pktbuf_malloc/gnrc_pktbuf_malloc.c b/sys/net/gnrc/pktbuf_malloc/gnrc_pktbuf_malloc.c index 57ec17d4e3..9cf5cbbec9 100644 --- a/sys/net/gnrc/pktbuf_malloc/gnrc_pktbuf_malloc.c +++ b/sys/net/gnrc/pktbuf_malloc/gnrc_pktbuf_malloc.c @@ -54,6 +54,10 @@ static inline void *_malloc(size_t size) static inline void _free(void *ptr) { if (ptr != NULL) { + /* The fuzzing module is only enabled when building a fuzzing + * application from the fuzzing/ subdirectory. If _free is + * called on the crafted fuzzing packet, the setup assumes that + * input processing has completed and the application terminates. */ #if defined(MODULE_FUZZING) && !defined(MODULE_GNRC_SOCK) if (ptr == gnrc_pktbuf_fuzzptr) { exit(EXIT_SUCCESS); diff --git a/sys/net/gnrc/sock/gnrc_sock.c b/sys/net/gnrc/sock/gnrc_sock.c index 9f43e89904..9147fed7b9 100644 --- a/sys/net/gnrc/sock/gnrc_sock.c +++ b/sys/net/gnrc/sock/gnrc_sock.c @@ -31,6 +31,7 @@ #ifdef MODULE_FUZZING extern gnrc_pktsnip_t *gnrc_pktbuf_fuzzptr; +gnrc_pktsnip_t *gnrc_sock_prevpkt = NULL; #endif #ifdef MODULE_XTIMER @@ -92,9 +93,15 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out, gnrc_pktsnip_t *pkt, *netif; msg_t msg; -#ifdef MODULE_FUZZING - static gnrc_pktsnip_t *prevpkt; - if (prevpkt && prevpkt == gnrc_pktbuf_fuzzptr) { + /* The fuzzing module is only enabled when building a fuzzing + * application from the fuzzing/ subdirectory. When using gnrc_sock + * the fuzzer assumes that gnrc_sock_recv is called in a loop. If it + * is called again and the previous return value was the special + * crafted fuzzing packet, the fuzzing application terminates. + * + * sock_async_event has its on fuzzing termination condition. */ +#if defined(MODULE_FUZZING) && !defined(MODULE_SOCK_ASYNC_EVENT) + if (gnrc_sock_prevpkt && gnrc_sock_prevpkt == gnrc_pktbuf_fuzzptr) { exit(EXIT_SUCCESS); } #endif @@ -159,7 +166,7 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out, } #endif #ifdef MODULE_FUZZING - prevpkt = pkt; + gnrc_sock_prevpkt = pkt; #endif return 0; diff --git a/sys/net/sock/async/event/sock_async_event.c b/sys/net/sock/async/event/sock_async_event.c index edcc5c2623..69ed79292c 100644 --- a/sys/net/sock/async/event/sock_async_event.c +++ b/sys/net/sock/async/event/sock_async_event.c @@ -16,6 +16,11 @@ #include "irq.h" #include "net/sock/async/event.h" +#ifdef MODULE_FUZZING +extern gnrc_pktsnip_t *gnrc_pktbuf_fuzzptr; +extern gnrc_pktsnip_t *gnrc_sock_prevpkt; +#endif + static void _event_handler(event_t *ev) { sock_event_t *event = (sock_event_t *)ev; @@ -36,6 +41,17 @@ static inline void _cb(void *sock, sock_async_flags_t type, void *arg, ctx->event.cb_arg = arg; ctx->event.type |= type; event_post(ctx->queue, &ctx->event.super); + + /* The fuzzing module is only enabled when building a fuzzing + * application from the fuzzing/ subdirectory. The fuzzing setup + * assumes that gnrc_sock_recv is called by the event callback. If + * the value returned by gnrc_sock_recv was the fuzzing packet, the + * fuzzing application is terminated as input processing finished. */ +#ifdef MODULE_FUZZING + if (gnrc_sock_prevpkt && gnrc_sock_prevpkt == gnrc_pktbuf_fuzzptr) { + exit(EXIT_SUCCESS); + } +#endif } static void _set_ctx(sock_async_ctx_t *ctx, event_queue_t *ev_queue)