public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
f3456b41026b48e87962b3dde58bc12c18274e43 blob 2671 bytes (raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
 
## Fuzzing passt with AFL++

### Prerequisites

- AFL++ (afl-clang-fast, afl-fuzz)

### Build

```
make fuzz
cp passt passt.fuzz
make fuzz-server
```

This produces:
- `passt.fuzz` -- instrumented with AFL++ and AddressSanitizer
- `fuzz-server` -- test server for bidirectional protocol fuzzing

To use a specific AFL++ installation:

```
make FUZZ_CC=/path/to/afl-clang-fast fuzz
```

### Run

Start the test server first, then the fuzzer:

```
# Terminal 1 -- test server:
./fuzz-server

# Terminal 2 -- fuzzer:
afl-fuzz -i fuzzing/testcase_dir -o fuzzing/sync_dir \
  -- ./passt.fuzz --foreground
```

Multi-core (secondary instances share the corpus):

```
# Terminal 1 -- main instance:
afl-fuzz -M main -i fuzzing/testcase_dir -o fuzzing/sync_dir \
  -- ./passt.fuzz --foreground

# Terminal 2 -- secondary with different power schedule:
afl-fuzz -S variant1 -p rare -i fuzzing/testcase_dir \
  -o fuzzing/sync_dir -- ./passt.fuzz --foreground
```

### Architecture

The fuzzer uses AFL++ persistent mode with shared memory fuzzing.
Each iteration:

1. Resets deterministic state (clock, flow table, epoll)
2. Reads an epoll event and packet data from AFL++ shared memory
3. For TAP events: injects a packet with fixed L2/L3/L4 headers
   into the tap pipeline via tap_add_packet() + tap_handler().
   The TCP destination port is fixed to 9999 (the test server's
   listening port).
4. Exchanges a turn flag with fuzz-server for bidirectional flow.
5. Calls passt_worker() to process the epoll event
6. Polls for host-side TCP events (connect completion, server data)

The test server connects to passt's UNIX socket (SOCK_SEQPACKET)
and listens on 127.0.0.1:9999 for TCP connections. It responds to
ARP requests and TCP SYNs on the UNIX socket, and echoes TCP data
(XOR'd with AFL++ shared memory) on the loopback side.

Deterministic wrappers in fuzz.c replace clock_gettime(),
getrandom(), getsockopt(TCP_INFO), and recv/recvmsg/recvfrom/
recvmmsg to eliminate non-determinism from kernel state. The recv
wrappers return AFL++ buffer data for non-TAP file descriptors,
giving the fuzzer control over what passt "receives" from host
sockets.

### Seed inputs

`testcase_dir/empty.bin` is a 12-byte zero file
(sizeof(struct epoll_event)). AFL++ discovers packet formats
through mutation from this minimal seed.

### Reproducing crashes

```
./passt.fuzz --foreground < \
  fuzzing/sync_dir/default/crashes/id:000000,...
```

Minimize a crash input:

```
afl-tmin -i fuzzing/sync_dir/default/crashes/id:000000,... \
  -o crash_minimized -- ./passt.fuzz --foreground
```
debug log:

solving f23e265 ...
found f23e265 in https://archives.passt.top/passt-dev/20260812072630.3235261-6-anskuma@redhat.com/

applying [1/1] https://archives.passt.top/passt-dev/20260812072630.3235261-6-anskuma@redhat.com/
diff --git a/fuzzing/README.fuzzing.md b/fuzzing/README.fuzzing.md\r
new file mode 100644\r
index 0000000..f23e265\r

1:7: trailing whitespace.
## Fuzzing passt with AFL++\r
1:8: trailing whitespace.
\r
1:9: trailing whitespace.
### Prerequisites\r
1:10: trailing whitespace.
\r
1:11: trailing whitespace.
- AFL++ (afl-clang-fast, afl-fuzz)\r
Checking patch fuzzing/README.fuzzing.md...
Applied patch fuzzing/README.fuzzing.md cleanly.
warning: squelched 90 whitespace errors
warning: 95 lines add whitespace errors.

index at:
100644 f3456b41026b48e87962b3dde58bc12c18274e43	fuzzing/README.fuzzing.md

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).