From 9afea75f931070f68be74917ff6d0fae6dfd9f22 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 8 Oct 2026 20:33:21 +0200 Subject: [PATCH] sudo: give every command run through sudo a terminal of its own An agent the operator starts as the agent account through sudo (hq ADR 0266) would otherwise share the operator's terminal and could push keystrokes into their shell after it ends. sudo still runs without a terminal for the mesh's own tools, so nothing they do changes. --- modules/sudo/README.md | 5 ++++- modules/sudo/cmd/sudo-tools/manifest_test.go | 2 +- modules/sudo/module.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/sudo/README.md b/modules/sudo/README.md index 2481f429..e6236069 100644 --- a/modules/sudo/README.md +++ b/modules/sudo/README.md @@ -6,7 +6,10 @@ Privilege escalation as a module (novox/hq to-be 42 Phase 1, research 027). - The `sudo` package. - `/etc/sudoers.d/10-mesh-operator`, root's, mode 0440, written whole: - ` ALL=(ALL:ALL) NOPASSWD: ALL`. + ` ALL=(ALL:ALL) NOPASSWD: ALL`, and `Defaults use_pty`: a command run through sudo gets a + terminal of its own, so an agent the operator starts as the agent account (hq ADR 0266) cannot push + keystrokes into the operator's shell. The rule names the operator account and nobody else: the agent + account has no sudo. That one line is what the mesh's acting tools assume: the packet filter, the service manager and the intrusion prevention tools act through `sudo -n` as the operator account (to-be 38 WP4). Before this diff --git a/modules/sudo/cmd/sudo-tools/manifest_test.go b/modules/sudo/cmd/sudo-tools/manifest_test.go index 60ed77d0..aba08c85 100644 --- a/modules/sudo/cmd/sudo-tools/manifest_test.go +++ b/modules/sudo/cmd/sudo-tools/manifest_test.go @@ -41,7 +41,7 @@ func TestTheDropInGrantsExactlyTheOperatorAccountAndParses(t *testing.T) { rules = append(rules, l) } } - if len(rules) != 1 || rules[0] != "${machine:account} ALL=(ALL:ALL) NOPASSWD: ALL" { + if len(rules) != 2 || rules[0] != "Defaults use_pty" || rules[1] != "${machine:account} ALL=(ALL:ALL) NOPASSWD: ALL" { t.Fatalf("rules: %q", rules) } if !strings.HasSuffix(content, "\n") { diff --git a/modules/sudo/module.json b/modules/sudo/module.json index a9a5fc93..41d2c828 100644 --- a/modules/sudo/module.json +++ b/modules/sudo/module.json @@ -20,7 +20,7 @@ "type": "file", "path": "/etc/sudoers.d/10-mesh-operator", "mode": "0440", - "content": "# The mesh's (module sudo, novox/hq to-be 42, research 027): the operator account escalates\n# without a prompt. The mesh's tools that act as root run `sudo -n` as this account and rely on it;\n# until this file, every machine said so only in a line set by hand in /etc/sudoers.\n# Written whole at every push: an edit here is overwritten. A file of this directory whose name\n# holds a dot or ends in ~ is not read by sudo; this name holds neither.\n${machine:account} ALL=(ALL:ALL) NOPASSWD: ALL\n" + "content": "# The mesh's (module sudo, novox/hq to-be 42, research 027): the operator account escalates\n# without a prompt. The mesh's tools that act as root run `sudo -n` as this account and rely on it;\n# until this file, every machine said so only in a line set by hand in /etc/sudoers.\n# Written whole at every push: an edit here is overwritten. A file of this directory whose name\n# holds a dot or ends in ~ is not read by sudo; this name holds neither.\n# Every command run through sudo gets a terminal of its own (novox/hq ADR 0266): an agent the operator\n# starts as the agent account through sudo cannot push keystrokes into the operator's shell (TIOCSTI).\nDefaults use_pty\n${machine:account} ALL=(ALL:ALL) NOPASSWD: ALL\n" } ], "build": {