Skip to main content

max / alloy

3.7 KB · 72 lines History Blame Raw
1 /* Alloy: the installer, reached over ssh, becoming root.
2 *
3 * `alloy install` does not escalate. On tty1 it does not need to —
4 * alloy-installer.service runs it as root — and over ssh it lands in the
5 * unprivileged `installer` account, where every privileged stage fails:
6 *
7 * error: Installing to disk: Querying root privilege: This command must be
8 * executed as the root user
9 * wipefs: error: /dev/vda: probing initialization failed: Permission denied
10 *
11 * Measured 2026-08-26 (GO alloy 2cf04f20). The wizard drew and answered all six
12 * steps and the erase confirmation before dying, so the headless flow the whole
13 * minting design rests on — boot the ISO, `ssh installer@<name>.local`, answer
14 * the questions — reached a wizard that could not write a disk.
15 *
16 * So etc/ssh/sshd_config.d/20-alloy-installer.conf runs the wizard under
17 * `run0`, and run0 asks polkit for org.freedesktop.systemd1.manage-units.
18 * Without a rule it asks a human, and there is no human on the far end of a
19 * headless install. This is that rule.
20 *
21 * WHY THIS GRANTS OVER SSH WHEN ITS SIBLING REFUSES TO. 50-alloy-settings.rules
22 * requires `active && local` and says so at length: its justification is "the
23 * person sitting at the machine", which an ssh login is not. That reasoning is
24 * untouched here because this grant rests on something else entirely — not on
25 * where the caller is, but on the fact that the account cannot exist anywhere a
26 * grant would matter.
27 *
28 * THE GATE IS STILL THE ACCOUNT. `installer` is created by
29 * alloy-installer-ssh.service, which carries
30 * ConditionKernelCommandLine=alloy.installer, which only the ISO's GRUB entries
31 * set. On an installed machine there is no such user, so the rule below matches
32 * nobody and this file is inert — exactly as the sshd drop-in beside it is
33 * inert for the same reason. A polkit rule cannot read the kernel command line,
34 * so it cannot check that itself; the Containerfile asserts the three files
35 * agree instead.
36 *
37 * WHAT THIS IS WORTH TO SOMEONE WHO HAS THE KEY, stated plainly rather than
38 * elided: manage-units is a password-less path to root, so anyone who can open
39 * this session can run anything as root on that medium. They could already
40 * partition its disks and write an OS to them, which is what the session is
41 * for. The exposure is a live installer medium on a LAN, and the credential is
42 * a key baked in at mint time. Widening it further would be a different
43 * decision; this does not.
44 *
45 * Ruled (a) by Max on 2026-08-26, against giving the account uid 0 and against
46 * a NOPASSWD sudoers line. Both would have worked. This one keeps the account
47 * unprivileged in its own right and puts the grant in a file somebody can read.
48 *
49 * Ordering: polkit reads /etc/polkit-1/rules.d and /usr/share/polkit-1/rules.d
50 * as one lexically sorted set, and the first rule to return a value wins. 50-
51 * so a user drop-in in /etc with a lower number overrides it outright.
52 */
53
54 polkit.addRule(function (action, subject) {
55 /* One action and one user. run0 asks for manage-units and nothing else, and
56 * the only thing that can use the grant is the ForceCommand that needs it:
57 * sshd replaces whatever the client asked to run, so there is no command
58 * line to get wrong and no shell to fall back to.
59 *
60 * Returning nothing rather than NOT for everything else, so this file
61 * grants and never denies — same rule as its sibling, and for the same
62 * reason: a NOT here would override a later rule with a better reason to
63 * allow something.
64 */
65 if (action.id !== "org.freedesktop.systemd1.manage-units") {
66 return;
67 }
68 if (subject.user === "installer") {
69 return polkit.Result.YES;
70 }
71 });
72