On Wed, Aug 12, 2026 at 12:56:26PM +0530, Anshu Kumari wrote: > Few components which needs to be disabled to support AFL++ > to work: > > - isolation.c: Skip isolation and seccomp sandboxing that breaks AFL++ > pipes, namespaces, and ASan mmap/mprotect operations. > - util.c / tap.c: Switch UNIX socket to SOCK_SEQPACKET to preserve frame > boundaries, simplifying tap_passt_input() to a single recv() and removing > vnet_len framing. Most of these changes are pretty trivial, but this one is not. I'd suggest moving this into its own patch for clarity, and so it can get a more detailed rationale / explanation in the commit message. Because the test server is using its own SEQPACKET protocol, somewhat similar to, but not identical with the qemu socket protocol, you're essentially adding a new tap backend for fuzzing. That's a reasonable approach, but I think it would be clearer to treat it as that, rather than as a weird special case of the normal passt tap backend. > - passt.h: Use /tmp/passt_fuzz_%i.socket to avoid path collisions with > production instances. > - tcp_buf.c: Include fuzz.h to route recvmsg() through deterministic wrappers. > > Signed-off-by: Anshu Kumari > --- > isolation.c | 11 +++++++++++ > passt.h | 4 ++++ > tap.c | 21 +++++++++++++++++++++ > tcp_buf.c | 1 + > util.c | 10 ++++++++++ > 5 files changed, 47 insertions(+) > > diff --git a/isolation.c b/isolation.c > index a30b329..61fc76a 100644 > --- a/isolation.c > +++ b/isolation.c > @@ -208,6 +208,9 @@ static int move_root(void) > */ > void isolate_initial(void) > { > +#ifdef FUZZING > + return; > +#endif Rather than just eliminating the isolate_*() routines entirely, I'd prefer to selectively disable the specific parts that block fuzzing. > uint64_t keep; > > /* We want to keep CAP_NET_BIND_SERVICE in the initial > @@ -389,6 +392,10 @@ void isolate_user(const struct ctx *c, uid_t uid, gid_t gid, bool use_userns, > */ > int isolate_prefork(const struct ctx *c) > { > +#ifdef FUZZING > + (void)c; > + return 0; > +#endif > int flags = CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWUTS; > uint64_t ns_caps = 0; > > @@ -466,6 +473,10 @@ int isolate_prefork(const struct ctx *c) > */ > void isolate_postfork(const struct ctx *c) > { > +#ifdef FUZZING > + (void)c; > + return; > +#endif > struct sock_fprog prog; > > prctl(PR_SET_DUMPABLE, 0); > diff --git a/passt.h b/passt.h > index 51ccd4f..141c9f8 100644 > --- a/passt.h > +++ b/passt.h > @@ -7,7 +7,11 @@ > #define PASST_H > > #define UNIX_SOCK_MAX 100 > +#ifdef FUZZING > +#define UNIX_SOCK_PATH "/tmp/passt_fuzz_%i.socket" > +#else > #define UNIX_SOCK_PATH "/tmp/passt_%i.socket" > +#endif Good idea. > union epoll_ref; > > diff --git a/tap.c b/tap.c > index dfa66c7..f32c9ad 100644 > --- a/tap.c > +++ b/tap.c > @@ -14,6 +14,7 @@ > */ > > #include > +#include > #include > #include > #include > @@ -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) */ > > @@ -144,8 +146,10 @@ void tap_send_single(const struct ctx *c, const void *data, size_t l2len) > > switch (c->mode) { > case MODE_PASST: > +#ifndef FUZZING > iov[iovcnt] = IOV_OF_LVALUE(vnet_len); > iovcnt++; > +#endif Right, I think this might be clearer as a new 'case MODE_FUZZ:'. > /* fall through */ > case MODE_PASTA: > iov[iovcnt].iov_base = (void *)data; > @@ -1231,6 +1235,22 @@ static void tap_passt_input(struct ctx *c, const struct timespec *now) > > tap_flush_pools(); > > +#ifdef FUZZING > + /* SOCK_SEQPACKET: each recv returns exactly one frame */ And I think this would be clearer as a new tap_fuzz_input(). > + do { > + n = recv(c->fd_tap, pkt_buf, sizeof(pkt_buf), MSG_DONTWAIT); > + } while ((n < 0) && errno == EINTR); > + > + if (n > 0 && n >= (ssize_t)sizeof(struct ethhdr)) { I suggest removing the length check: that way the fuzzer can also look for any bugs we might have if we ever get undersized frames from the tap interface. > + struct iov_tail data; > + > + data = IOV_TAIL_FROM_BUF(pkt_buf, n, 0); > + tap_add_packet(c, &data, now); > + } else if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { > + tap_sock_reset(c); I don't think we really care about reset and recovery for the fuzzing case, so a die() would probably suffice here. > + return; > + } > +#else > if (partial_len) { > /* We have a partial frame from an earlier pass. Move it to the > * start of the buffer, top up with new data, then process all > @@ -1281,6 +1301,7 @@ static void tap_passt_input(struct ctx *c, const struct timespec *now) > > partial_len = n; > partial_frame = p; > +#endif Whenever a #if is more than a handful of lines, it's generally helpful to put a comment on the #endif so you can tell what the #if was conditional on without having to scroll up a bunch. > > tap_handler(c, now); > } > diff --git a/tcp_buf.c b/tcp_buf.c > index 72c4541..eb28abe 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/util.c b/util.c > index 28c32e4..7f29c3b 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 > #endif > @@ -229,7 +230,11 @@ int sock_l4_dualstack_any(const struct ctx *c, enum epoll_type type, > */ > int sock_unix(char *sock_path) > { > +#ifdef FUZZING > + int fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); > +#else > int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); > +#endif Special casing what's ostensibly a general helper to open unix sockets is a bit nasty - it's relying on the fact that the only Unix socket that we're really using is the one for tap. Treating fuzz as a different tap backend would address this too. > struct sockaddr_un addr = { > .sun_family = AF_UNIX, > }; > @@ -248,8 +253,13 @@ int sock_unix(char *sock_path) > UNIX_SOCK_PATH, i)) > die_perror("Can't build UNIX domain socket path"); > > +#ifdef FUZZING > + ex = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, > + 0); > +#else > ex = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, > 0); > +#endif > if (ex < 0) > die_perror("Failed to check for UNIX domain conflicts"); > > -- > 2.55.0 > -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson