// SPDX-License-Identifier: GPL-3.0-or-later // IPC Roundtrip Fuzzer - Targets CLI<->daemon framing and payload encode/decode #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace yams::daemon; namespace { class FuzzRoundtripProcessor : public RequestProcessor { public: boost::asio::awaitable process(const Request& request) override { if (std::holds_alternative(request)) { PongResponse pong; pong.serverTime = std::chrono::steady_clock::now(); pong.roundTrip = std::chrono::milliseconds{0}; co_return Response{std::in_place_type, std::move(pong)}; } if (std::holds_alternative(request)) { StatusResponse status{}; status.running = true; status.ready = true; status.version = "fuzz"; co_return Response{std::in_place_type, std::move(status)}; } co_return SuccessResponse{"fuzz: ok"}; } }; std::vector run_handler_roundtrip(std::span payload, const RequestHandler::Config& config) { boost::asio::io_context io; auto processor = std::make_shared(); RequestHandler handler(processor, config); std::vector request_data(payload.begin(), payload.end()); auto fut = boost::asio::co_spawn( io, handler.handle_request(std::move(request_data), yams::compat::stop_token{}), boost::asio::use_future); io.run(); return fut.get(); } } // namespace extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size < MessageFramer::HEADER_SIZE) { return 0; } FrameReader reader; MessageFramer framer; const size_t chunk = std::max(1, size / 4); size_t offset = 0; while (offset < size) { const size_t remaining = size - offset; const size_t to_feed = std::min(remaining, chunk); const auto feed_result = reader.feed(data + offset, to_feed); offset += feed_result.consumed; if (reader.has_frame()) { auto frame_result = reader.get_frame(); if (!frame_result) continue; const auto& frame = frame_result.value(); if (frame.size() < MessageFramer::HEADER_SIZE) { continue; } auto header_result = framer.parse_header(frame); if (!header_result) { continue; } const auto payload_size = header_result.value().payload_size; if (payload_size == 0 || frame.size() < MessageFramer::HEADER_SIZE + payload_size) { continue; } const auto payload = std::span(frame.data() + MessageFramer::HEADER_SIZE, payload_size); RequestHandler::Config config; config.enable_streaming = (data[0] & 1) != 0; config.enable_multiplexing = (data[0] & 2) != 0; config.max_frame_size = 1 * 1024 * 1024; std::vector response_payload; try { response_payload = run_handler_roundtrip(payload, config); } catch (...) { continue; } auto response_msg = ProtoSerializer::decode_payload(response_payload); if (!response_msg) { continue; } auto response_frame = framer.frame_message(response_msg.value()); if (!response_frame) { continue; } auto parsed_response = framer.parse_frame(response_frame.value()); (void)parsed_response; } if (feed_result.consumed == 0) { break; } } return 0; }