Skip to main content

Module resources

Module resources 

Source
Expand description

Host-process resource bounds for every native subprocess this runtime spawns.

Sibling of crate::limits, and deliberately not a replacement for it: that module bounds a WASM guest inside its wasmtime store (linear memory, tables, epoch deadline), this one bounds the operating-system processes the runtime forks — shell::execute_shell and runtime::dispatch_native_tool. A capsule that cannot escape its containment can still wedge the host it runs on: fork bombs, unbounded open files, unbounded writes, unbounded per-process CPU and address space, and unbounded workdir growth are all denial of service, not boundary defeats — nothing outside the granted scope is read, written, or reached — but a wedged host is still a broken host.

Three mechanisms, in descending order of portability:

  • setrlimit(2) ceilings ([apply_hard_rlimits]), applied inside the forked child’s pre_exec window on every Unix platform. Per-process, POSIX-portable, no configuration required of the host.
  • a cgroup v2 scope ([crate::cgroup]) around the whole subprocess tree, Linux only. This is what rlimits structurally cannot do: RLIMIT_NPROC is a per-uid ceiling, checked against every thread the uid owns on the host, so it bounds neither this tree nor anything else in particular. pids.max on a cgroup counts only the scope’s own tasks, and a spawn that joins a scope gets no RLIMIT_NPROC from this module at all ([NprocBound]).
  • a periodic workdir-size check ([WorkdirGuard]), on every platform. A plain filesystem walk on a fixed cadence, so a breach is caught within one poll interval — not instantly.

§A silent manifest means defaults, never “unlimited”

HostResourceLimits::resolve follows crate::limits::ExecutionLimits::resolve exactly: the manifest’s capabilities.resources block with every omitted field replaced by its DEFAULT_* constant, and the whole block’s absence treated as “every field omitted”. There is no “unset” state downstream — a capsule that declares nothing is bounded identically to one that declares every default by hand.

§Hard limits, not soft ones

setrlimit(2) takes both a soft (rlim_cur) and a hard (rlim_max) value, and an unprivileged process may raise its own soft limit up to the hard one at any time. Against a hostile agent a soft-only cap is therefore advisory: one setrlimit call from inside the capsule undoes it. Every limit this module sets writes rlim_cur == rlim_max, leaving no ceiling to raise into, and lowering rlim_max is irreversible for an unprivileged process.

Structs§

HostResourceLimits
Fully-resolved host-process limits for one session: the manifest’s capabilities.resources block with every omitted field replaced by its DEFAULT_*.

Constants§

DEFAULT_CGROUP_CPU_PERCENT
Default cgroup cpu.max quota as a percentage of one core: 200 = two cores’ worth.
DEFAULT_CGROUP_IO_BYTES_PER_SEC
Default cgroup io.max read+write throughput on the workdir’s backing device — 100 MiB/s.
DEFAULT_CGROUP_MEMORY_BYTES
Default cgroup memory.max — 4 GiB aggregate across the whole subprocess tree. Above the per-process ceiling on purpose: the tree bound exists to catch what many processes do together, so setting it at or below the single-process bound would make it redundant.
DEFAULT_CGROUP_PIDS_MAX
Default cgroup pids.max — 256 tasks aggregate across the whole subprocess tree.
DEFAULT_CPU_SECONDS
Default RLIMIT_CPU hard ceiling — one hour of CPU time per spawned subprocess.
DEFAULT_MAX_FILE_SIZE_BYTES
Default RLIMIT_FSIZE hard ceiling — 4 GiB, the largest single file a subprocess may write.
DEFAULT_MAX_OPEN_FILES
Default RLIMIT_NOFILE hard ceiling — open descriptors per spawned subprocess.
DEFAULT_MAX_PROCESSES
Default RLIMIT_NPROC headroom for a spawn with no cgroup scope — how much past the uid’s count at that spawn a subprocess tree may add, in whichever unit this platform’s RLIMIT_NPROC is checked against. Unused for a spawn that joins a scope. See [NprocBound] for which spawns get it and [uid_task_count] for the per-platform unit.
DEFAULT_MEMORY_BYTES
Default RLIMIT_AS (Linux) / RLIMIT_DATA (macOS) hard ceiling — 2 GiB per subprocess.
DEFAULT_WORKDIR_MAX_BYTES
Default ceiling on total workdir size — 10 GiB, checked periodically.