Sitelet https://github.com/devhttps/omarchy/commit/df819a6f9869b080f2d8ba88e3be0b21023d6487
Skip to content

Commit df819a6

Browse files
ryanrhughesdhh
andcommitted
Close three paths from an unprivileged session to root
Apply the Omabot patch on Quattro, verify effective SSH hardening, prevent stored provisioning state from restoring the blanket input-group grant, and stop Omarchy from shipping asdcontrol authorization that belongs to the package. Co-authored-by: David Heinemeier Hansson <david@hey.com>
1 parent 943d2fc commit df819a6

10 files changed

Lines changed: 274 additions & 70 deletions

‎bin/omarchy-provision-owner‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -677,11 +677,15 @@ user_groups() {
677677
if [[ -f $PROVISIONING_DIR/groups ]]; then
678678
while IFS= read -r group; do
679679
[[ -n $group ]] || continue
680-
# Never grant docker at first boot, even if an older install recorded it
681-
# (or a factory snapshot predating the opt-in default carries it): the
682-
# docker group is root-equivalent. It is opt-in via
683-
# omarchy-setup-security-sudoless-docker.
680+
# Never replay old privileged group defaults. Docker is always opt-in.
681+
# Input is only retained when the factory image has one of the features
682+
# whose installer deliberately grants access to raw input devices.
684683
[[ $group == "docker" ]] && continue
684+
if [[ $group == "input" ]] &&
685+
! pacman -Qq xpadneo-dkms &>/dev/null &&
686+
! pacman -Qq ydotool &>/dev/null; then
687+
continue
688+
fi
685689
getent group "$group" >/dev/null || continue
686690
[[ ",$groups," == *",$group,"* ]] || groups+=",$group"
687691
done <"$PROVISIONING_DIR/groups"

‎bin/omarchy-setup-security-sshd‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,48 @@ authorize_pasted_key() {
143143
authorize_key "$key" || exit 1
144144
}
145145

146+
# Only called after a key is authorized. Disabling password authentication
147+
# before then could lock the owner out of the machine.
148+
disable_password_auth() {
149+
local config=/etc/ssh/sshd_config.d/10-omarchy-hardening.conf
150+
local effective_config
151+
152+
if [[ ! -s $AUTHORIZED_KEYS ]]; then
153+
echo -e "\e[31mCannot disable SSH password authentication without an authorized key.\e[0m" >&2
154+
return 1
155+
fi
156+
157+
echo "Disabling SSH password authentication, now that a key is authorized..."
158+
sudo install -Dm644 /dev/stdin "$config" <<'CONF'
159+
# Written by omarchy-setup-security-sshd once an SSH key was authorized.
160+
# Delete this file and reload sshd to allow password logins again.
161+
PasswordAuthentication no
162+
KbdInteractiveAuthentication no
163+
CONF
164+
165+
# Validate before reloading: a config sshd rejects would otherwise take the
166+
# service down on its next restart, potentially stranding a remote owner.
167+
if ! sudo sshd -t; then
168+
echo -e "\e[31msshd rejected the hardening config; removing it and leaving passwords on.\e[0m" >&2
169+
sudo rm -f "$config"
170+
return 1
171+
fi
172+
173+
# Syntax alone is insufficient because sshd uses the first value it reads for
174+
# these settings. An earlier administrator rule could leave passwords enabled.
175+
if ! effective_config=$(sudo sshd -T) ||
176+
! grep -qxF "passwordauthentication no" <<<"$effective_config" ||
177+
! grep -qxF "kbdinteractiveauthentication no" <<<"$effective_config"; then
178+
echo -e "\e[31msshd did not apply the password-authentication restrictions; removing the ineffective config.\e[0m" >&2
179+
sudo rm -f "$config"
180+
return 1
181+
fi
182+
183+
# Reload rather than restart so an administrator already connected keeps
184+
# their session.
185+
sudo systemctl reload sshd.service
186+
}
187+
146188
echo -e "\e[32mSetting up SSH server access with key-based authentication.\n\e[0m"
147189

148190
setup_sshd
@@ -161,5 +203,8 @@ else
161203
esac
162204
fi
163205

206+
disable_password_auth
207+
164208
echo -e "\e[32m\nPerfect! The SSH server is running and your key is authorized.\e[0m"
209+
echo "Password logins are off; this machine now accepts authorized keys only."
165210
echo "You can now connect with: ssh $USER@$(hostname)"

‎etc/sudoers.d/omarchy-asdcontrol‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎install/hardware/all.sh‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ run_logged "$OMARCHY_INSTALL/hardware/dell-xps-touchpad-haptics.sh"
44
run_logged "$OMARCHY_INSTALL/hardware/surface.sh"
55

66
run_logged "$OMARCHY_INSTALL/hardware/network.sh"
7-
run_logged "$OMARCHY_INSTALL/hardware/input-group.sh"
87
run_logged "$OMARCHY_INSTALL/hardware/set-wireless-regdom.sh"
98
run_logged "$OMARCHY_INSTALL/hardware/fix-fkeys.sh"
109
run_logged "$OMARCHY_INSTALL/hardware/fix-synaptic-touchpad.sh"

‎install/hardware/input-group.sh‎

Lines changed: 0 additions & 11 deletions
This file was deleted.

‎migrations/1787865477.sh‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
echo "Drop the default input group grant, which allowed unprivileged keylogging"
2+
3+
# Membership of `input` gives raw read/write access to /dev/input/event*: any
4+
# process running as the user can capture keystrokes and synthesize input. The
5+
# blanket grant is unnecessary: the Xbox-controller and ydotool installers add
6+
# the group themselves when those features are deliberately installed.
7+
#
8+
# Preserve membership where one of those opt-in features is present; removing
9+
# it there would break the feature the user chose to install.
10+
if id -nG "$USER" | grep -qw input; then
11+
if pacman -Qq xpadneo-dkms &>/dev/null || pacman -Qq ydotool &>/dev/null; then
12+
echo "Keeping $USER in the input group: controller or ydotool support is installed."
13+
else
14+
sudo gpasswd -d "$USER" input >/dev/null
15+
echo "Removed $USER from the input group. Log out and back in to apply."
16+
omarchy-state set reboot-required
17+
fi
18+
fi
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
source "$(dirname "$0")/base-test.sh"
6+
7+
migration="$ROOT/migrations/1787865477.sh"
8+
test_dir=$(mktemp -d)
9+
trap 'rm -rf "$test_dir"' EXIT
10+
11+
stub_bin="$test_dir/bin"
12+
mkdir -p "$stub_bin"
13+
14+
cat >"$stub_bin/id" <<'STUB'
15+
#!/bin/bash
16+
printf '%s\n' "${STUB_GROUPS:-wheel}"
17+
STUB
18+
cat >"$stub_bin/pacman" <<'STUB'
19+
#!/bin/bash
20+
[[ $1 == "-Qq" ]] || exit 2
21+
[[ " ${STUB_PACKAGES:-} " == *" $2 "* ]]
22+
STUB
23+
cat >"$stub_bin/sudo" <<'STUB'
24+
#!/bin/bash
25+
exec "$@"
26+
STUB
27+
cat >"$stub_bin/gpasswd" <<'STUB'
28+
#!/bin/bash
29+
printf '%s\n' "$*" >>"${GPASSWD_CALLS:?}"
30+
STUB
31+
cat >"$stub_bin/omarchy-state" <<'STUB'
32+
#!/bin/bash
33+
printf '%s\n' "$*" >>"${STATE_CALLS:?}"
34+
STUB
35+
chmod +x "$stub_bin"/*
36+
37+
gpasswd_calls="$test_dir/gpasswd-calls"
38+
state_calls="$test_dir/state-calls"
39+
40+
run_migration() {
41+
rm -f "$gpasswd_calls" "$state_calls"
42+
USER=tester STUB_GROUPS="$1" STUB_PACKAGES="${2:-}" \
43+
GPASSWD_CALLS="$gpasswd_calls" STATE_CALLS="$state_calls" \
44+
PATH="$stub_bin:$PATH" bash -euo pipefail "$migration"
45+
}
46+
47+
run_migration "wheel input" >/dev/null
48+
grep -qxF -- "-d tester input" "$gpasswd_calls" || fail "migration removes default input membership"
49+
grep -qxF "set reboot-required" "$state_calls" || fail "migration flags the session change for reboot"
50+
pass "migration removes the blanket input grant"
51+
52+
run_migration "wheel" >/dev/null
53+
[[ ! -e $gpasswd_calls ]] || fail "migration does not remove an already-absent group"
54+
[[ ! -e $state_calls ]] || fail "migration does not flag a reboot when nothing changed"
55+
pass "migration is idempotent after input membership is gone"
56+
57+
run_migration "wheel input" xpadneo-dkms >/dev/null
58+
[[ ! -e $gpasswd_calls ]] || fail "migration preserves input for controller support"
59+
[[ ! -e $state_calls ]] || fail "preserved controller support does not flag a reboot"
60+
61+
run_migration "wheel input" ydotool >/dev/null
62+
[[ ! -e $gpasswd_calls ]] || fail "migration preserves input for ydotool"
63+
[[ ! -e $state_calls ]] || fail "preserved ydotool support does not flag a reboot"
64+
pass "migration preserves deliberate input-group opt-ins"
Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
#!/bin/bash
22
#
3-
# The install scripts that grant group memberships must record them in the provisioning
4-
# groups file (for first-boot user creation and factory reset) and only call
5-
# usermod when the install user actually exists.
6-
#
7-
# Docker is deliberately excluded: the docker group is root-equivalent, so it is
8-
# no longer granted at install time (opt in with omarchy-setup-security-sudoless-docker).
3+
# Privileged groups are never granted by the default install. Docker remains an
4+
# explicit opt-in, and raw input-device access is granted only by the optional
5+
# controller and ydotool installers.
96

107
set -euo pipefail
118

@@ -16,13 +13,7 @@ trap 'rm -rf "$TMPDIR"' EXIT
1613

1714
export OMARCHY_PROVISIONING_DIR="$TMPDIR/provisioning"
1815

19-
# Stub getent/usermod: the fake system knows only the user "existing".
2016
mkdir -p "$TMPDIR/bin"
21-
cat >"$TMPDIR/bin/getent" <<'STUB'
22-
#!/bin/bash
23-
[[ $1 == passwd && $2 == existing ]] && { echo "existing:x:1000:1000::/home/existing:/bin/bash"; exit 0; }
24-
exit 2
25-
STUB
2617
cat >"$TMPDIR/bin/usermod" <<STUB
2718
#!/bin/bash
2819
echo "\$@" >>"$TMPDIR/usermod.calls"
@@ -44,48 +35,31 @@ cat >"$TMPDIR/bin/sudo" <<STUB
4435
echo "\$@" >>"$TMPDIR/sudo.calls"
4536
exec "\$@"
4637
STUB
47-
chmod +x "$TMPDIR/bin"/{getent,usermod,groupadd,install,find,sudo}
38+
chmod +x "$TMPDIR/bin"/{usermod,groupadd,install,find,sudo}
4839
export PATH="$TMPDIR/bin:$PATH"
4940
export OMARCHY_PATH="$ROOT"
5041

51-
# No install user (deferred-provisioning install): groups recorded, usermod not called.
42+
# A deferred-provisioning install records neither privileged group.
5243
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/docker.sh"
53-
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/hardware/input-group.sh"
5444
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/browser-policy.sh"
5545

56-
[[ -f $OMARCHY_PROVISIONING_DIR/groups ]] || fail "groups file written without an install user"
57-
grep -qxF input "$OMARCHY_PROVISIONING_DIR/groups" || fail "input group recorded"
58-
! grep -qxF omarchy-browser-policy "$OMARCHY_PROVISIONING_DIR/groups" ||
59-
fail "browser-policy group must not be recorded"
46+
[[ ! -f $OMARCHY_PROVISIONING_DIR/groups ]] ||
47+
! grep -Eq '^(docker|input)$' "$OMARCHY_PROVISIONING_DIR/groups" ||
48+
fail "default install must not record docker or input groups"
6049
[[ ! -f $TMPDIR/usermod.calls ]] || fail "usermod not called without an install user"
6150
[[ ! -f $TMPDIR/groupadd.calls ]] || ! grep -F omarchy-browser-policy "$TMPDIR/groupadd.calls" >/dev/null ||
6251
fail "browser-policy group is not created"
6352
grep -F -- '-d -m 0755 -o root -g root /etc/chromium/policies/managed' "$TMPDIR/install.calls" >/dev/null ||
6453
fail "browser-policy directory is created root-owned"
65-
pass "deferred provisioning records groups without calling usermod"
66-
67-
# The docker group is root-equivalent and must never be granted automatically.
68-
! grep -qxF docker "$OMARCHY_PROVISIONING_DIR/groups" || fail "docker group must not be recorded"
69-
pass "docker group is not recorded at install"
54+
pass "deferred provisioning records no privileged groups"
7055

71-
# Missing user (defensive): no usermod either.
72-
OMARCHY_INSTALL_USER=ghost bash -eE "$ROOT/install/hardware/input-group.sh"
73-
OMARCHY_INSTALL_USER=ghost bash -eE "$ROOT/install/config/browser-policy.sh"
74-
[[ ! -f $TMPDIR/usermod.calls ]] || fail "usermod not called for a missing user"
75-
pass "missing install user defers group grants"
76-
77-
# Re-running never duplicates entries.
78-
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/hardware/input-group.sh"
79-
[[ $(grep -cxF input "$OMARCHY_PROVISIONING_DIR/groups") == 1 ]] || fail "input group recorded once"
80-
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/browser-policy.sh"
81-
pass "group recording is idempotent"
82-
83-
# Existing user: usermod applies the recorded groups, and docker is never among them.
56+
# The same remains true when an install user already exists.
8457
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/config/docker.sh"
85-
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/hardware/input-group.sh"
8658
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/config/browser-policy.sh"
87-
grep -qx -- "-aG input existing" "$TMPDIR/usermod.calls" || fail "usermod grants input to the install user"
88-
! grep -q -- "omarchy-browser-policy" "$TMPDIR/usermod.calls" ||
89-
fail "usermod must not grant browser-policy to the install user"
90-
! grep -q -- "docker" "$TMPDIR/usermod.calls" || fail "usermod must not grant docker to the install user"
91-
pass "existing install user gets input but never docker or browser-policy"
59+
[[ ! -f $TMPDIR/usermod.calls ]] || fail "default install must not grant privileged groups"
60+
pass "existing install user gets neither docker nor input access"
61+
62+
! grep -q 'hardware/input-group.sh' "$ROOT/install/hardware/all.sh" ||
63+
fail "hardware setup must not call the removed input-group grant"
64+
[[ ! -e $ROOT/install/hardware/input-group.sh ]] || fail "blanket input-group grant is removed"
65+
pass "hardware setup has no blanket input-group grant"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
source "$(dirname "$0")/base-test.sh"
6+
7+
test_dir=$(mktemp -d)
8+
trap 'rm -rf "$test_dir"' EXIT
9+
10+
stub_bin="$test_dir/bin"
11+
mkdir -p "$stub_bin"
12+
13+
cat >"$stub_bin/omarchy-pkg-add" <<'STUB'
14+
#!/bin/bash
15+
printf 'pkg %s\n' "$*" >>"${CALL_LOG:?}"
16+
STUB
17+
cat >"$stub_bin/omarchy-cmd-missing" <<'STUB'
18+
#!/bin/bash
19+
exit 0
20+
STUB
21+
cat >"$stub_bin/systemctl" <<'STUB'
22+
#!/bin/bash
23+
printf 'systemctl %s\n' "$*" >>"${CALL_LOG:?}"
24+
STUB
25+
cat >"$stub_bin/sshd" <<'STUB'
26+
#!/bin/bash
27+
case $1 in
28+
-t)
29+
[[ ${SSHD_SYNTAX_VALID:-1} == 1 ]]
30+
;;
31+
-T)
32+
printf 'passwordauthentication %s\n' "${SSHD_PASSWORD_AUTH:-no}"
33+
printf 'kbdinteractiveauthentication %s\n' "${SSHD_KBD_AUTH:-no}"
34+
;;
35+
*)
36+
exit 2
37+
;;
38+
esac
39+
STUB
40+
cat >"$stub_bin/sudo" <<'STUB'
41+
#!/bin/bash
42+
case $1 in
43+
install)
44+
destination="${TEST_ROOT:?}${4:?}"
45+
/usr/bin/mkdir -p "${destination%/*}"
46+
/usr/bin/install -Dm644 /dev/stdin "$destination"
47+
;;
48+
rm)
49+
/usr/bin/rm -f "${TEST_ROOT:?}${3:?}"
50+
;;
51+
*)
52+
exec "$@"
53+
;;
54+
esac
55+
STUB
56+
chmod +x "$stub_bin"/*
57+
58+
ssh-keygen -q -t ed25519 -N "" -f "$test_dir/key"
59+
public_key=$(<"$test_dir/key.pub")
60+
61+
run_setup() {
62+
local scenario="$1"
63+
local home="$test_dir/$scenario/home"
64+
local root="$test_dir/$scenario/root"
65+
66+
mkdir -p "$home" "$root"
67+
: >"$test_dir/$scenario.calls"
68+
69+
HOME="$home" TEST_ROOT="$root" CALL_LOG="$test_dir/$scenario.calls" \
70+
SSHD_SYNTAX_VALID="${SSHD_SYNTAX_VALID:-1}" \
71+
SSHD_PASSWORD_AUTH="${SSHD_PASSWORD_AUTH:-no}" \
72+
SSHD_KBD_AUTH="${SSHD_KBD_AUTH:-no}" \
73+
PATH="$stub_bin:$PATH" \
74+
bash "$ROOT/bin/omarchy-setup-security-sshd" --key="$public_key"
75+
}
76+
77+
output=$(run_setup success)
78+
config="$test_dir/success/root/etc/ssh/sshd_config.d/10-omarchy-hardening.conf"
79+
grep -qxF "PasswordAuthentication no" "$config" || fail "SSH setup disables password authentication"
80+
grep -qxF "KbdInteractiveAuthentication no" "$config" || fail "SSH setup disables keyboard-interactive authentication"
81+
grep -qxF "systemctl reload sshd.service" "$test_dir/success.calls" || fail "SSH setup reloads the validated config"
82+
grep -q "Password logins are off" <<<"$output" || fail "SSH setup reports hardening after it succeeds"
83+
pass "SSH setup authorizes a key and disables password logins"
84+
85+
if SSHD_PASSWORD_AUTH=yes run_setup ineffective >"$test_dir/ineffective.output" 2>&1; then
86+
fail "SSH setup must fail when password authentication remains effective"
87+
fi
88+
[[ ! -e $test_dir/ineffective/root/etc/ssh/sshd_config.d/10-omarchy-hardening.conf ]] ||
89+
fail "SSH setup removes an ineffective hardening config"
90+
! grep -qF "systemctl reload sshd.service" "$test_dir/ineffective.calls" ||
91+
fail "SSH setup must not reload ineffective hardening"
92+
! grep -q "Password logins are off" "$test_dir/ineffective.output" ||
93+
fail "SSH setup must not claim ineffective hardening succeeded"
94+
pass "SSH setup verifies the effective daemon settings"
95+
96+
if SSHD_SYNTAX_VALID=0 run_setup invalid >"$test_dir/invalid.output" 2>&1; then
97+
fail "SSH setup must fail when sshd rejects its config"
98+
fi
99+
[[ ! -e $test_dir/invalid/root/etc/ssh/sshd_config.d/10-omarchy-hardening.conf ]] ||
100+
fail "SSH setup removes a rejected hardening config"
101+
! grep -qF "systemctl reload sshd.service" "$test_dir/invalid.calls" ||
102+
fail "SSH setup must not reload a rejected config"
103+
! grep -q "Password logins are off" "$test_dir/invalid.output" ||
104+
fail "SSH setup must not claim rejected hardening succeeded"
105+
pass "SSH setup fails safely when sshd rejects the config"

0 commit comments

Comments
 (0)