Skip to Content
Viewing feat/v0.5-runtime docs — not the stable branch. Changes vs main · Go to main

Managed Bundles

Relevant source files

A managed controller is delivered as an AXMB bundle: a canonical binary container that is separate from the legacy RBPF signed-ELF container. Authentication of a bundle does not admit, publish or execute it; the preparation worker independently verifies the instructions, enforces fallible memory budgets and performs timing admission.

Bundle format v1

All integers are unsigned little-endian. A bundle is exactly a 224-byte header followed by instruction_count * 8 bytes of BPF instructions; the complete bundle is at most 256 KiB. Empty payloads, truncation, trailing bytes, unknown versions/features and nonzero reserved bytes reject.

OffsetLengthField
04Magic AXMB
42Bundle version, exactly 1
62Header length, exactly 224
84Complete bundle length
124Instruction slot count (including wide-immediate continuations)
1616Opaque logical behavior ID
328Signer-provided revision
402Control slot, exactly 0
422Managed context version, exactly 1
442Managed helper contract version, exactly 1
462Binding flags: bit 0 declares the read-only envelope at local handle 0
484Effect ceiling: bit 0 permits requesting a wheel pair
524Private ARRAY value size
564Private ARRAY maximum entries
604Reserved zero
6432SHA3-256 of the executable payload
9632Full Ed25519 signer public key
12832Reserved zero
16064Ed25519 signature
224variableExecutable payload

Private state is either absent (both ARRAY fields zero) or one zero-initialized ARRAY at local handle 1, four-byte keys, with value size times entries at most 16 KiB. There is no initializer, external map, pinning or shared map.

Signature

The signature is ordinary Ed25519 (not Ed25519ph) over a 32-byte SHA3-256 digest:

SHA3-256( "axiomos managed bundle v1" || 0x00 || header[0..160] )

The header’s payload digest binds the whole executable payload, so authentication needs no payload-sized temporary allocation. A signature over only the executable digest (the legacy scheme) is not accepted. Trust selection compares all 32 public-key bytes; the retained signer fingerprint is SHA3-256 of the key. The artifact retains the manifest, full signer identity, SHA3-256 of the whole signed bundle and SHA3-256 of the payload. Installation generations are kernel-issued and never encoded in the bundle.

Managed verification

ManagedContract retains the binding declarations and the intersection of the signed, signer-policy and control-slot effect ceilings. Verification returns a ManagedProgram; ordinary hook and JIT APIs cannot accept that type.

Rules enforced by the managed verifier:

  • Only map lookup, private-array update and ManagedMotorPairV1 (helper 1009) are permitted. Direct GPIO/PWM/motor helpers are denied.
  • Map handles must be proven constants, exactly 0 (envelope, read-only) or 1 (private array), with local generation zero.
  • Undeclared, global or stale handles, unsupported instruction modes, pseudo bindings, non-normalized calls, malformed wide immediates and loops reject.
  • Key and update-value buffers must fit their exact declared extent and contain initialized scalar bytes; nullable map values require refinement.
  • Managed pointer spills and pointer-to-scalar conversion reject.

Preparation-path buffer growth and state copies are fallible and charged to a VerificationBudget that accounts for the pinned allocator’s 16-byte minimum and 8-byte size quantum, overlapping growth and retained output. Exhaustion returns explicit resource errors without affecting the active controller.

Managed context and helper

The managed payload is a sealed, padding-free 56-byte ManagedControlContextV1 passed through the existing context wrapper:

FieldType
version, sizeu32, u32 (1, 56)
cycle IDu64
scheduled / actual / sensor timeu64 nanoseconds each
sensor valuei64 (raw sonar echo in microseconds)
validity, reservedu32 (0 or 1), u32 zero

Helper 1009 takes two sign-extended per-mille values in [-1000, 1000]. Success records one invocation-local request; it is captured, not applied. A second or malformed request aborts the invocation even if the bytecode ignores the helper result. Execution or map failure returns no request. Successful completion distinguishes None from an explicit (0, 0) for audit; None maps to the defined zero output. Legacy MotorPairV1 keeps its separate semantics.

Authoring

rk bundle signs a raw, nonempty stream of 8-byte little-endian instructions with an external Ed25519 PKCS#8 key. It reuses the kernel’s canonical manifest builder and signing hash, rejects ELF input and writes only to a new file.

rk bundle --input target/managed-bpf/clear_streak.bin \ --output target/managed-bpf/clear_streak.axmb \ --key /path/to/signing-key.pk8 \ --behavior-id 00000000000000000000000000000003 --revision 1 --motor-pair \ --array-value-size 4 --array-entries 1 rk verify --input controller.axmb --key /path/to/signer.pub

rk verify authenticates AXMB bundles and reports the full signed identity; directory trust selection matches the full public key (an 8-byte prefix match is insufficient). Legacy rk sign and RBPF verification remain available.

Example controllers

examples/bpf/managed/ contains three C controllers built by build.sh (Clang + LLVM objcopy, output in target/managed-bpf/):

ExamplePolicy
conservative_obstacle.cStop below 1400 us echo; otherwise 250 per-mille cruise
slow_approach.cStop through 600 us, 100 per-mille through 1399 us, otherwise 300 per-mille
clear_streak.cUses private array handle 1; requires three consecutive samples of at least 1400 us before 180 per-mille

Each requests (0, 0) for an invalid sensor or nonpositive echo. Host tests in rk_cli/tests/managed_bundle.rs and the kernel compile the actual sources and run them through the verifier, manager and interpreter.

The thresholds and speeds are uncalibrated demonstration values. No generated controller is included in a boot image; bundles are uploaded after boot.

Last updated on