feat(runtime): apply kiln.resource_limits manifest on-target — complete the AD-WCMC-001 enforcement (SR-45, closes #415 #421) - #464
Merged
Conversation
…(SR-45)
Complete the AD-WCMC-001 on-target enforcement: a module's signed
`kiln.resource_limits` custom section is now APPLIED at load time, not
extracted-then-discarded. An embedded/gale deployment with NO `--memory`
CLI flag is still bounded by the module's own manifest.
- kiln-decoder: real `extract_resource_limits_from_binary` — scans the
binary's custom sections and decodes `kiln.resource_limits`. Strictly
distinguishes absent (Ok(None)) from present-but-malformed (Err): a
broken manifest must fail loud, never be treated as absent.
- kiln-runtime load_module: the manifest's max_memory_usage is converted
via EngineResourceLimits::from_max_memory_bytes and fed into the SAME
SR-46/47/48 pre-instantiate gate (check_declared_minimums) and runtime
grow caps (set_runtime_max_pages / set_runtime_max_elements) that the
CLI path uses. The banned `.unwrap_or(None)` masking fallback and the
"TODO: Apply resource limits" are gone; a malformed section is now a
load error.
- Precedence (SR-45): when both a CLI `--memory` bound and a manifest
bound are present, the MOST-RESTRICTIVE (minimum) wins — an operator
cannot loosen a module's signed self-declared bound, and a module
cannot loosen the operator's cap (EngineResourceLimits::most_restrictive).
- EngineBuilder::from_binary: no longer swallows extraction errors (the
old loop always yielded ASIL-D from a stub). It now selects the ASIL
mode from the manifest's qualified level, fails loud on a malformed
manifest or unknown level, and defaults to QM only when the manifest
(or its level) is genuinely absent. Dead `with_resource_config`
storage (never read by build()) removed.
- kiln-foundation: deleted the vacuous extract_resource_limits_from_binary
stub that ignored the binary and returned a defaulted config.
Manifest fields not expressible by EngineResourceLimits (max_call_depth,
fuel) are not yet enforced by this gate; the memory bound — the WCMC
attack surface — is.
Tests (RED->GREEN): manifest_memory_bound_enforced_without_cli_limits,
manifest_bound_admits_fitting_module_and_caps_growth,
manifest_tighter_than_cli_wins, cli_tighter_than_manifest_wins (pins the
converse), malformed_manifest_section_fails_loud,
builder_from_binary_fails_loud_on_malformed_manifest,
builder_from_binary_selects_manifest_asil_level; decoder unit tests
test_extract_{absent_section_is_none,present_section_roundtrips,
malformed_section_is_error,non_wasm_binary_is_error}.
Closes #415
Closes #421
Implements: SR-45
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FcTUZgts331Z1TK3q8YBQj
Bump SR-45 to implemented, retarget release v0.5.0 -> v0.4.4 (the enforcement-capstone release), and record the IMPLEMENTED (PR #464) note with the verifying test names, matching the SR-46..51 convention. Implements: SR-45 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FcTUZgts331Z1TK3q8YBQj
🔍 Build Diagnostics ReportSummary
🎯 Impact AnalysisIssues in Files You Modified
Cascading Issues (Your Changes Breaking Other Files)
✅ No Issues DetectedPerfect! Your changes don't introduce any new errors or warnings, and don't break any existing code. 📊 Full diagnostic data available in workflow artifacts 🔧 To reproduce locally: # Install cargo-kiln
cargo install --path cargo-kiln
# Analyze your changes
cargo-kiln build --output json --filter-severity error
cargo-kiln check --output json --filter-severity warning |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Completes the AD-WCMC-001 embedded trust chain's on-target end (SR-45, #415, #421): a module's signed
kiln.resource_limitscustom section is now applied at load, not extracted-then-discarded. An embedded/gale deployment with no--memoryCLI flag is still bounded by the module's own manifest, and a present-but-malformed manifest fails the load instead of silently proceeding unbounded.How
resource_limits_section.rs): new realextract_resource_limits_from_binary(binary)— scans the binary's top-level custom sections and decodeskiln.resource_limits. Three strictly-distinguished outcomes:Ok(None)(section absent),Ok(Some)(present + valid),Err(present but undecodable/invalid, or broken section framing). The old kiln-foundation "extractor" was a stub that ignored the binary and returned a defaulted config; it is deleted.CapabilityAwareEngine::load_module: the manifest'smax_memory_usageis converted withEngineResourceLimits::from_max_memory_bytesand fed into the same SR-46/47/48 pre-instantiate gate (check_declared_minimums) and runtime grow caps (set_runtime_max_pages/set_runtime_max_elements) the CLI path uses. The banned.unwrap_or(None)fallback and theTODO: Apply resource limitsare gone.--memorybound and a manifest bound exist, the most-restrictive (min) wins (EngineResourceLimits::most_restrictive) — an operator cannot loosen a module's signed self-declared bound, and a module cannot loosen the operator's cap.EngineBuilder::from_binary: no longer swallows errors (the old loop always produced ASIL-D from the stub). It selects the ASIL mode from the manifest's qualified level, fails loud on malformed manifests / unknown levels, defaults to QM only when the manifest or its level is genuinely absent. The deadwith_resource_configstorage (never read bybuild()) is removed.Manifest fields
EngineResourceLimitscannot express (max_call_depth, fuel) are not yet enforced by this gate; the memory bound — the WCMC attack surface — is.Tests (TDD, RED→GREEN)
Engine level (
kiln-runtime/tests/resource_limits_gate_tests.rs, serial):manifest_memory_bound_enforced_without_cli_limits— manifest bound, no CLI flag, oversized declared min → rejected before allocation (was: loaded unbounded)manifest_bound_admits_fitting_module_and_caps_growth— fitting module loads and carries the manifest-derived runtime page capmanifest_tighter_than_cli_wins/cli_tighter_than_manifest_wins— min-precedence in both directionsmalformed_manifest_section_fails_loud— truncated payload → load errorbuilder_from_binary_fails_loud_on_malformed_manifest,builder_from_binary_selects_manifest_asil_levelDecoder level (
kiln-decoder/src/resource_limits_section.rs):test_extract_absent_section_is_none,test_extract_present_section_roundtrips,test_extract_malformed_section_is_error,test_extract_non_wasm_binary_is_errorAll 12 gate tests green; kiln-runtime lib 101 passed; kiln-foundation lib+tests 148+ passed; workspace
cargo checkclean. Pre-existing broken test targets on main (7 in kiln-runtime, kiln-decoder no_std lib, 2 decoder lib tests, foundation example) are unchanged and untouched by this PR.Closes #415
Closes #421
Implements: SR-45
🤖 Generated with Claude Code
https://claude.ai/code/session_01FcTUZgts331Z1TK3q8YBQj