From: Anshu Kumari <anskuma@redhat.com>
To: sbrivio@redhat.com, passt-dev@passt.top
Cc: lvivier@redhat.com, anskuma@redhat.com, abdobngad@gmail.com
Subject: [PATCH v2 3/7] fuzz: Guard protocol handlers against invalid fuzz-injected state
Date: Mon, 28 Sep 2026 10:47:23 +0530 [thread overview]
Message-ID: <20260928051727.2251281-4-anskuma@redhat.com> (raw)
In-Reply-To: <20260928051727.2251281-1-anskuma@redhat.com>
Use fuzz_assert() instead of assert() for flow lookups, add NULL
checks after conn_at_sidx()/udp_at_sidx(), and validate timer
references — all no-ops in non-fuzzing builds.
Signed-off-by: Anshu Kumari <anskuma@redhat.com>
---
icmp.c | 8 +++++---
tap.c | 13 +++++++++++++
tcp.c | 18 ++++++++++++------
tcp_buf.c | 1 +
tcp_splice.c | 4 +++-
udp.c | 29 +++++++++++++++++++++--------
udp_flow.c | 3 ++-
util.c | 1 +
8 files changed, 58 insertions(+), 19 deletions(-)
diff --git a/icmp.c b/icmp.c
index 0fe23667..539f8e77 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,7 @@ static struct icmp_ping_flow *ping_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
- assert(flow->f.type == FLOW_PING4 || flow->f.type == FLOW_PING6);
+ fuzz_assert(flow->f.type == FLOW_PING4 || flow->f.type == FLOW_PING6);
return &flow->ping;
}
@@ -72,7 +73,7 @@ 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;
union sockaddr_inany sr;
socklen_t sl = sizeof(sr);
char buf[USHRT_MAX];
@@ -82,7 +83,8 @@ void icmp_sock_handler(const struct ctx *c, union epoll_ref ref,
if (c->no_icmp)
return;
- assert(pingf);
+ fuzz_assert(pingf);
+ ini = &pingf->f.side[INISIDE];
n = recvfrom(ref.fd, buf, sizeof(buf), 0, &sr.sa, &sl);
if (n < 0) {
diff --git a/tap.c b/tap.c
index dfa66c71..b8e6b61f 100644
--- a/tap.c
+++ b/tap.c
@@ -14,6 +14,7 @@
*/
#include <sched.h>
+#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
@@ -61,6 +62,7 @@
#include "vhost_user.h"
#include "vu_common.h"
#include "epoll_ctl.h"
+#include "fuzz.h"
/* Maximum allowed frame lengths (including L2 header) */
@@ -512,6 +514,9 @@ size_t tap_send_frames(const struct ctx *c, const struct iovec *iov,
{
size_t m;
+#ifdef FUZZING
+ return nframes;
+#endif
if (c->fd_tap == -1)
return nframes;
@@ -1229,6 +1234,10 @@ static void tap_passt_input(struct ctx *c, const struct timespec *now)
ssize_t n;
char *p;
+#ifdef FUZZING
+ partial_frame = NULL;
+ partial_len = 0;
+#endif
tap_flush_pools();
if (partial_len) {
@@ -1412,6 +1421,10 @@ static void tap_sock_unix_init(const struct ctx *c)
*/
bool tap_is_ready(const struct ctx *c)
{
+#ifdef FUZZING
+ (void)c;
+ return true;
+#endif
if (c->fd_tap < 0)
return false;
diff --git a/tcp.c b/tcp.c
index 3b78d2ed..f491264d 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,7 @@ static struct tcp_tap_conn *conn_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
- assert(flow->f.type == FLOW_TCP);
+ fuzz_assert(flow->f.type == FLOW_TCP);
return &flow->tcp;
}
@@ -2606,7 +2607,7 @@ void tcp_listen_handler(const struct ctx *c, union epoll_ref ref,
union flow *flow;
int s;
- assert(!c->no_tcp);
+ fuzz_assert(!c->no_tcp);
if (!(flow = flow_alloc()))
return;
@@ -2681,7 +2682,11 @@ 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;
+
+ fuzz_assert(ref.flow < FLOW_MAX);
+ fuzz_assert(FLOW(ref.flow)->f.type == FLOW_TCP);
+ conn = &FLOW(ref.flow)->tcp;
assert(!c->no_tcp);
assert(conn->f.type == FLOW_TCP);
@@ -2752,8 +2757,9 @@ void tcp_sock_handler(const struct ctx *c, union epoll_ref ref,
{
struct tcp_tap_conn *conn = conn_at_sidx(ref.flowside);
- assert(!c->no_tcp);
- assert(pif_at_sidx(ref.flowside) != PIF_TAP);
+ fuzz_assert(!c->no_tcp);
+ fuzz_assert(conn);
+ fuzz_assert(pif_at_sidx(ref.flowside) != PIF_TAP);
if (conn->events == CLOSED)
return;
@@ -2939,7 +2945,7 @@ static void tcp_get_rto_params(struct ctx *c)
*/
int tcp_init(struct ctx *c)
{
- assert(!c->no_tcp);
+ fuzz_assert(!c->no_tcp);
tcp_get_rto_params(c);
diff --git a/tcp_buf.c b/tcp_buf.c
index 72c45412..eb28abeb 100644
--- a/tcp_buf.c
+++ b/tcp_buf.c
@@ -32,6 +32,7 @@
#include "tcp_conn.h"
#include "tcp_internal.h"
#include "tcp_buf.h"
+#include "fuzz.h"
#define TCP_FRAMES_MEM 128
#define TCP_FRAMES \
diff --git a/tcp_splice.c b/tcp_splice.c
index 4b01f1aa..f688dbdf 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -56,6 +56,7 @@
#include "inany.h"
#include "flow.h"
#include "epoll_ctl.h"
+#include "fuzz.h"
#include "flow_table.h"
@@ -105,7 +106,7 @@ static struct tcp_splice_conn *conn_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
- assert(flow->f.type == FLOW_TCP_SPLICE);
+ fuzz_assert(flow->f.type == FLOW_TCP_SPLICE);
return &flow->tcp_splice;
}
@@ -594,6 +595,7 @@ 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;
+ fuzz_assert(conn);
assert(conn->f.type == FLOW_TCP_SPLICE);
if (conn->events == SPLICE_CLOSED)
diff --git a/udp.c b/udp.c
index 505e5540..198ec4da 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 */
@@ -629,7 +630,7 @@ static int udp_sock_recverr(const struct ctx *c, int s, flow_sidx_t sidx,
}
uflow = udp_at_sidx(sidx);
- assert(uflow);
+ fuzz_assert(uflow);
fromside = &uflow->f.side[sidx.sidei];
toside = &uflow->f.side[!sidx.sidei];
topif = uflow->f.pif[!sidx.sidei];
@@ -698,7 +699,8 @@ static int udp_sock_errs(const struct ctx *c, int s, flow_sidx_t sidx,
socklen_t errlen;
int rc, err;
- assert(!c->no_udp);
+ fuzz_assert(!c->no_udp);
+ fuzz_assert(uflow);
/* Empty the error queue */
while ((rc = udp_sock_recverr(c, s, sidx, pif, port, now)) > 0)
@@ -780,7 +782,7 @@ static int udp_peek_addr(int s, union sockaddr_inany *src,
*/
static int udp_sock_recv(const struct ctx *c, int s, struct mmsghdr *mmh, int n)
{
- assert(!c->no_udp);
+ fuzz_assert(!c->no_udp);
n = recvmmsg(s, mmh, n, 0, NULL);
if (n < 0) {
@@ -807,9 +809,12 @@ 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;
+ fuzz_assert(toside && uflow);
+ to_s = uflow->s[tosidx.sidei];
+
if ((n = udp_sock_recv(c, from_s, udp_mh_recv, n)) <= 0)
return;
@@ -836,9 +841,12 @@ 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;
+ fuzz_assert(toside && uflow);
+ omac = uflow->f.tap_omac;
+
if ((n = udp_sock_recv(c, s, udp_mh_recv, n)) <= 0)
return;
@@ -884,6 +892,9 @@ void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
pif_name(frompif), port);
/* FIXME: what now? close/re-open socket? */
}
+#ifdef FUZZING
+ break;
+#endif
continue;
}
@@ -901,10 +912,12 @@ 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);
+ fuzz_assert(uflow);
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,7 +962,7 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref,
{
struct udp_flow *uflow = udp_at_sidx(ref.flowside);
- assert(!c->no_udp && uflow);
+ fuzz_assert(!c->no_udp && uflow);
if (events & EPOLLERR) {
if (udp_sock_errs(c, ref.fd, ref.flowside,
@@ -1034,7 +1047,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
in_port_t src, dst;
uint8_t topif;
- assert(!c->no_udp);
+ fuzz_assert(!c->no_udp);
if (!packet_get(p, idx, &data))
return 1;
@@ -1183,7 +1196,7 @@ static void udp_get_timeout_params(struct ctx *c)
*/
int udp_init(struct ctx *c)
{
- assert(!c->no_udp);
+ fuzz_assert(!c->no_udp);
udp_get_timeout_params(c);
diff --git a/udp_flow.c b/udp_flow.c
index f59649f6..7500be14 100644
--- a/udp_flow.c
+++ b/udp_flow.c
@@ -16,6 +16,7 @@
#include "flow_table.h"
#include "udp_internal.h"
#include "epoll_ctl.h"
+#include "fuzz.h"
/**
* udp_at_sidx() - Get UDP specific flow at given sidx
@@ -31,7 +32,7 @@ struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
if (!flow)
return NULL;
- assert(flow->f.type == FLOW_UDP);
+ fuzz_assert(flow->f.type == FLOW_UDP);
return &flow->udp;
}
diff --git a/util.c b/util.c
index 28c32e43..a5e23299 100644
--- a/util.c
+++ b/util.c
@@ -36,6 +36,7 @@
#include "epoll_ctl.h"
#include "pasta.h"
#include "serialise.h"
+#include "fuzz.h"
#ifdef HAS_GETRANDOM
#include <sys/random.h>
#endif
--
2.55.0
next prev parent reply other threads:[~2026-09-28 5:17 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 5:17 [PATCH v2 0/7] Add AFL++ fuzzing support for passt Anshu Kumari
2026-09-28 5:17 ` [PATCH v2 1/7] fuzz: Add AFL++ shared memory testcase buffer layout Anshu Kumari
2026-09-28 5:17 ` [PATCH v2 2/7] fuzz: Add deterministic wrappers for assert, clock and getsockopt Anshu Kumari
2026-09-28 5:17 ` Anshu Kumari [this message]
2026-09-28 5:17 ` [PATCH v2 4/7] fuzz: Bypass sandboxing for fuzzing builds Anshu Kumari
2026-09-28 5:17 ` [PATCH v2 5/7] fuzz: Add AFL++ persistent mode fuzz loop Anshu Kumari
2026-09-28 5:17 ` [PATCH v2 6/7] fuzz: Add host-side test server for bidirectional fuzzing Anshu Kumari
2026-09-28 5:17 ` [PATCH v2 7/7] fuzz: Add build targets, namespace setup and documentation Anshu Kumari
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260928051727.2251281-4-anskuma@redhat.com \
--to=anskuma@redhat.com \
--cc=abdobngad@gmail.com \
--cc=lvivier@redhat.com \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).