Sandbox Contract
link-sandbox-contract: the sandbox's policy, independent of its
implementation. It reads a sandbox's spec, resolves its permissions,
and checks addresses and names on the network, with no command line,
backend or proxy, for every side that edits or enforces a policy.
The spec
Spec is a sandbox's spec, a TOML file whose sections are its only
grants (Sandbox Spec):
Files, Network (its NetworkMode), Internet, Lan, Localhost
(its Port), Tools, Browser and Commands, each with an Os
table. It's here, in its own contract, since more than the sandbox
plugin keeps one: an agent's file, a harness's grants.
What it leaves to others
What a spec opens on a machine is the confinement resolver's, and its
refusals that need the machine itself are the sandbox plugin's: another
plugin has a spec checked by running lnk sandbox.
Its parts
spec::grants is the grant algebra policy editors share (union),
spec::resolve the OS overrides and authored paths, and
spec::schema the schema and documentation made from the type
(Section), which lnk sandbox spec --keys and --schema print.
The programs a sandbox may run
Programs is Any ([commands] allow = ["*"]) or Only these, by
path: a file, or a folder of them; none, nothing. Its
requirement_policy names the effective command policy, unrestricted
or restricted.
Folders every sandbox hides
hidden_dirs gives the folders every sandbox hides, whatever it's
allowed, but for what it names in them: ~/Link/Agents (agents_dir,
a folder per agent, hidden from every sandbox but an agent's own),
~/Link/Teams (teams_dir, hidden but for what a member is granted of
it) and ~/Link/History (history_dir, what Link keeps a while of
what's gone).
A folder no sandbox may write
unsafe_files says why no sandbox may write a folder, when it mustn't:
where writing is a way out of a sandbox (programs and settings that run
or are read outside it) or holds the user's keys.
Variables a caller can't give
check_given_variable refuses a variable a caller can't give a
sandboxed program: those lnk sandbox run keeps or sets itself, the
dynamic loader's (LD_*, DYLD_*) and a proxy's. Startup hooks and
interpreter search paths are refused too: an environment grant must not
install code before the requested command starts.
What Linux shows of the machine
system::LINUX_READS is what Linux's sandbox shows a program of the
machine outside its own folders, read only, those that exist: the
system's programs and libraries, and selected public settings from
/etc. Anything kept in them, whatever its mode, a sandboxed program
running as its owner can read; /run, /tmp and the homes it gives
fresh.
A box's users
box_users is what the box plugin writes of a box's users (lnk box user) and every other side reads: where root keeps them, the line that
lets a key in, and the one way into a user's sandbox, for an SSH session
and a run alike.
Where root keeps them
In /etc/lnk/users/<name>/, where neither they nor anything they run
writes: user.toml (BoxUser, their folder and key), <name>.toml
(their sandbox's spec, its paths absolute) and authorized_keys, which
sshd reads for them in place of their own, for the group lnk-users
(GROUP).
The line that lets a key in
line gives it, restrict,pty,command="..." entering the sandbox:
restrict turns off port, agent and X11 forwarding and ~/.ssh/rc,
each a way around the sandbox, and pty gives back a terminal. Their
login shell is /bin/sh, which reads no file of theirs before the
command, and the programs are root's copies in /usr/local/lib/lnk.
Tests
LNK_TEST_BOX_ROOT (TEST_ROOT) puts a test's folder in place of /,
for tests of a stand-in box; only a debug build reads it.
An ordinary box's workers
box_workers is the root launcher of an ordinary box: its settings in
/etc/lnk/workers.json (CONFIG), ordinary with its Controller
(uid, gid, groups) or packed, and the program it runs,
/usr/local/lib/lnk/lnk-sandbox (PROGRAM). Packed boxes use their
slot users; computers keep the person's explicit keeper fallback.
privileged
The root-owned helper: only an already authorized controller can ask sudo, and no sudo rule is given to a worker. It keeps explicitly inherited descriptors (the proxy's namespace handshake), and the child's given environment.