Under FUZZING, AFL++ can inject arbitrary epoll event types
from its shared memory buffer. When an event references a flow
table entry whose type doesn't match the handler, the existing
assert() crashes the process eventually masking the real bugs.
If there is no flow at the start of fuzzing then also we are
just returning early instead of hitting crashes. Allowing the
fuzzer to explore other code path.
Replace assert() with NULL returns in the flow-lookup functions
when compiled with -DFUZZING:
- tcp.c: conn_at_sidx(), tcp_timer_handler(), tcp_sock_handler()
- tcp_splice.c: conn_at_sidx(), tcp_splice_sock_handler()
- udp.c: udp_sock_handler(), udp_sock_to_sock(),
udp_buf_sock_to_tap(), udp_sock_fwd() error path
- udp_flow.c: udp_at_sidx()
- icmp.c: ping_at_sidx(), icmp_sock_handler()
Signed-off-by: Anshu Kumari
---
icmp.c | 14 +++++++++++++-
tcp.c | 19 ++++++++++++++++++-
tcp_splice.c | 10 ++++++++++
udp.c | 29 +++++++++++++++++++++++++++--
udp_flow.c | 5 +++++
5 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/icmp.c b/icmp.c
index 0fe2366..cdfa253 100644
--- a/icmp.c
+++ b/icmp.c
@@ -39,6 +39,7 @@
#include "icmp.h"
#include "flow_table.h"
#include "epoll_ctl.h"
+#include "fuzz.h"
#define ICMP_ECHO_TIMEOUT 60 /* s, timeout for ICMP socket activity */
#define ICMP_NUM_IDS (1U << 16)
@@ -58,7 +59,12 @@ static struct icmp_ping_flow *ping_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
+#ifdef FUZZING
+ if (flow->f.type != FLOW_PING4 && flow->f.type != FLOW_PING6)
+ return NULL;
+#else
assert(flow->f.type == FLOW_PING4 || flow->f.type == FLOW_PING6);
+#endif
return &flow->ping;
}
@@ -72,7 +78,13 @@ void icmp_sock_handler(const struct ctx *c, union epoll_ref ref,
const struct timespec *now)
{
struct icmp_ping_flow *pingf = ping_at_sidx(ref.flowside);
- const struct flowside *ini = &pingf->f.side[INISIDE];
+ const struct flowside *ini;
+
+#ifdef FUZZING
+ if (!pingf)
+ return;
+#endif
+ ini = &pingf->f.side[INISIDE];
union sockaddr_inany sr;
socklen_t sl = sizeof(sr);
char buf[USHRT_MAX];
diff --git a/tcp.c b/tcp.c
index 3b78d2e..612c884 100644
--- a/tcp.c
+++ b/tcp.c
@@ -316,6 +316,7 @@
#include "tcp_buf.h"
#include "tcp_vu.h"
#include "epoll_ctl.h"
+#include "fuzz.h"
/*
* The size of TCP header (including options) is given by doff (Data Offset)
@@ -456,7 +457,12 @@ static struct tcp_tap_conn *conn_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
+#ifdef FUZZING
+ if (flow->f.type != FLOW_TCP)
+ return NULL;
+#else
assert(flow->f.type == FLOW_TCP);
+#endif
return &flow->tcp;
}
@@ -2681,7 +2687,14 @@ void tcp_timer_handler(const struct ctx *c, union epoll_ref ref,
const struct timespec *now)
{
struct itimerspec check_armed = { { 0 }, { 0 } };
- struct tcp_tap_conn *conn = &FLOW(ref.flow)->tcp;
+ struct tcp_tap_conn *conn;
+
+#ifdef FUZZING
+ if (ref.flow >= FLOW_MAX ||
+ FLOW(ref.flow)->f.type != FLOW_TCP)
+ return;
+#endif
+ conn = &FLOW(ref.flow)->tcp;
assert(!c->no_tcp);
assert(conn->f.type == FLOW_TCP);
@@ -2752,6 +2765,10 @@ void tcp_sock_handler(const struct ctx *c, union epoll_ref ref,
{
struct tcp_tap_conn *conn = conn_at_sidx(ref.flowside);
+#ifdef FUZZING
+ if (!conn)
+ return;
+#endif
assert(!c->no_tcp);
assert(pif_at_sidx(ref.flowside) != PIF_TAP);
diff --git a/tcp_splice.c b/tcp_splice.c
index 4b01f1a..005ecd1 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -105,7 +105,12 @@ static struct tcp_splice_conn *conn_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
+#ifdef FUZZING
+ if (flow->f.type != FLOW_TCP_SPLICE)
+ return NULL;
+#else
assert(flow->f.type == FLOW_TCP_SPLICE);
+#endif
return &flow->tcp_splice;
}
@@ -594,6 +599,11 @@ void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
struct tcp_splice_conn *conn = conn_at_sidx(ref.flowside);
unsigned evsidei = ref.flowside.sidei;
+#ifdef FUZZING
+ if (!conn)
+ return;
+#endif
+
assert(conn->f.type == FLOW_TCP_SPLICE);
if (conn->events == SPLICE_CLOSED)
diff --git a/udp.c b/udp.c
index 505e554..9431353 100644
--- a/udp.c
+++ b/udp.c
@@ -118,6 +118,7 @@
#include "udp_internal.h"
#include "udp_vu.h"
#include "epoll_ctl.h"
+#include "fuzz.h"
#define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */
@@ -807,9 +808,15 @@ static void udp_sock_to_sock(const struct ctx *c, int from_s, int n,
const struct flowside *toside = flowside_at_sidx(tosidx);
const struct udp_flow *uflow = udp_at_sidx(tosidx);
uint8_t topif = pif_at_sidx(tosidx);
- int to_s = uflow->s[tosidx.sidei];
+ int to_s;
int i;
+#ifdef FUZZING
+ if (!uflow)
+ return;
+#endif
+ to_s = uflow->s[tosidx.sidei];
+
if ((n = udp_sock_recv(c, from_s, udp_mh_recv, n)) <= 0)
return;
@@ -836,9 +843,15 @@ static void udp_buf_sock_to_tap(const struct ctx *c, int s, int n,
{
const struct flowside *toside = flowside_at_sidx(tosidx);
struct udp_flow *uflow = udp_at_sidx(tosidx);
- uint8_t *omac = uflow->f.tap_omac;
+ uint8_t *omac;
int i;
+#ifdef FUZZING
+ if (!uflow)
+ return;
+#endif
+ omac = uflow->f.tap_omac;
+
if ((n = udp_sock_recv(c, s, udp_mh_recv, n)) <= 0)
return;
@@ -901,10 +914,18 @@ void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
} else if (flow_sidx_valid(tosidx)) {
struct udp_flow *uflow = udp_at_sidx(tosidx);
+#ifdef FUZZING
+ if (!uflow) {
+ discard = true;
+ continue;
+ }
+#endif
+
flow_err_ratelimit(
uflow, now,
"No support for forwarding UDP from %s to %s",
pif_name(frompif), pif_name(topif));
+
discard = true;
} else {
warn_ratelimit(now, "Discarding datagram without flow");
@@ -949,6 +970,10 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref,
{
struct udp_flow *uflow = udp_at_sidx(ref.flowside);
+#ifdef FUZZING
+ if (!uflow)
+ return;
+#endif
assert(!c->no_udp && uflow);
if (events & EPOLLERR) {
diff --git a/udp_flow.c b/udp_flow.c
index f59649f..6c5b010 100644
--- a/udp_flow.c
+++ b/udp_flow.c
@@ -31,7 +31,12 @@ struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
+#ifdef FUZZING
+ if (flow->f.type != FLOW_UDP)
+ return NULL;
+#else
assert(flow->f.type == FLOW_UDP);
+#endif
return &flow->udp;
}
--
2.55.0