// libFuzzer harness for executorch::runtime::Program::load() // Targets the .pte flatbuffer parsing path (runtime/executor/program.cpp). // Authorized local testing only - huntr MFV scope: ExecuTorch .pte parser. #include #include #include #include #include using executorch::extension::BufferDataLoader; using executorch::runtime::Program; static bool g_initialized = false; extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) { if (!g_initialized) { executorch::runtime::runtime_init(); g_initialized = true; } constexpr std::size_t kMaxInput = 32U * 1024U * 1024U; if (data == nullptr || size == 0 || size > kMaxInput) { return 0; } BufferDataLoader loader(data, size); // Try both verification levels - Minimal is the one used in perf-sensitive // deployments and skips more validation than InternalConsistency. auto program_ic = Program::load(&loader, Program::Verification::InternalConsistency); if (getenv("ET_FUZZ_DEBUG")) { fprintf(stderr, "[dbg] IC program.ok()=%d", program_ic.ok()); if (!program_ic.ok()) { fprintf(stderr, " error=0x%x", static_cast(program_ic.error())); } else { fprintf(stderr, " num_methods=%zu", program_ic.get().num_methods()); } fprintf(stderr, "\n"); BufferDataLoader loader2(data, size); auto program_min = Program::load(&loader2, Program::Verification::Minimal); fprintf(stderr, "[dbg] Minimal program.ok()=%d", program_min.ok()); if (!program_min.ok()) { fprintf(stderr, " error=0x%x", static_cast(program_min.error())); } else { fprintf(stderr, " num_methods=%zu", program_min.get().num_methods()); } fprintf(stderr, "\n"); } if (program_ic.ok()) { // Touch metadata to exercise more of the parsing surface. auto& p = program_ic.get(); auto n = p.num_methods(); for (size_t i = 0; i < n; ++i) { auto name = p.get_method_name(i); if (name.ok()) { auto meta = p.method_meta(name.get()); if (meta.ok()) { auto& m = meta.get(); (void)m.name(); (void)m.num_inputs(); (void)m.num_outputs(); (void)m.num_attributes(); (void)m.num_memory_planned_buffers(); (void)m.num_instructions(); // uses_backend()/num_backends()/get_backend_name() exercise the // ExecutionPlan::delegates() optional field - not guarded against // null in uses_backend() per source review. (void)m.uses_backend("XNNPACK"); (void)m.uses_backend(""); size_t nb = m.num_backends(); for (size_t bi = 0; bi < nb; ++bi) { (void)m.get_backend_name(bi); } size_t na = m.num_attributes(); for (size_t ai = 0; ai < na && ai < 64; ++ai) { (void)m.attribute_tensor_meta(ai); } size_t ni = m.num_inputs(); for (size_t ii = 0; ii < ni && ii < 64; ++ii) { (void)m.input_tag(ii); (void)m.input_tensor_meta(ii); } size_t no = m.num_outputs(); for (size_t oi = 0; oi < no && oi < 64; ++oi) { (void)m.output_tag(oi); (void)m.output_tensor_meta(oi); } size_t nmb = m.num_memory_planned_buffers(); for (size_t mi = 0; mi < nmb && mi < 64; ++mi) { (void)m.memory_planned_buffer_size(mi); (void)m.memory_planned_buffer_device(mi); } } } } } return 0; }