Skip to content

Commit 15c4cae

Browse files
docs(threat-model): add Nested Execution & Sandbox Escape analysis + hardening direction
1 parent 7860838 commit 15c4cae

1 file changed

Lines changed: 49 additions & 0 deletions

File tree

THREAT_MODEL.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,55 @@ wraps armed runs in a hard 10-minute watchdog.
210210
restrictive mode unless `--socket-mode 0660` is set; connecting is gated by
211211
HMAC + peer-UID regardless, but operators on shared hosts should set it.
212212

213+
### Nested execution and sandbox escape
214+
215+
Jinn Guard's enforcement boundary is **processes in a governed cgroup, as seen by
216+
the host kernel.** The userspace intent layer is opt-in; the floor that governs a
217+
process which *doesn't ask* is the host BPF-LSM, applied to governed cgroups. The
218+
guarantee therefore rests on three assumptions, and a nested execution context can
219+
attack each one: the governed tag is **un-sheddable**, the kernel's **namespace
220+
view is authoritative**, and **no second kernel** is introduced.
221+
222+
| Vector | How it escapes | Severity |
223+
| --- | --- | --- |
224+
| Nested VM / microVM (qemu, Firecracker, gVisor, Kata, `/dev/kvm`) | Work runs under a **second kernel**; host BPF-LSM never sees the guest's syscalls | Critical |
225+
| cgroup migration | Process moves itself/a child to a cgroup outside `governed_scope`; LSM no longer gates it | Critical |
226+
| User namespace (`unshare`/`clone` `CLONE_NEWUSER`) | Unprivileged agent gains in-ns "root", then creates mount/cgroup/pid namespaces | High |
227+
| Mount namespace / `pivot_root` / bind-mount | Remaps the filesystem so a denied path looks allowed (generalizes the mount-boundary item above) | High |
228+
| Nested container runtime (runc/podman/nspawn) | Child runs in fresh namespaces + possibly a fresh cgroup → ungoverned unless the tag is inherited | High |
229+
| Interpreter chains (JG-ADV-2026-001) | A child interpreter performs the real work; a "soft sandbox" | Medium |
230+
231+
**Hardening direction (tracked in the hardening backlog and §10):**
232+
233+
1. **Un-sheddable governance tag.** Tag the *task* (BPF task-local storage)
234+
inherited on `clone`/`fork`/`exec`, rather than relying on cgroup membership
235+
alone; deny `cgroup.procs` writes that move a governed task out of scope. The
236+
tag follows the process tree and cannot be dropped.
237+
2. **Deny the nesting primitives by default for governed agents.** Add LSM
238+
mediation for `mount`/`move_mount`, `pivot_root`, `chroot`, `setns`, and
239+
namespace-creating `clone`/`unshare` flags. A governed agent with no legitimate
240+
need is denied these, collapsing most of the surface.
241+
3. **Treat VM launch as a hard boundary.** Host BPF-LSM cannot see inside a guest
242+
kernel. Deny `/dev/kvm` and `/dev/vhost-*` and VMM binaries for governed
243+
agents. A VM-capable governed agent is **outside the single-host enforcement
244+
model unless a nested Jinn Guard instance governs the guest** (recursive
245+
governance). This is stated as an explicit scope limit, not a claim.
246+
4. **Key path decisions on inode/superblock identity, not path strings**, so
247+
bind-mount/`pivot_root` remapping cannot fool the denylist (deepens the
248+
mount-boundary fix).
249+
5. **Drop nesting-enabling capabilities** (`CAP_SYS_ADMIN`, `CAP_SYS_CHROOT`) and
250+
restrict unprivileged user-namespace creation for governed workloads.
251+
6. **Default-deny dangerous operations at the kernel floor for governed scope**, so
252+
a nested process that never speaks the protocol still cannot exec/mount/connect
253+
outside policy — i.e., non-cooperation is safe.
254+
7. **Detect even where permitted:** namespace/cgroup/mount/VM-device creation by a
255+
governed agent is a high-signal event and is logged/alerted (canary-style).
256+
257+
Until items 1–3 land, operators should run governed agents **without
258+
`CAP_SYS_ADMIN`** and with unprivileged user namespaces disabled
259+
(`kernel.unprivileged_userns_clone=0` where the workload permits), which blocks
260+
the high-severity namespace and mount vectors at the OS level today.
261+
213262
---
214263

215264
## 8. Threats to validity — the risk model and the formal guarantee

0 commit comments

Comments
 (0)