wai: reader limits for the extension formats' durations #258

Merged
dcharlot merged 5 commits from wai/extension-duration-limits into main 2026-10-15 01:04:12 -04:00

2026-10-14

Transaction Science
fuzz: the seed writer lives under src/bin, where cargo and the orphan check find it
All checks were successful
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Successful in 5m3s
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Successful in 2m34s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 5m21s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 6m39s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 5m50s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 4s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m28s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m8s
wai-pack / wai-pack · linux (pull_request) Successful in 1m18s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 3m57s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 19s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m18s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m31s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m45s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 42m29s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m2s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 25s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 9m6s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 35s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 51s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 2m4s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m25s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m16s
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Successful in 3m41s
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Successful in 2m1s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 17m14s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 5m22s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m24s
wai-quantum WebGPU member / member · DX12 and Vulkan (cbio-windows) (pull_request) Successful in 11m52s
`no-vanity-metrics / No new orphan source files` flagged wai/wai-rs/fuzz/src/seeds.rs:
a [[bin]] declared by an explicit path under src/ is reached by no `mod`, so the
check, which knows cargo's auto-discovered roots (src/bin/*.rs among them), counted it
as never compiled. It is the `seeds` binary run.sh builds; under src/bin/ it is both.
The check now reports no new orphans (25 pinned, 25 expected).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 19:53:40 -04:00
Transaction Science
Merge main into wai/extension-duration-limits
Some checks failed
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m2s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 14s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 9m20s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 10s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 28s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 53s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 2m4s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m29s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m16s
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Successful in 2m47s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 18m13s
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Successful in 2m15s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m21s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 5m36s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 40m33s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 39m34s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 5m24s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 6m16s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 5m33s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 4s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m27s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m6s
wai-pack / wai-pack · linux (pull_request) Successful in 1m18s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 4m0s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 20s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m15s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m31s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m37s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 41m39s
wai-quantum WebGPU member / member · DX12 and Vulkan (cbio-windows) (pull_request) Has been cancelled
# Conflicts:
#	wai/CHANGELOG.md
2026-10-14 12:33:21 -04:00
Transaction Science
wai: reader limits for the extension formats' durations
Some checks failed
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Has been cancelled
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Has been cancelled
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Has been cancelled
wai-pack / wai-pack · does this change touch it (pull_request) Has been cancelled
wai-pack / wai-pack · linux (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Has been cancelled
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Has been cancelled
WAI section references / cited sections exist (pull_request) Has been cancelled
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Has been cancelled
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Has been cancelled
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
workflow hygiene / every workflow supersedes its own queue (pull_request) Has been cancelled
lockfiles / every Cargo.lock is current (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
A score, haptic signal, audio scene, splat4d clip or film declares its length in its
contract, and rendering allocates in proportion: a score's mixdown allocated `duration`
samples outright, a haptic channel `duration` × 2 bytes, a scene's stereo mix 20 bytes a
sample, and the splat4d and film receipts a hash a frame. Nothing bounded the
declaration, so a few bytes could ask a renderer for more memory than any machine has.
SECURITY.md recorded it as a gap when the fuzzing PR found the reader-side reservations.

Each extension's contract section (score, haptics, spatial-audio, volumetric,
linear-film and its reel) now has a reader limit shared with SPEC §2, through a new
always-on module `wai::limits`:
- score and haptics: `duration × channels` at most 2^27 samples;
- audio scene: `duration` at most 2^26, so the stereo floor is at most 2^27 samples;
- splat4d `n_frames`, film `frames`, a reel's shots together: at most 2^20 frames.
A reader may refuse past them (`duration_too_long`) when it reads the contract, before
anything is rendered; a conforming encoder writes none.

The film schedule's tick, `start_tick + f × ticks_per_frame`, wrapped in release builds
and panicked in debug ones. A reader must now refuse a schedule whose last tick passes
2^64 - 1 (a film's, and each shot's of a reel); `Film::frame_tick` saturates and
`Reel::frame_tick` uses checked arithmetic.

tests/extension_duration_limits.rs rewrites a committed vector of each format to declare
exactly its limit (it reads) and one past it (refused by name), and checks the film
schedule ending at 2^64 - 1 (reads) and past it (refused). Falsified: with the readers
as they were, all three tests fail. The world, audio, haptic, splat4d, score and film
corpora verify unchanged; the 275 lib tests with the container features pass. CI runs
the test beside container_reservations on every leg.

SECURITY.md drops the gap and keeps the one this exposes: replaying a world to a far
tick costs time in proportion (memory is bounded, time is not).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 11:07:16 -04:00
Transaction Science
wai: coverage-guided fuzzing of the reader, and the container reservations it found
Some checks failed
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
tests in CI / every test file is run by a job or listed with its reason (pull_request) Has been cancelled
standards workspaces build + test / jouleclaw-rs (pull_request) Has been cancelled
standards workspaces build + test / aac-rs (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulecontract-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / map-rs (pull_request) Has been cancelled
standards workspaces build + test / mesh-rs (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
spec citations resolve / Code cites no section its SPEC lacks (pull_request) Has been cancelled
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
no-vanity-metrics / No new orphan source files (pull_request) Has been cancelled
lockfiles / every Cargo.lock is current (pull_request) Has been cancelled
SECURITY.md's remaining known gap: fuzzing was a seeded-random smoke test, with no
coverage guidance for the manifest parser, the integer payload parsers or the codec
wrappers. wai-rs/fuzz/ adds four libFuzzer targets (cargo-fuzz, AddressSanitizer):

- envelope: version detection, the WAI1 and WAI2 readers, the listing form;
- int_payload: int_payload::decode_int against each (capability, parameter set) pair
  the integer conformance corpus commits, the first byte choosing the pair;
- media: the picture, audio, video and text decoders of the floor and the recommended
  set, the first byte choosing the decoder;
- containers: the extension containers (world, causal op, film, reel, score, haptic,
  splat4d, audio scene).

`seeds` builds the corpora from the repository: every committed envelope, integer
payload and container, and a valid payload per decoder from the reference writers.
`run.sh` runs each target for a given time, tells a find (exit 1, input kept in
fuzz/artifacts) from a tool failure (exit 2), and builds with --no-cfg-fuzzing because
rav1e depends on libfuzzer-sys under cfg(fuzzing), which left wai's cdylib with an
undefined symbol. wai-fuzz.yml runs each target for 15 minutes nightly on the macOS
runner (which has the codec libraries), never per pull request, keeping the corpus on
the CI volume between nights. wai-rs's one multi-line inline table (c2pa) is put on one
line: cargo-fuzz's TOML parser rejects it.

Found in the containers target's first seconds: the audio scene reader reserved a
u32 count of entries read from the input before reading one, so a few bytes asked for
48 GiB. The world, reel, score, haptic and splat4d readers did the same. Each now
reserves no more than its remaining bytes could hold. tests/container_reservations.rs
rewrites a committed vector of each to declare 2^32 - 1 entries in four bytes and
requires a refusal with no single allocation past a few megabytes, through an allocator
that records the largest request and refuses past 256 MiB; on the old readers the world
asset table alone asked for 256 GiB (falsified). wai-conformance runs it on every leg.

SECURITY.md now says what is fuzzed, and keeps two gaps: the C libraries are not
instrumented, and the extension formats' declared durations have no reader limit yet
(rendering allocates in proportion; reading is bounded).

Smoke runs on the build host: envelope, int_payload and media 120 s each, nothing
found; containers found the above, then ran 300 s clean once fixed. Green there: the new
test, and the 275 lib tests with the container features. Clean: tests-in-CI, spec and
section refs, workflow concurrency, lockfiles, vanity metrics, comparative prose,
public names.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 10:58:29 -04:00
Transaction Science
wai: reader limits for picture, audio and video payloads
Some checks failed
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
tests in CI / every test file is run by a job or listed with its reason (pull_request) Has been cancelled
standards workspaces build + test / jouleclaw-rs (pull_request) Has been cancelled
standards workspaces build + test / aac-rs (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulecontract-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / map-rs (pull_request) Has been cancelled
standards workspaces build + test / mesh-rs (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
spec citations resolve / Code cites no section its SPEC lacks (pull_request) Has been cancelled
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
no-vanity-metrics / No new orphan source files (pull_request) Has been cancelled
lockfiles / every Cargo.lock is current (pull_request) Has been cancelled
The image, audio and AV1 decoders allocated what a payload declared, within whatever
their libraries allowed: the gap SECURITY.md listed first. SPEC §2 now sets reader
limits for them as it does for manifests and text: a picture up to 65 536 on a side
and 2^27 pixels, audio up to 2^27 samples counting every channel, AV1 up to 2^20
temporal units of such pictures. A reader may refuse past them (image_too_large,
audio_decoded_too_long, video_too_large), from what the payload declares; the writers
refuse the same. SPEC §5 now states the payload framing of the AV1, FLAC and Ogg Opus
capabilities, which only packaging §7 described for AV1.

Defects found and fixed on the way:
- flac_decode reserved STREAMINFO's declared total: 2^36 - 1 samples asked the
  allocator for 256 GiB before a sample was decoded.
- A 24-bit FLAC decoded to about ±256: the scale assumed 16 bits.
- opus_decode refused a stream whose source rate was not an Opus rate (44.1 kHz);
  RFC 7845 makes that field informational. Its output had no bound at all.
- png_decode and jpeg_decode guessed the format, so a PNG payload holding WebP decoded.
- jxl_decode refused deeper than 8 bits and returned 1 or 4 channels for grey or alpha.
- av1_decode decoded every packet and only then truncated to n; panicked on monochrome
  (empty chroma planes); misread 4:2:2, 4:4:4 and high bit depth; and let dav1d
  allocate whatever a sequence header declared. dav1d is now held to the header's
  h × w, a frame wider or taller than declared is refused, and av1_decode_each streams
  one frame at a time; the whole-output entry points refuse past 4 GiB from the header.

8-bit 4:2:0 frames decode byte for byte as before. AVIF decodes through libavif
directly with the reader limits as its decoder limits (libavif-image and the rav1e
build inside libavif are gone from the lockfile). include/wai.h is regenerated, which
also brings in the `# Safety` lines #241 added to the sources.

tests/media_decode_bounds.rs (14 tests, run by codec-wrappers) checks every limit at
its edge and one past it, on real payloads and on headers rewritten to declare more
than they hold. Falsified: the unbounded FLAC reserve, the 4:2:0-only conversion,
format guessing, an off-by-one pixel limit and the missing dav1d limit each fail it.
Green on the build host: those 14, fuzz_smoke, ffi_robustness, the text bounds and
memory tests, corpus_provenance, video_receipt, and the 193 lib tests with codecs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 10:08:25 -04:00