# `Hyper.SuidHelper.ChrootJail`
[🔗](https://github.com/harmont-dev/hyper/blob/main/lib/hyper/suid_helper/chroot_jail.ex#L1)

Privileged chroot/jail lifecycle, via the setuid helper's `chroot-jail`
subcommands (`prepare` / `remove`). These are built into the helper (no
external binary), so there is no separate `test_system/0` -
`Hyper.SuidHelper.test_system/0` already checks the helper itself is present.

# `err`

```elixir
@type err() :: Hyper.SuidHelper.err()
```

# `grant_api`

```elixir
@spec grant_api(Path.t()) :: :ok | {:error, :socket_pending} | {:error, err()}
```

Hand the firecracker API `socket` to the node user so the unprivileged
controller can `connect()` to it. The jailer drops firecracker to a per-VM
uid/gid and chroots it, so the socket it creates is owned by that per-VM id and
the node (a different uid) gets `EACCES` on connect. The helper chowns just
that one socket to its caller (the node user) and chmods it `0660`, leaving the
rest of the per-VM isolation intact.

Returns `{:error, :socket_pending}` while firecracker has not yet created the
socket, so the caller can keep waiting.

# `grant_vsock`

```elixir
@spec grant_vsock(Path.t()) :: :ok | {:error, :socket_pending} | {:error, err()}
```

Hand the firecracker vsock `socket` to the node user so the unprivileged
controller can set up the guest AF_VSOCK connection. Firecracker creates the
vsock Unix-domain socket inside the jail owned by the per-VM uid/gid; the node
(a different uid) gets `EACCES`. The helper chowns just that one socket to its
caller and chmods it `0660`, leaving the rest of the per-VM isolation intact.

Returns `{:error, :socket_pending}` while firecracker has not yet created the
vsock socket, so the caller can keep waiting.

# `prepare`

```elixir
@spec prepare(Path.t(), Path.t(), Path.t(), non_neg_integer(), non_neg_integer()) ::
  :ok | {:error, err()}
```

Prepare `chroot_root`'s boot artifacts: stage the `kernel` file in and `mknod`
a node mirroring the rootfs `device`, both owned `uid:gid`. The helper places
them at the fixed in-jail names (`/vmlinux`, `/rootfs`) and reads the device's
major:minor itself.

# `remove`

```elixir
@spec remove(Path.t(), Path.t()) :: :ok | {:error, err()}
```

Remove a VM's stale jail before (re)launch: recursively delete the per-VM
chroot dir and rmdir its (empty) cgroup leaf. Idempotent - a first boot with no
prior state is a no-op. The helper confines `chroot` under the jail base and
`cgroup` under `/sys/fs/cgroup` (see `native/suidhelper`).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
