Skip to content
Harobanda

What it refuses

Ask a program, from inside, what it can reach.

The reference machine qemu_confine runs the same small witness as six programs whose files differ by a word or two, and each reports what it can actually reach. The boot calls each one a world: one service while it runs, inside walls the kernel keeps. These lines are from its pin — a saved copy of a boot someone read and found right, which every later boot is compared with line by line.

two reference machines, from their pins
# blind: its file asks only to run programs -- NEEDS [process]
boot: start blind -- pid N -- /harb confined eth0 /data /var/log
confined: eth0 -- no such interface from here: this world has a network namespace of its own and there is nothing in it
confined: processes -- this world is pid N and can see the machine's other processes: one table for everybody
confined: /data -- an empty directory and nothing mounted on it: this world has a mount namespace of its own and the machine's storage is not in it
confined: /var/log -- an empty directory and nothing mounted on it: this world has a mount namespace of its own and the machine's storage is not in it
confined: the floor -- refused by the kernel (EPERM): this world cannot change the machine it runs on
confined: fork -- permitted: this world started another process, and this line is the child speaking

# still: its file asks for the network and the disks, not to start programs
confined: fork -- refused by the kernel (EPERM): this world cannot start another process

# qemu_egress: its network may reach one range, and nowhere else
boot: egress lan -- 10.9.0.0/16 and nowhere else: no default route
reach 8.8.8.8 -- no route: this machine knows no way there

Word for word from machines/qemu_confine.expected and machines/qemu_egress.expected; the lines starting with # are this page's. blind got exactly what it asked for and nothing else: it may start programs, and it has no network and none of the machine's disks.

The floor

Some things no file can ask for.

In this project's words, the floor is what no world may do, whatever it declared. The kernel refuses these 25 calls to every program, in eight groups, each kept for a reason. It is a named list, never a claim that everything else is safe.

attaching or detaching disksthe file says which disks a program sees — mount, umount2, pivot_root
loading code into the kernelthe kernel is the one built into the image — init_module, finit_module, delete_module, kexec_load, kexec_file_load
restarting the boxonly the machine's first program decides when it stops — reboot
setting the clocka program may read the time, never move it under everyone else — settimeofday, clock_settime, adjtimex, clock_adjtime
renaming the machinewho the machine says it is — sethostname, setdomainname
building or entering walls of its ownthe walls are built before the program starts, and are not its to widen, narrow or leave — unshare, setns
looking inside another programanother program's memory is not its to read or steer — ptrace
touching the machine's own plumbingswap, kernel filters, the kernel's log, process accounting, device files — swapon, swapoff, bpf, syslog, acct, mknod, mknodat

The list is off_limits in src/confine.zig, each group under the sentence that explains it.

Next: The ten agent threats → What a hijacked agent can still reach, threat by threat.