From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202608 header.b=BQUw0IUk; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id D64A55A0262 for ; Tue, 18 Aug 2026 07:33:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202608; t=1787031185; bh=tcpsd+Er9QwVr1Qv8Th+FSywD9qx91fEhCxu9mlulqA=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=BQUw0IUk6Aux1rbxLpZRXDrP4lgFDAzjQgiS98S4R+eiYiY4m8EvgoCyd2FFCbWl0 3Dptz+H9M/I+Vyn9SKOF0Z4MhlPEvh5bUPWWotBBQGSBJh+jwKGAMQDWVz5yd8pWqU Hn1MD+kpZTlkezJADli/shUOomo7EkpqMeRy2OQneNA2VDCDa0NPnBJr8Xd2/eBgOI 6Z22wAnffFc2AZ4Tb1DDclkGM4TAX+3U+lKq7EPGmFfWKvaTY5rh57wM94g+sy8wtP far4BbOVtyHjZCedEZ3QAxJqVwLSB73Q7qBKFVxjj5bz/iUu3M0/Nh6swN/UwzLPP1 MV+5sWvBVW/vQ== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4hPJJK1WGZz4wHr; Tue, 18 Aug 2026 15:33:05 +1000 (AEST) Date: Tue, 18 Aug 2026 15:24:17 +1000 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH 5/5] fuzz: Add test server for bidirectional protocol fuzzing Message-ID: References: <20260812072630.3235261-1-anskuma@redhat.com> <20260812072630.3235261-6-anskuma@redhat.com> <20260813095323.4c2719bd@elisabeth> <20260814093558.41626ef3@elisabeth> <20260814135523.5aace311@elisabeth> <20260817220915.45d3a039@elisabeth> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="uzDvcAGNDEZhh6Ai" Content-Disposition: inline In-Reply-To: <20260817220915.45d3a039@elisabeth> Message-ID-Hash: 4EUQ7IYQ5KXZRWJ65G7W5ESH7RVG4H4U X-Message-ID-Hash: 4EUQ7IYQ5KXZRWJ65G7W5ESH7RVG4H4U X-MailFrom: dgibson@gandalf.ozlabs.org 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: Anshu Kumari , passt-dev@passt.top, aerosound161@gmail.com, abdobngad@gmail.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: --uzDvcAGNDEZhh6Ai Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Mon, Aug 17, 2026 at 10:09:16PM +0200, Stefano Brivio wrote: > On Mon, 17 Aug 2026 16:58:18 +1000 > David Gibson wrote: >=20 > > On Fri, Aug 14, 2026 at 01:55:24PM +0200, Stefano Brivio wrote: > > > On Fri, 14 Aug 2026 20:02:46 +1000 > > > David Gibson wrote: > > > =20 > > > > On Fri, Aug 14, 2026 at 09:35:59AM +0200, Stefano Brivio wrote: =20 > > > > > On Fri, 14 Aug 2026 15:40:35 +1000 > > > > > David Gibson wrote: > > > > > =20 > > > > > > On Thu, Aug 13, 2026 at 09:53:24AM +0200, Stefano Brivio wrote:= =20 > > > > > > > On Wed, 12 Aug 2026 12:56:28 +0530 > > > > > > > Anshu Kumari wrote: > > > > > > > =20 > > > > > > > > Add fuzz-server that acts as passt's network peer > > > > > > > > during fuzzing. =20 > > > > > > >=20 > > > > > > > To me, this part makes sense. But this one: > > > > > > > =20 > > > > > > > > It connects to passt's UNIX socket =20 > > > > > > >=20 > > > > > > > much less, while: > > > > > > > =20 > > > > > > > > and listens on 127.0.0.1:9999 for TCP connections. =20 > > > > > > >=20 > > > > > > > this is the part that I expected instead. Otherwise it's not = just > > > > > > > passt's network peer, it's the guest as well. > > > > > > > =20 > > > > > > > > UNIX socket path: responds to ARP requests and TCP SYNs with > > > > > > > > stateless replies (swapped addresses, fixed ISN). Respons= es > > > > > > > > are XOR'd with AFL++ shared memory data so the fuzzer can > > > > > > > > mutate server behavior. =20 > > > > > > >=20 > > > > > > > This looks rather complicated to me. =20 > > > > > >=20 > > > > > > It does. > > > > > > =20 > > > > > > > The approach I was suggesting with a test server is the follo= wing: > > > > > > >=20 > > > > > > >=20 > > > > > > > ,- exchanges guest-side data with ------------. > > > > > > > | ,---------|---------. > > > > > > > | ,--| passt | > > > > > > > | / '-.---------------^-' > > > > > > > ,---|---. / | connect(), | a= ccept(), > > > > > > > | AFL++ |-- shares memory with ---| | send data, | r= eply with > > > > > > > '---|---' \ | etc. | d= ata, etc. > > > > > > > | \ ,-v---------------'-. > > > > > > > | '--| test server | > > > > > > > | '---------|---------' > > > > > > > '- exchanges host-side data with -------------' > > > > > > >=20 > > > > > > > ...at least in its basic form. Eventually, the test server sh= ould be > > > > > > > able to connect to passt itself (and we could call it "test p= eer" at > > > > > > > that point). =20 > > > > > >=20 > > > > > > So, I agree that to meaningfully fuzz things, we want the fuzze= r to be > > > > > > able to control data on both the guest and host side. I can se= e two > > > > > > basic approaches: > > > > > >=20 > > > > > > A) Alter passt/pasta so that instead of directly communicating= with > > > > > > external entities (either guest or host side) we use mocked > > > > > > versions which retrieve data from AFL. We can do that eith= er at > > > > > > the system call level, or at a higher helper function level= , the > > > > > > lower level we go, the more of the "normal" passt code we're > > > > > > exercising, but doing at a slightly higher level might be e= asier > > > > > > to implement > > > > > >=20 > > > > > > B) Run passt/pasta in an environment where we can intercept the > > > > > > external transfers to a test server / test peer / test gues= t which > > > > > > in turn responds based on data from AFL. > > > > > >=20 > > > > > > Both the current draft and the sketch diagram Stefano has provi= ded are > > > > > > a hybrid of both approaches, so far I'm not seeing a clear adva= ntage > > > > > > to that over going all one way or the other. =20 > > > > >=20 > > > > > Of course, B) would be cleaner (and not that complicated, see bel= ow), > > > > > but we don't want to do that guest-side (sending data from a test > > > > > guest) because we would lose the speed advantage of having shared > > > > > memory on the path that _really_ matters for fuzzing (the guest is > > > > > untrusted, the kernel isn't). =20 > > > >=20 > > > > I agree we lose the speed advantage, but I don't really see why that > > > > matters more on the guest side than the host. =20 > > >=20 > > > Because AFL++ tries to vary the input to discover new code paths, but > > > if it's not necessary (and in general it's not for host-side payload), > > > the input might remain relatively constant, and memory content that > > > isn't changed it's cache hot. =20 > >=20 > > Ok... but I'm still not seeing the connection. AFAIK the important > > thing for fuzzing speed is how long each fuzz test case takes to run - > > the duration of the AFL_LOOP() body. That includes getting a new case > > via shared memory, but also whatever else we do in that loop, which > > will typically involve at least one socket side and at least one tap > > side event. If the socket side events involve real socket calls and > > synchronization with another process that will cost us on that loop > > duration, even if the socket peer was informed what to do via > > cache-hot shared memory. >=20 > Those "real socket calls" are faster if copy_to_user() and > copy_from_user() (AFL++ to kernel, kernel to passt, passt to kernel, > AFL++ to passt) use cache-hot data, that's all. Ok. > For sufficiently big amounts of data (megabytes) the system call > overhead is negligible compared to data copies. Sure, but I think the more interesting fuzzing cases are going to be short but malformed packets. > > Or am I missing something super obvious. > >=20 > > > I have only profiled the "guest" side of things so far, though. > > >=20 > > > In any case, this is minor. If we can have shared memory and no furth= er > > > transport on one path, it's better than having it on zero paths. =20 > >=20 > > Well, true. But doing some of the fuzz directly via interposed > > syscalls and some via an external test peer adds the complication of > > having to synchronize eahc of those things operating from the same > > source of fuzz data. >=20 > True, that part could be a bit simpler if the test peer could take care > of both (I really think we should avoid mocking all the host-side > system calls, that is, approach A, also because we already tried to do > that, see below). >=20 > On the other hand, note that there's no need for explicit > synchronisation with the approach I described. AFL++ could send data > through passt using a buffer, the test peer could send data back using > another buffer (all part of the same memory region from the perspective > of AFL++). Those memory regions don't need to overlap, and AFL++ doesn't > mutate output after it started passt (or the wrapper running passt and > test server). AIUI with __AFL_LOOP() it *will* mutate data after starting passt (that's kind of the whole point). But it will only do so at clearly defined points (between __AFL_LOOP() iterations). > The test peer doesn't really need to synchronise with passt. It could > send data after it receives some, or it could send data a number of > times in a row without receiving anything. There would need to be some > kind of "playbook" generated by AFL++ with discrete quantities of time. So.. I can see a case for doing stuff with a "dumb" test server, that *doesn't* use an AFL generated playbook: it either just echoes back, or transmits a fixed payload. Obviously that won't exercise bugs triggered by host side weirdness, but as you've said malformed guest side packets are probably the more interesting place to start fuzzing, so I could see this as an interesting interim step. Once the test server is drive by an AFL generated playbook, I'm not seeing why it's any easier to build than mocking the host side syscalls in passt based on the AFL data. > I think you would need this regardless of the approach (A, B, or a mix). I'm not sure what "this" refers to here. > > > > Yes, fuzzing the guest > > > > side matters more, but most guest side operations will induce passt= to > > > > perform a host side operation, so the speed of the host side handli= ng > > > > matters even if the guest side is what we care about fuzzing. > > > > =20 > > > > > That's something we already established a while ago when AbdAlRah= man > > > > > was working on it. We hadn't really looked into the host side yet= , back > > > > > then. > > > > >=20 > > > > > So, host side: we can't do it (and it's much less important) beca= use we > > > > > need to use those sockets in the same way passt uses them. =20 > > > >=20 > > > > I'm not sure what you mean. I outlined a way to do this below. =20 > > >=20 > > > Sure, strictly speaking, we can, but we can't if we want to obtain a > > > realistic approximation of what we would be normally doing on sockets= =2E =20 > >=20 > > So sorry, I was unclear, in that I outlined both an approach A > > (mocking the socket syscalls) and an approach B (fuzzed frames in an > > containing namespace) way of handling the socket side. I'm not sure > > which one you're addressing here. >=20 > Approach A. The mocking we would do of host-side system calls won't be > realistic. Do you mean 1) "not realistic for us to implement", or 2) "won't behave sufficiently similarly to real syscalls to be a useful test". In either sense, I'm not sure why For 1), it's certainly non-trivial, but it seems to me it would be easier than a playbook driven test peer. For 2), yes, it would generate many non-realistic scenarios, but it will also generate realistic ones, in a much wider gamut than a test server would. The coverage drive feedback should let AFL find those cases. > > > We would wrap all the host-side socket operations, in that case, which > > > is really not ideal, to the point of questioning the whole > > > effectiveness. =20 > >=20 > > Why? I mean mocking all the socket syscalls is a moderate amount of > > work, but I'm not actually sure it's any more than writing a separate > > test peer. >=20 > But the test peer would just call send() on sockets it accepts. It's > not much writing. Thus excluding multi-packet exchanges, inbound initiated connections, connections which are active in both directions concurrently, scenarios with concurrent connections, various combinations of retransmits, FINs and RSTs. i.e. lots of the most interesting ground to find bugs. And that's even assuming that the guest side fuzzed input causes passt to send a connection request to the test server at a particular address. To even get that far, we need to constrain the input to exclude most of the absolutely most interesting malformed packets. > > Plus it allows the fuzzer to find bugs related to weird > > timing and/or weird TCP_INFO results. >=20 > ...the weird timing conditions would anyway be maintained with approach > B for the host-side. The weird TCP_INFO results is exactly what I'd > like to avoid testing (at least to start with). Well, it depends what you mean by "weird". The obvious way of mocking TCP_INFO would result in many straight-up illegal / impossible values, which I'll grant is not interesting. However, it would also result in rare but possible combinations, which is exactly the sort of thing it would be great to test. I'll grant you that as a place to start, it would be reasonable to look at fuzzing only guest side input, with a well behaved server on the host side. But I still don't see how you get around the problem of having to constrain the guest input a _lot_ to make it even be something that will connect to the test server in the way we expect. > > > > > The guest side interface is a trivial recv(), the host side is so= mething > > > > > complicated with iovecs and everything. =20 > > > >=20 > > > > I'm now not sure if you're saying this in relation to approach B, or > > > > approach A. =20 > > >=20 > > > That's independent from the chosen approach: it's like that without > > > fuzzing. =20 > >=20 > > Um.. I don't follow what you're saying here at all. >=20 > Leaving fuzzing alone: >=20 > 1. guest-side operations are a simple recv() (again, my main concern is > the guest *writing* data in a problematic way) I'll allow that's probably the most interesting case. I certainly don't think it's the only one. I'm thinking something like a bug that only occurs if we get an RST from the host side at the same moment we were about to discard a connection. Mocking syscalls (including clock_gettime()) lets us find things like that in a short time period. > 2. host-side operations are a complicated mix of a number of system > calls with I/O vectoring >=20 > ...therefore 1. is okay to mock in my opinion because we are unlikely > to discover bugs there, but 2. isn't because our host-side interface is > much more complicated. Ah, I think I see. You're worried about bugs in the actual marshalling of buffers for the syscalls, that we might bypass. I can sort of see that, but I don't think it's actually that bad. > > > If we wrap / skip recv() on the guest side, that's not a big loss. If > > > we wrap host-side socket operations, that's a significant deviation a= nd > > > we'll miss bugs. =20 > >=20 > > I don't see why that would be a significant deviation. >=20 > Because AFL++ won't behave like a real kernel? So we test ourselves against an even wider range of conditions than the real world. Oh no. > > > > > > (B) is quite easy to do guest side - we just connect a "test gu= est" to > > > > > > passt's socket. Approach B is much harder for host side. The = current > > > > > > draft has a test server listening on a single address. =20 > > > > >=20 > > > > > This is just to get something up and running though, it obviously= needs > > > > > to be changed later. =20 > > > >=20 > > > > I don't see how we are "up and running" if fuzzed packets from the > > > > guest induce passt to forward them to random host side addresses th= at > > > > we're not controlling - we won't generate reproducible results. =20 > > >=20 > > > If you look at patch 4/5, it hardcodes the destination port and uses a > > > known destination address (again, for the moment). It's not random. It > > > will need to be random of course. =20 > >=20 > > Right, that's my point. If we hardcode the destination, we're not > > fuzzing one of the things we most want to fuzz. If we don't hardcode > > the destination then this simple approach for a test peer doesn't work > > any more. >=20 > ...yes, of course, until you set up a route that redirects connections > to any address to the test peer. Then it works without hardcoding any > address. Ah, ok. I've been confusing a bit the single address test peer in this series with the any-route one you have in mind. Ok, fair enough, I now see an any-route test peer (without playbook) as a good place to start with guest side fuzzing. Once we want some sort of test peer playbook, I'm no longer convinced it's not as easy to do that via syscall mocking, which would also explore a wider range of possible bugs. > > > > > > But that means > > > > > > the fuzzing is fundamentally incapable of finding bugs involving > > > > > > talking to multiple peers at once. Worse, we have to constrain= the > > > > > > construction of guest side data so that we talk to the test ser= ver not > > > > > > something else, and that's one of the things we most want to fu= zz. > > > > > >=20 > > > > > > To really take approach B for the host side we'd need to interc= ept > > > > > > *all* host side network traffic regardless of address. Probably > > > > > > easiest way to do that would be put the whole thing inside anot= her > > > > > > netns. That outside netns would have a default route to a tap = device, > > > > > > and on the other side of the tap device would be a test server = serving > > > > > > up frames built from the fuzzer output. =20 > > > > >=20 > > > > > As I was mentioning, this could be done in a network namespace wi= thout > > > > > any interface, by making the test server listen to all ports and = all > > > > > addresses, with a non-local bind and a so-called AnyIP route. Tes= ted: > > > > >=20 > > > > > $ pasta -- sh -c 'ip route add local default dev lo; nc -l 1 & { = sleep 1; echo x | nc -N 1.2.3.4 1; }' > > > > > x =20 > > > >=20 > > > > True, but having the fuzzer synthesize L2 frames =20 > > >=20 > > > Slightly easier, perhaps, but that's beyond the scope of fuzzing we > > > need (AFL++ will start trying to build malformed frames which we won't > > > see anyway and effectively fuzz the kernel instead). =20 > >=20 > > True. But once you're doing all this anyip magic in the test server > > and fuzzing the various addresses, I can no longer see that it's any > > easier to implement than mocking the syscalls on the passt side. >=20 > There's no need to do any AnyIP magic in the test server, it's one > single setup command (the one I showed above). >=20 > The test server could just bind to all ports on 0.0.0.0 and ::, and > receive everything. >=20 > > > > seems easier to me > > > > than having it directly synthesize the various socket operations the > > > > host side peer might perform. =20 > > >=20 > > > I don't see this as complicated. There just needs to be a way for AFL= ++ > > > to say how much payload the test server might need to send in a given > > > round, and that can be used as argument to send() or sendmsg(). That's > > > what I meant by "play script." =20 > >=20 > > If the test server is just sending back a fixed payload, which isn't > > particularly interesting. We're much more likely to find bugs with > > odd mixtures of sending payloads, resets and new connections. >=20 > Well, of course the test server / peer would eventually need to do > that. That would be part of its play script, eventually (I would leave > it out at the beginning and have just variable-sized payloads). >=20 > But it's just calling connect() or close() depending on some bytecode > sequence rather than having to implement something that behaves like > connnect(). Right, but the thing with mocking syscalls is we don't actually have to implement what connect() (or, accept() from the passt side, I guess), actually does. We just need it to return things that connect() might return. Ideally anything the syscall can return, both error code and data. If it "overshoots" and also generates impossible stuff, that's not terrible - it just means we implement robustness against kernel weirdness along the way to finding other bugs. > > > > > > It's probably easier to co-ordinate if the host side and guest = side > > > > > > test server is the same, so we'd have: > > > > > >=20 > > > > > > ,-------. ,-------------. > > > > > > | AFL++ |-- shares memory with ---| test peer | > > > > > > '-------' '--v------v---' > > > > > > | | > > > > > > /-tap device-/ | > > > > > > | | > > > > > > /- test netns ----------^-------------------|-------------\ > > > > > > | | | > > > > > > | ,--------. | | > > > > > > | | passt >----------------/ | > > > > > > | '--------' | > > > > > > \---------------------------------------------------------/ > > > > > >=20 > > > > > > The test peer generates host side frames via the tap device, an= d guest > > > > > > side frames via the Unix socket. =20 > > > > >=20 > > > > > The UNIX socket is something we want to avoid, it's really much s= lower > > > > > compared to shared memory (we tried something like that) on the p= ath > > > > > where AFL++ is trying to mutate data fast (because it can hit a l= ot of > > > > > different code paths with small changes, compared to changing > > > > > socket-side payload). =20 > > > >=20 > > > > Right. That's why I conclude approch A is probably better further > > > > down. But even if we only care about fuzzing guest side, we'll > > > > usually incur the cost of operations on both sides, so I don't see > > > > that using shared memory is more important for guest side than host > > > > side interposition. > > > > =20 > > > > > > It could also be done with pasta, like this: > > > > > >=20 > > > > > > ,-------. ,-------------. > > > > > > | AFL++ |-- shares memory with ---| test peer | > > > > > > '-------' '--v------v---' > > > > > > | | > > > > > > /-tap device-/ packet > > > > > > | socket > > > > > > /- test netns ----------^-------------------|-------------\ > > > > > > | | | > > > > > > | ,--------. ,----------------|---. | > > > > > > | | pasta >-tap device-< guest netns * | | > > > > > > | '--------' '--------------------' | > > > > > > \---------------------------------------------------------/ > > > > > >=20 > > > > > >=20 > > > > > > The order it generates host vs. guest frames should also come f= rom the > > > > > > fuzzer, not be fixed. At least theoretically, this is non-inva= sive: > > > > > > it could run with an unmodified passt/pasta. Except that > > > > > > - AFL would still need coverage feedback from passt/pasta > > > > > > - It wouldn't allow us to simulate odd timings (except by act= ually > > > > > > expending real time) > > > > > > - The various interposing layers will probably slow down fuzz= ing. > > > > > > =20 > > > > > > So, I rather suspect it will work better to go fully to approac= h A: no > > > > > > test peer at all, instead passt itself is modified to use mocked > > > > > > versions of all the external syscalls to slurp data from AFL. = The > > > > > > draft series already does this for epoll_wait() and recv*(), bu= t we'd > > > > > > need to also do that for recv*() on the tap socket, connect(), > > > > > > accept(), TCP_INFO and probably others. We'd also need to mock > > > > > > "sending" calls, send(), write() and shutdown() at least - but = those > > > > > > could probably be no-ops. =20 > > > > >=20 > > > > > ...except that by mocking all those we lose a lot of complexity w= here > > > > > historically we had a ton of bugs. If we just mock recv() it's mu= ch > > > > > less (well yes we had bugs there as well but it was like 3 or 4 o= ver the > > > > > entire project history). =20 > > > >=20 > > > > If we mock as close as possible to the syscall level, I don't see t= hat > > > > bypass much of our complexity. To be clear, I'm suggesting mocks > > > > where both returned data and error codes are derived from the fuzze= r, > > > > not just no-op stubs. =20 > > >=20 > > > Doing that is not a realistic test though, because the kernel won't > > > return random error codes. =20 > >=20 > > Sure, so AFL learns those inputs send it into a boring exit-with-error > > path, and looks for inputs (i.e. return codes) that send it down more > > interesting paths. >=20 > One thing is exit-with-error, another whole thing is EAGAIN returns > that have no reason to be there. That's effectively emulating a spurious event, which is something we generally _should_ be robust against. > Or recvmsg() with random iovec structs populated by AFL++. We choose the iovecs, recvmsg() just populates the buffers, which is fairly straightforward (and since it will be payloads, fairly uninteresting). > Of course we'll want to be robust to all that but I guess we'll spend > months finding those "bugs" and fixing them before we get to do > anything useful. Hm. Maybe. > > > Indeed it would be nice to be robust to kernel issues, but I don't see > > > it as a priority (and I guess we would waste the whole time on those > > > "issues" if we do that). > > > =20 > > > > > > This is more invasive, of course. It also means we need to dea= l with > > > > > > the case where AFL generates a syscall results that should be > > > > > > impossible - that should move onto the next case ASAP, but not = be > > > > > > flagged as a passt bug. On the other hand, this approach shoul= d be > > > > > > fast, and since we can also mock clock_gettime(), the fuzzer can > > > > > > potentially find timer logic bugs that would only occur after h= ours or > > > > > > days in real time. > > > > > > =20 > > > > > > > As far as I understood, it's not trivial to make the same ins= tance > > > > > > > of AFL++ share memory with two processes at the same time, so= the > > > > > > > memory-sharing path might need to take a more complicated tur= n, for > > > > > > > example there could be a wrapper starting both passt and the = test > > > > > > > server and sharing memory with them, or passt could _addition= ally_ > > > > > > > (using a special out-of-band fuzzing channel) share data from= AFL++ > > > > > > > with the test server. > > > > > > >=20 > > > > > > > An example of communication below (but events don't necessari= ly need > > > > > > > to be in this order, this is just an example). For simplicity= , let's > > > > > > > ignore the fact that AFL++ might not directly share memory wi= th passt > > > > > > > and test server, and assume there are three areas of memory t= hat > > > > > > > AFL++ directly controls: > > > > > > >=20 > > > > > > > a. shared with passt: an array of struct epoll_event, 'ev' > > > > > > >=20 > > > > > > > b. shared with passt: the kind of tap-side buffer you impleme= nted in > > > > > > > 4/5, 'buf' > > > > > > >=20 > > > > > > > c. shared with the test server: a separate buffer, 'test_buf' > > > > > > >=20 > > > > > > > Example: > > > > > > >=20 > > > > > > > 1. AFL++ writes an EPOLLIN event in 'ev' with type > > > > > > > EPOLL_TYPE_TAP_PASST, of some data in 'buf', and some data= in > > > > > > > 'test_buf' > > > > > > >=20 > > > > > > > 2. AFL++ starts passt and the test server > > > > > > >=20 > > > > > > > 3. passt reads the EPOLL_TYPE_TAP_PASST event from 'ev', read= s data > > > > > > > from 'buf' and hands it to passt_tap_handler() > > > > > > >=20 > > > > > > > 4. this happens to be have Ethernet, IP, and TCP headers, wit= h the > > > > > > > SYN flag set, and destination address set to the address o= f the > > > > > > > test server (we might want to force all this, at least ini= tially, > > > > > > > or give it as a hint to AFL++ somehow), so passt connects = to > > > > > > > the test server > > > > > > >=20 > > > > > > > 5. the test server accepts the connection, and sends the cont= ents > > > > > > > of 'test_buf' on it (for the test server, this is directly > > > > > > > payload, without headers, as they don't make sense there).= I'm > > > > > > > not sure if we should have a different set of events (mayb= e we > > > > > > > need a "play script" for the server, in case?) > > > > > > >=20 > > > > > > > 6. this generates an EPOLLOUT event for passt. It's not in 'e= v', > > > > > > > it's a regular epoll_wait() (I think we could have an > > > > > > > epoll_wait() loop where we additionally read one event from > > > > > > > 'ev' for every iteration, or something like that) > > > > > > >=20 > > > > > > > 7. passt marks the connection as established and inserts it i= n the > > > > > > > flow table > > > > > > >=20 > > > > > > > 8. passt reads the data sent from the test server and generat= es > > > > > > > whatever TCP data packet to the "guest" (it might simply be > > > > > > > a sink) > > > > > > >=20 > > > > > > > ...and this attempt ends here because AFL++ generated a single > > > > > > > event for passt, but there could be more (this should also be > > > > > > > decided by AFL++). > > > > > > >=20 > > > > > > > Would something like this make sense? =20 >=20 > --=20 > Stefano >=20 --=20 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 --uzDvcAGNDEZhh6Ai Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmqD7HQACgkQzQJF27ox 2Gf3bQ/+J+pxOEpY9fspD2pv2zkSCvHoDr0iYeWxzxAHRUvZTI4hyQl79c2UuDMI ivywIXs3sdAGYAfplCHX4+XC3iTZPhJR4/tBYDnnS4W7KvqeLvpBnyAIkZomI+su dumJXPEcjtzMMXdGni+gX06RC1zJst1icBlIPfHZUl79ysipV26Zj+gGrjKA+jDE uyPHSQSVPjMcnIyYzjVGVV8qCq8HDc+QrTCorz16/CJ7xTV0Ff5BJD0gkr3gpA7j 4GAuhWN9x9VPIstfs2hCTgG1SlIDYg7D+zevKZ8uDTobafHYgFgz5rHycUNNk8s/ vWwQBy/3jzxKCSZo0a/W5mJMz66fM/pEy1CllgDyOYHMOgWVB3zx9p6I8Nsw2RBt 8Rc5gS6j2Ej9GNihNssd1CBTOsmYx7Dfoaj9GnBNPHSUtFFP6lQLhJmOZ+ixBmAm Kt8+CZalvu+IGKi2RZiAL+bZhvuGOLz9zWzlf5XdYI/ZEwpcPUmyFNRqQdk1nxIB +Ot/l5bLY1tMZLT09vP93jr2t7qYshL+vnAS0313mj7xE23M98zxn8jeR2hsKE5/ QDOdSdwR8/yZAD93McUAt4fQgIdflEEDAV1RglVQI9Y4PUoOqOx7N2jJW1IFw1au V7qs+qNdJm+zLKA1cru5oa1yVO7DjPTQoE/UYfKPk1CS6ls5cYE= =k6Ui -----END PGP SIGNATURE----- --uzDvcAGNDEZhh6Ai--