From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IUWHF9K5; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTPS id E16AA5A0271 for ; Wed, 12 Aug 2026 09:26:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1786519612; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wKcwULmNHzdM4EjJm60Na9UUZUuvgKnoXDeE0y9MJVk=; b=IUWHF9K5vbJT0cp/QUJ4s4qqHtu7jiz3C7/fcQsk+706tDnxy+vAU9oohD56r+RmgS+B/q o3TkwyoLGoIGta1BCo9IPDUYZqlYHA+fzo4KIVFkVF7KUif9Zw4Z6ZBfozzmGiqmVE/rwM QDUJlW3a2pitefmJOxHEhUTkFiMknGE= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-177-k_gI7PEsOqaWyCT2qY_K7Q-1; Wed, 12 Aug 2026 03:26:47 -0400 X-MC-Unique: k_gI7PEsOqaWyCT2qY_K7Q-1 X-Mimecast-MFC-AGG-ID: k_gI7PEsOqaWyCT2qY_K7Q_1786519606 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 28DCA18001E2; Wed, 12 Aug 2026 07:26:46 +0000 (UTC) Received: from anskuma-thinkpadp1gen7.bengluru.csb (unknown [10.74.80.105]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 40837195DF91; Wed, 12 Aug 2026 07:26:42 +0000 (UTC) From: Anshu Kumari To: david@gibson.dropbear.id.au, sbrivio@redhat.com, passt-dev@passt.top Subject: [PATCH 2/5] fuzz: Add flow type guards for fuzzing stability Date: Wed, 12 Aug 2026 12:56:25 +0530 Message-ID: <20260812072630.3235261-3-anskuma@redhat.com> In-Reply-To: <20260812072630.3235261-1-anskuma@redhat.com> References: <20260812072630.3235261-1-anskuma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: bTLLhHxSUSyydqjTMpp8uwrDmDzRJ4MsGeBw3G3CiJA_1786519606 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: VF5EOESYVKYMBZRGPW2WRH3L6OZI44BH X-Message-ID-Hash: VF5EOESYVKYMBZRGPW2WRH3L6OZI44BH X-MailFrom: anskuma@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: aerosound161@gmail.com, abdobngad@gmail.com, anskuma@redhat.com, lvivier@redhat.com X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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