Skip to content

fuzz(flatbuf): add fuzz harness for FunctionCall/FunctionCallResult decode - #1878

Open
Devendrakumarsinha wants to merge 1 commit into
hyperlight-dev:mainfrom
Devendrakumarsinha:fuzz/flatbuf-decode-harness
Open

Devendrakumarsinha wants to merge 1 commit into
hyperlight-dev:mainfrom
Devendrakumarsinha:fuzz/flatbuf-decode-harness

Conversation

@Devendrakumarsinha

Copy link
Copy Markdown

Summary

Adds a libfuzzer-based fuzz target that directly exercises the FlatBuffers
decode path for FunctionCall and FunctionCallResult — the host-side
parsing of guest-controlled wire data arriving via the G2H virtqueue.

Motivation

Existing fuzzers (guest_call, host_call) exercise these decode paths
only indirectly through a full sandbox with a running hypervisor. This
harness isolates the parsing logic without requiring KVM or Hyper-V,
enabling faster iteration and broader input coverage.

Design

BoundedSource mirrors RecvChain semantics: take_bytes/take_chunks
reject reads beyond available data, matching production behavior and
avoiding false OOM positives from unbounded test allocators.

Results

  • Coverage: ~960 branch points
  • exec/s: ~110,000 (no hypervisor overhead)
  • No crashes found

Testing

cargo +nightly fuzz run flatbuf_decode -- -max_len=65536

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The harness does not currently reproduce production control and external-payload boundaries or trailing-byte validation.

3 open findings
What changed in this PR

Adds a fast fuzz target for FlatBuffers function call decoding without a hypervisor.

Changes:

  • Adds bounded external-value fuzzing.
  • Registers the fuzz target and dependencies.
  • Updates fuzz-generated file exclusions.
File Description
fuzz/​fuzz_targets/​flatbuf_decode.rs Implements the decode harness.
fuzz/​Cargo.toml Registers the target and dependencies.
fuzz/​.gitignore Updates fuzz output exclusions.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread fuzz/fuzz_targets/flatbuf_decode.rs
Comment thread fuzz/fuzz_targets/flatbuf_decode.rs
Comment thread fuzz/.gitignore
@andreiltd

andreiltd commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Hey @Devendrakumarsinha , thanks for the contribution! This looks very reasonable although those few comments from copilot about mirroring production code is worth addressing 🙂

@hyperlight-gh-bot

This comment has been minimized.

@Devendrakumarsinha
Devendrakumarsinha force-pushed the fuzz/flatbuf-decode-harness branch from 4c0441d to b32d581 Compare October 13, 2026 16:58
@Devendrakumarsinha

Copy link
Copy Markdown
Author

Thanks @andreiltd ,addressed all three, mirroring the production G2H path in read_control:

Split control/external ; reads the 4-byte LE size prefix, takes SIZE_PREFIX_LEN + payload_len as the size-prefixed control FlatBuffer, and passes only the trailing bytes to BoundedSource as the external payload (via transport::{SIZE_PREFIX_LEN, size_prefix_payload_len}). Invalid layouts are rejected before decoding, like read_control.
finish rejects trailing external bytes ; mirrors finish_external_values.
coverage/ restored in .gitignore.

…ecode

Add a libfuzzer-based fuzz target that directly exercises the FlatBuffers
decode path for FunctionCall and FunctionCallResult — the host-side parsing
of guest-controlled wire data arriving via the G2H virtqueue.

Previously these decode paths had no direct fuzz coverage; existing fuzzers
(guest_call, host_call) exercise them only indirectly through a full sandbox.
This harness isolates the parsing logic without requiring a hypervisor.

Uses a BoundedSource that mirrors RecvChain semantics: take_bytes/take_chunks
reject reads beyond available data, matching production behavior.

Initial run (~1M iterations):
- Coverage: ~960 branch points
- exec/s: ~110,000
- No crashes found

Signed-off-by: Devendra Kumar Sinha <devendrasinha.me@gmail.com>
@Devendrakumarsinha
Devendrakumarsinha force-pushed the fuzz/flatbuf-decode-harness branch from b32d581 to fd33f16 Compare October 13, 2026 17:25
@andreiltd andreiltd added kind/enhancement For PRs adding features, improving functionality, docs, tests, etc. area/fuzzing Fuzzing related test failures created from weekly CI labels Oct 14, 2026
@andreiltd

Copy link
Copy Markdown
Member

Hey, thanks! This looks very close: lock file need to be updated, also CI need to pick up new fuzzing target, so it need to be added to: ValidatePullRequest.yml,  Fuzzing.yml and Justfile.

@hyperlight-gh-bot

Copy link
Copy Markdown

Benchmark Results

Measured commit: fd33f164c175
Baseline commit: 7d244de79713

kvm / amd (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 753.14 ns (➖ 1.04x faster)
vec_bytes 589.87 ns (➖ 1.00x slower)
373.55 µs (➖ 1.00x faster)

payload_allocation

slot_pool_segmented
262144 524.34 ns (➖ 1.00x faster)
65536 149.34 ns (➖ 1.05x slower)

sandboxes

create_initialized_and_drop
medium 82.19 ms (➖ 1.01x slower)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
7.81 ns (➖ 1.00x slower) 7.71 ns (➖ 1.01x faster) 7.74 ns (➖ 1.00x faster)

snapshot_files

load_snapshot_unverified
small 92.49 µs (➖ 1.01x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.54 µs (➖ 1.06x slower) 7.12 µs (➖ 1.00x slower)
65536 2.06 µs (➖ 1.06x slower) 1.97 µs (➖ 1.07x faster)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 6.32 µs (➖ 1.01x faster) 6.34 µs (➖ 1.00x slower)
8192 1.11 µs (➖ 1.07x slower) 1.08 µs (➖ 1.05x slower)
262144 27.19 µs (➖ 1.06x faster)
kvm / intel (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 663.09 ns (➖ 1.03x faster)
vec_bytes 495.76 ns (➖ 1.05x faster)
668.53 µs (➖ 1.00x slower)

payload_allocation

slot_pool_segmented
262144 497.30 ns (➖ 1.10x faster)
65536 134.63 ns (➖ 1.03x faster)

sandboxes

create_initialized_and_drop
medium 73.05 ms (➖ 1.05x faster)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
6.97 ns (➖ 1.01x slower) 6.91 ns (➖ 1.00x slower) 6.89 ns (➖ 1.01x faster)

snapshot_files

load_snapshot_unverified
small 45.23 µs (➖ 1.01x slower)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.66 µs (➖ 1.02x slower) 7.60 µs (➖ 1.01x slower)
65536 2.15 µs (➖ 1.01x slower) 2.14 µs (➖ 1.02x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 7.10 µs (➖ 1.00x slower) 7.08 µs (➖ 1.01x faster)
8192 773.16 ns (➖ 1.04x slower) 754.39 ns (➖ 1.06x slower)
262144 30.16 µs (➖ 1.04x slower)
mshv3 / amd (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 948.92 ns (➖ 1.02x slower)
vec_bytes 720.44 ns (➖ 1.04x slower)
318.99 µs (➖ 1.18x slower)

payload_allocation

slot_pool_segmented
262144 718.19 ns (➖ 1.02x faster)
65536 197.15 ns (➖ 1.02x slower)

sandboxes

create_initialized_and_drop
medium 60.60 ms (➖ 1.00x faster)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
9.44 ns (➖ 1.03x faster) 9.66 ns (➖ 1.01x faster) 9.50 ns (➖ 1.02x faster)

snapshot_files

load_snapshot_unverified
small 83.35 µs (➖ 1.01x slower)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 10.03 µs (➖ 1.01x slower) 9.77 µs (➖ 1.04x faster)
65536 2.39 µs (➖ 1.04x faster) 2.24 µs (➖ 1.01x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 8.59 µs (➖ 1.13x faster) 8.39 µs (➖ 1.15x faster)
8192 1.30 µs (➖ 1.07x faster) 1.39 µs (➖ 1.14x slower)
262144 36.84 µs (➖ 1.03x faster)
mshv3 / intel (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 941.76 ns (➖ 1.02x slower)
vec_bytes 695.81 ns (➖ 1.07x slower)
774.76 µs (➖ 1.02x faster)

payload_allocation

slot_pool_segmented
262144 656.77 ns (➖ 1.04x slower)
65536 168.82 ns (➖ 1.01x slower)

sandboxes

create_initialized_and_drop
medium 68.92 ms (➖ 1.03x slower)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
10.07 ns (➖ 1.14x slower) 9.28 ns (➖ 1.06x slower) 9.22 ns (➖ 1.05x slower)

snapshot_files

load_snapshot_unverified
small 46.19 µs (➖ 1.01x slower)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.99 µs (➖ 1.01x slower) 7.92 µs (➖ 1.02x faster)
65536 2.27 µs (➖ 1.00x faster) 2.26 µs (➖ 1.00x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 7.70 µs (➖ 1.02x slower) 7.49 µs (➖ 1.01x faster)
8192 919.83 ns (➖ 1.02x faster) 930.84 ns (➖ 1.02x slower)
262144 38.26 µs (➖ 1.14x faster)
hyperv-ws2025 / amd (Windows) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 1.12 µs (➖ 1.03x faster)
vec_bytes 760.97 ns (➖ 1.01x slower)
2.15 ms (➖ 1.04x faster)

payload_allocation

slot_pool_segmented
262144 822.97 ns (➖ 1.31x faster)
65536 233.43 ns (➖ 1.26x faster)

sandboxes

create_initialized_and_drop
medium 77.31 ms (➖ 1.06x faster)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
10.88 ns (➖ 1.02x slower) 11.07 ns (➖ 1.02x faster) 10.89 ns (➖ 1.01x slower)

snapshot_files

load_snapshot_unverified
small 766.39 µs (➖ 1.13x slower)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 8.57 µs (➖ 1.02x faster) 8.58 µs (➖ 1.00x faster)
65536 2.54 µs (➖ 1.00x slower) 2.54 µs (➖ 1.00x slower)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 8.75 µs (➖ 1.01x faster) 9.51 µs (➖ 1.08x slower)
8192 1.41 µs (➖ 1.04x faster) 1.43 µs (➖ 1.05x slower)
262144 39.25 µs (➖ 1.01x slower)
hyperv-ws2025 / intel (Windows) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 1.28 µs (➖ 1.05x slower)
vec_bytes 770.69 ns (➖ 1.04x faster)
2.95 ms (➖ 1.03x faster)

payload_allocation

slot_pool_segmented
262144 737.13 ns (➖ 1.05x faster)
65536 213.41 ns (➖ 1.08x faster)

sandboxes

create_initialized_and_drop
medium 101.93 ms (➖ 1.14x faster)

slot_pool

alloc_dealloc_1500 alloc_dealloc_4096 alloc_dealloc_128
10.31 ns (➖ 1.01x slower) 9.98 ns (➖ 1.01x faster) 9.89 ns (➖ 1.07x faster)

snapshot_files

load_snapshot_unverified
small 532.61 µs (➖ 1.10x faster)

virtq_readonly

slot_pool_segmented_fragmented slot_pool_segmented
262144 7.74 µs (➖ 1.02x faster) 7.75 µs (➖ 1.06x faster)
65536 2.33 µs (➖ 1.04x faster) 2.37 µs (➖ 1.03x faster)

virtq_readwrite

slot_pool_segmented_fragmented slot_pool_segmented
65536 8.75 µs (➖ 1.02x slower) 8.43 µs (➖ 1.03x faster)
8192 1.25 µs (➖ 1.12x faster) 1.09 µs (➖ 1.26x faster)
262144 41.15 µs (➖ 1.01x faster)

Reported by cargo ci bench-report --candidate run:38438487611 --config-file bench_report.toml.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/fuzzing Fuzzing related test failures created from weekly CI kind/enhancement For PRs adding features, improving functionality, docs, tests, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants