Skip to content

firma-run (root module)

Modules


Authority selection and local-launch preparation.

Subordinate modules:

  • [config] — user-level firma.toml reader.
  • [selection] — resolver that combines CLI args and config into a single [AuthoritySelection].
  • [prepare] — local Authority configuration and launch preparation.
  • metadata — per-run authority/metadata.toml writer.

Loopback egress guard: seccomp user-notify interceptor for connect(2).

A wrapped agent’s direct connection to a loopback address bypasses HTTP_PROXY and never reaches the Sidecar. To close that gap we trap every connect(2) the agent makes and block the ones targeting a loopback address that is not a sanctioned Firma endpoint (the proxy bridge or DNS stub).

A loopback destination is also allowed when the agent’s own network namespace has a listener on that port — a service the agent started inside its jail (e.g. a test server binding 127.0.0.1:0). Because the guard runs only in structural mode, that namespace is private, so such a listener is by construction in-jail and reachable only from the agent itself; the netns_local_ports probe reads /proc/<pid>/net/* to recognize it.

seccomp’s user-notify filter must be installed inside the sandbox, on the agent’s own process, but serviced by a supervisor that is not itself subject to the filter. bwrap offers no way to hand the notification listener fd back to the parent, so:

  1. [install_and_exec] runs as a thin wrapper inside the sandbox (invoked by the entrypoint as firma __egress-guarded-run -- <agent> <args...>). It installs a filter that returns SECCOMP_RET_USER_NOTIF for connect, sends the resulting listener fd to the host supervisor over a Unix socket (SCM_RIGHTS), then execves the agent. The filter survives the exec.
  2. [start] runs the host-side supervisor (held in [crate::routing::NetworkRuntime]). It receives the listener fd and services notifications: it reads the target sockaddr from the agent via process_vm_readv(2), classifies it, and answers each connect.

The deny path is race-free: returning an errno does not re-execute the syscall. The allow path answers with SECCOMP_USER_NOTIF_FLAG_CONTINUE, which re-reads the agent-controlled sockaddr when the kernel re-runs the syscall — the classic seccomp-notify TOCTOU window. We accept it because the allow-list is just Firma’s own loopback ports and, in structural mode, the agent’s network namespace is private, so even a won race reaches only the agent’s own loopback, never a host service. This is defense in depth layered on the network-namespace boundary, not a standalone hard guarantee.

A related short-read hazard on the read path is also handled fail-closed: process_vm_readv(2) can return fewer bytes than requested (e.g. a sockaddr straddling a page boundary with the second page unmapped), which would leave the buffer tail zero-filled and misclassify a loopback destination as 0.0.0.0. read_remote_mem rejects any short read, so the caller blocks rather than allowing on a partial read.

Linux-only: seccomp and process_vm_readv(2) are Linux primitives.

Swappable foreground log sink shared with the firma CLI.

firma run writes its own compact log lines to stderr by default. Once the wrapped agent’s TUI takes over the terminal those lines would corrupt the agent’s interface, so the sink is redirected to <dir>/run.log for the duration of the session and restored to stderr for teardown output.

This module owns the pure, sink-swapping core — [ForegroundLog] and its shared [ForegroundState] — with no dependency on tracing. The CLI wires ForegroundState into a tracing layer: it resolves the active destination on each write via [ForegroundState::write] and gates ANSI color on [ForegroundState::is_stderr].

In file mode (--log-file) no compact stderr layer is installed, so the handle is [ForegroundLog::idle]: redirect/restore are no-ops and the destination is never consulted.