srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/fuzz/fuzz_tcp_reassembly.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz/fuzz_tcp_reassembly.cpp')
-rw-r--r--fuzz/fuzz_tcp_reassembly.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/fuzz/fuzz_tcp_reassembly.cpp b/fuzz/fuzz_tcp_reassembly.cpp
new file mode 100644
index 0000000..78ca91c
--- /dev/null
+++ b/fuzz/fuzz_tcp_reassembly.cpp
@@ -0,0 +1,42 @@
+#include <cstddef>
+#include <cstdint>
+
+#include "wireframe/net/tcp_reassembly.hpp"
+
+using namespace wireframe::net;
+
+// Unlike the other fuzz harnesses, this drives *one* TcpReassembler
+// with a whole sequence of segments parsed out of a single input --
+// the interesting bugs here are in cross-call state (the flow map,
+// per-direction sequence tracking, the buffer-size cap), not in
+// decoding one segment alone. Each record is a fixed 19-byte header
+// (src ip/port, dst ip/port, seq, flags, a payload length) followed by
+// that many payload bytes; malformed/truncated trailing records are
+// simply skipped rather than treated as an error, same as any other
+// best-effort parse in this project.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ TcpReassembler reassembler;
+
+ size_t pos = 0;
+ while (pos + 19 <= size) {
+ Ipv4Address src{{data[pos], data[pos + 1], data[pos + 2], data[pos + 3]}};
+ Ipv4Address dst{{data[pos + 4], data[pos + 5], data[pos + 6], data[pos + 7]}};
+ std::uint16_t src_port = static_cast<std::uint16_t>(data[pos + 8] << 8 | data[pos + 9]);
+ std::uint16_t dst_port = static_cast<std::uint16_t>(data[pos + 10] << 8 | data[pos + 11]);
+ std::uint32_t seq = static_cast<std::uint32_t>(data[pos + 12]) << 24 |
+ static_cast<std::uint32_t>(data[pos + 13]) << 16 |
+ static_cast<std::uint32_t>(data[pos + 14]) << 8 | data[pos + 15];
+ std::uint8_t flags = data[pos + 16];
+ std::uint16_t payload_len =
+ static_cast<std::uint16_t>(data[pos + 17] << 8 | data[pos + 18]);
+ pos += 19;
+
+ std::size_t available = size - pos;
+ std::size_t take = payload_len < available ? payload_len : available;
+ std::span<const unsigned char> payload{data + pos, take};
+ pos += take;
+
+ reassembler.process_segment(src, src_port, dst, dst_port, seq, flags, payload);
+ }
+ return 0;
+}