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=LkvEVuqs; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id 3F85E5A0271 for ; Wed, 12 Aug 2026 09:27:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1786519619; 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=s3gZaIft9e/o9y9Ioqe7KxcOZu2Ibxma6S3ObKLcYP8=; b=LkvEVuqsEMVHJpWTPVpO3leFxhZk+yD6q6JISvdg5VG0X5hkiH9dPIoZoSrcQS2D+EwqhZ q8unhbglVuHOYztYAcUtGVobb6+amRHYzXHIwnDthtHSi5cznmJ8jVDgJfS0hNS9UfCM1q bu8XdwEAJsrn456oi3mxjt9QdDw5vX8= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-486-3xE2mtQTP2unRBpcs-gFMw-1; Wed, 12 Aug 2026 03:26:54 -0400 X-MC-Unique: 3xE2mtQTP2unRBpcs-gFMw-1 X-Mimecast-MFC-AGG-ID: 3xE2mtQTP2unRBpcs-gFMw_1786519613 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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A1F6819560A1; Wed, 12 Aug 2026 07:26:53 +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 833EA195DF91; Wed, 12 Aug 2026 07:26:50 +0000 (UTC) From: Anshu Kumari To: david@gibson.dropbear.id.au, sbrivio@redhat.com, passt-dev@passt.top Subject: [PATCH 4/5] fuzz: Add AFL++ persistent mode fuzz loop Date: Wed, 12 Aug 2026 12:56:27 +0530 Message-ID: <20260812072630.3235261-5-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: YyD-gauNtyw-04nxxRMWNFA93udlfeoL5UQJ2kH_Y5o_1786519613 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: 3E6H27B5XXDJNF467F65BHRRN62ODA4L X-Message-ID-Hash: 3E6H27B5XXDJNF467F65BHRRN62ODA4L 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: Add the AFL++ persistent mode fuzz loop to passt.c main(). The loop uses __AFL_LOOP() for in-process iteration and __AFL_FUZZ_TESTCASE_BUF for shared memory fuzzing. Each iteration: - Resets deterministic clock, flow table, and epoll instance. - Drains stale data from the TAP socket. - Reads an epoll event from the AFL++ buffer. - For TAP events: constructs a packet with fixed L2/L3/L4 headers and injects it via tap_add_packet() + tap_handler(). - Exchanges a turn flag with the test server for bidirectional flow over the UNIX socket. - Calls passt_worker() to process the event. - Polls for host-side TCP events via epoll_wait(). - Runs post_handler() for deferred work. Added the 'make fuzz' target which builds passt with afl-clang-fast, -DFUZZING, -DNDEBUG, and AddressSanitizer. Signed-off-by: Anshu Kumari --- Makefile | 8 +++ passt.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) diff --git a/Makefile b/Makefile index fe1df58..8e4121e 100644 --- a/Makefile +++ b/Makefile @@ -123,6 +123,14 @@ valgrind: BASE_CPPFLAGS += -DVALGRIND valgrind: BASE_CFLAGS += -g valgrind: all +FUZZ_CC ?= afl-clang-fast + +.PHONY: fuzz + +fuzz: + $(MAKE) clean + $(MAKE) CC="$(FUZZ_CC)" CPPFLAGS="-DFUZZING -DNDEBUG" CFLAGS="-g -fsanitize=address" passt + .PHONY: clean clean: $(RM) $(BIN) *~ *.o seccomp.h seccomp_repair.h seccomp_pesto.h pasta.1 \ diff --git a/passt.c b/passt.c index 5054551..e026eb2 100644 --- a/passt.c +++ b/passt.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "util.h" #include "passt.h" @@ -54,12 +55,56 @@ #include "repair.h" #include "netlink.h" #include "epoll_ctl.h" +#include "flow_table.h" +#include "fuzz.h" #define NUM_EPOLL_EVENTS 8 #define TIMER_INTERVAL_ MIN(TCP_TIMER_INTERVAL, FWD_PORT_SCAN_INTERVAL) #define TIMER_INTERVAL MIN(TIMER_INTERVAL_, FLOW_TIMER_INTERVAL) +#ifdef FUZZING + +/* AFL++ persistent mode / shared memory fuzzing compatibility macros. */ +#ifndef __AFL_FUZZ_TESTCASE_LEN + ssize_t fuzz_len; + unsigned char fuzz_buf[1024 * 1024]; +# define __AFL_FUZZ_TESTCASE_LEN fuzz_len +# define __AFL_FUZZ_TESTCASE_BUF fuzz_buf +# define __AFL_FUZZ_INIT() void sync(void) +# define __AFL_LOOP(x) \ + ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0) +# define __AFL_INIT() sync() +#endif + +#ifdef __AFL_HAVE_MANUAL_CONTROL + __AFL_FUZZ_INIT(); +#endif + +static struct fuzz_turn *fuzz_turn_ptr; + +/** + * fuzz_turn_connect() - Map the turn flag shared memory + * + * Return: pointer to mapped turn flag, or NULL on failure + */ +static struct fuzz_turn *fuzz_turn_connect(void) +{ + struct fuzz_turn *t; + int fd; + + fd = open(FUZZ_TURN_PATH, O_RDWR); + if (fd < 0) + return NULL; + + t = mmap(NULL, sizeof(*t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + + return (t == MAP_FAILED) ? NULL : t; +} + +#endif + char pkt_buf[PKT_BUF_BYTES] __attribute__ ((aligned(PAGE_SIZE))); struct ctx passt_ctx = { @@ -282,9 +327,17 @@ static void passt_worker(void *opaque, int nfds, struct epoll_event *events) icmp_sock_handler(c, ref, &now); break; case EPOLL_TYPE_VHOST_CMD: +#ifdef FUZZING + if (!c->vdev) + break; +#endif vu_control_handler(c->vdev, c->fd_tap, eventmask); break; case EPOLL_TYPE_VHOST_KICK: +#ifdef FUZZING + if (!c->vdev) + break; +#endif vu_kick_cb(c->vdev, ref, &now); break; case EPOLL_TYPE_REPAIR_LISTEN: @@ -450,6 +503,141 @@ int main(int argc, char **argv) timer_init(c, &now); +#ifdef FUZZING + fuzz_turn_ptr = fuzz_turn_connect(); + +#define FUZZ_LOOP_ITERATIONS 10000 +#define FUZZ_DRAIN_BUF_SIZE 1600 + +#ifdef __AFL_HAVE_MANUAL_CONTROL + __AFL_INIT(); +#endif + { + unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; + + while (__AFL_LOOP(FUZZ_LOOP_ITERATIONS)) { + int len = __AFL_FUZZ_TESTCASE_LEN; + int injected = 0; + int pkt_len, round; + struct epoll_event ev; + union epoll_ref ref; + int min_pkt = sizeof(struct ethhdr) + + sizeof(struct iphdr) + + sizeof(struct tcphdr); + + if (len < (int)sizeof(ev)) + continue; + + /* Reset clock, flow table and epoll for each + * AFL++ iteration. + */ + fuzz_clock_reset(); + clock_gettime(CLOCK_MONOTONIC, &now); + timer_init(c, &now); + + flow_init(); + + /* Recreate epoll instance */ + close(c->epollfd); + c->epollfd = epoll_create1(EPOLL_CLOEXEC); + flow_epollid_register(EPOLLFD_ID_DEFAULT, c->epollfd); + + if (c->fd_tap >= 0) { + union epoll_ref tref = { + .type = EPOLL_TYPE_TAP_PASST, + .fd = c->fd_tap + }; + epoll_add(c->epollfd, + EPOLLIN | EPOLLRDHUP, tref); + + /* Drain stale socket data */ + char drain[FUZZ_DRAIN_BUF_SIZE]; + while (recv(c->fd_tap, drain, sizeof(drain), + MSG_DONTWAIT) > 0); + } + + /* Read epoll event from AFL++ buffer */ + memcpy(&ev, buf, sizeof(ev)); + ref = *((union epoll_ref *)&ev.data.u64); + + /* Set recv payload in AFL++ shared memory */ + fuzz_recv_data = buf + FUZZ_RECV_OFF; + fuzz_recv_data_len = + (len > FUZZ_RECV_OFF + FUZZ_RECV_MAX) + ? FUZZ_RECV_MAX + : ((len > FUZZ_RECV_OFF) + ? len - FUZZ_RECV_OFF : 0); + + /* Inject fuzz packet for TAP events */ + if (ref.type == EPOLL_TYPE_TAP_PASST || + ref.type == EPOLL_TYPE_TAP_PASTA) { + struct iov_tail data; + struct ethhdr *eh; + struct iphdr *iph; + struct tcphdr *th; + + tap_flush_pools(); + memset(pkt_buf, 0, min_pkt); + + pkt_len = len - (int)sizeof(ev); + if (pkt_len > 0) + memcpy(pkt_buf, buf + sizeof(ev), + pkt_len); + if (pkt_len < min_pkt) + pkt_len = min_pkt; + + /* construct ethernet header */ + eh = (struct ethhdr *)pkt_buf; + memcpy(eh->h_dest, c->our_tap_mac, ETH_ALEN); + memcpy(eh->h_source, c->guest_mac, ETH_ALEN); + eh->h_proto = htons(ETH_P_IP); + + /* construct IPv4 header */ + iph = (struct iphdr *)(pkt_buf + sizeof(*eh)); + iph->version = 4; + iph->ihl = 5; + iph->protocol = IPPROTO_TCP; + iph->saddr = c->ip4.addr.s_addr; + iph->daddr = c->ip4.guest_gw.s_addr; + iph->tot_len = htons(pkt_len - sizeof(*eh)); + + /* Fix TCP Header */ + th = (struct tcphdr *)(pkt_buf + sizeof(*eh) + + sizeof(*iph)); + th->dest = htons(9999); + if (th->doff < 5) + th->doff = 5; + + data = IOV_TAIL_FROM_BUF(pkt_buf, pkt_len, 0); + tap_add_packet(c, &data, &now); + tap_handler(c, &now); + injected = 1; + } + + /* Turn exchange -- only if data was sent */ + if (injected && fuzz_turn_ptr) { + __atomic_store_n(&fuzz_turn_ptr->turn, 1, + __ATOMIC_RELEASE); + while (__atomic_load_n(&fuzz_turn_ptr->turn, + __ATOMIC_ACQUIRE) != 0); + } + + passt_worker(c, 1, &ev); + + /* Process host-side TCP events */ + for (round = 0; round < 4; round++) { + nfds = epoll_wait(c->epollfd, events, + NUM_EPOLL_EVENTS, 0); + if (nfds <= 0) + break; + passt_worker(c, nfds, events); + } + + post_handler(c, &now); + } + } + return 0; +#else loop: /* NOLINTBEGIN(bugprone-branch-clone): intervals can be the same */ /* cppcheck-suppress [duplicateValueTernary, unmatchedSuppression] */ @@ -461,4 +649,5 @@ loop: passt_worker(c, nfds, events); goto loop; +#endif /* FUZZING */ } -- 2.55.0