// Fuzz target for the .veloxpart.meta reader โ€” the file AGENT-CORE ยง5 calls // attacker-adjacent (it lives in a world-writable-ish download directory). The reader // must be total: no crash, no over-read, no unbounded allocation, on ANY byte string. // // clang++ -std=c++23 -fsanitize=fuzzer,address,undefined ... (see CMakeLists.txt) // ./fuzz_veloxpart -max_len=8192 corpus/veloxpart/ #include #include #include #include "vdm/meta/veloxpart.hpp" #include "vdm/util/bytes.hpp" #include "vdm/util/crc32.hpp" using vdm::ConstByteSpan; using vdm::meta::parse_veloxpart; using vdm::meta::serialize_veloxpart; using vdm::meta::VeloxPart; namespace { void check_roundtrip_stable(const VeloxPart &vp) { // A value the reader accepted must serialize and re-parse to an equal value โ€” // otherwise the reader is accepting something the writer can't reproduce. auto image = serialize_veloxpart(vp); auto again = parse_veloxpart(ConstByteSpan(image.data(), image.size())); if (!again.has_value() || !(again.value() == vp)) __builtin_trap(); } } // namespace extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { ConstByteSpan raw(reinterpret_cast(data), size); // 1. Raw bytes straight in โ€” most inputs die at the magic or CRC check. if (auto r = parse_veloxpart(raw); r.has_value()) check_roundtrip_stable(r.value()); // 2. Same bytes with a valid CRC-32 appended, so the field parser is actually // reached and the ByteReader bounds checks (and load_le's precondition behind // them) get exercised on structurally-plausible-but-hostile input. std::vector with_crc(raw.begin(), raw.end()); std::uint32_t c = vdm::crc32(raw); for (int i = 0; i < 4; ++i) with_crc.push_back(static_cast((c >> (8 * i)) & 0xFF)); if (auto r = parse_veloxpart(ConstByteSpan(with_crc.data(), with_crc.size())); r.has_value()) check_roundtrip_stable(r.value()); return 0; }