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>
This commit is contained in:
Ryan Hughes
2026-08-30 12:54:08 -04:00
co-authored by David Heinemeier Hansson
parent 943d2fcbe9
commit df819a6f98
10 changed files with 274 additions and 70 deletions
+8 -4
View File
@@ -677,11 +677,15 @@ user_groups() {
if [[ -f $PROVISIONING_DIR/groups ]]; then
while IFS= read -r group; do
[[ -n $group ]] || continue
# Never grant docker at first boot, even if an older install recorded it
# (or a factory snapshot predating the opt-in default carries it): the
# docker group is root-equivalent. It is opt-in via
# omarchy-setup-security-sudoless-docker.
# Never replay old privileged group defaults. Docker is always opt-in.
# Input is only retained when the factory image has one of the features
# whose installer deliberately grants access to raw input devices.
[[ $group == "docker" ]] && continue
if [[ $group == "input" ]] &&
! pacman -Qq xpadneo-dkms &>/dev/null &&
! pacman -Qq ydotool &>/dev/null; then
continue
fi
getent group "$group" >/dev/null || continue
[[ ",$groups," == *",$group,"* ]] || groups+=",$group"
done <"$PROVISIONING_DIR/groups"
+45
View File
@@ -143,6 +143,48 @@ authorize_pasted_key() {
authorize_key "$key" || exit 1
}
# Only called after a key is authorized. Disabling password authentication
# before then could lock the owner out of the machine.
disable_password_auth() {
local config=/etc/ssh/sshd_config.d/10-omarchy-hardening.conf
local effective_config
if [[ ! -s $AUTHORIZED_KEYS ]]; then
echo -e "\e[31mCannot disable SSH password authentication without an authorized key.\e[0m" >&2
return 1
fi
echo "Disabling SSH password authentication, now that a key is authorized..."
sudo install -Dm644 /dev/stdin "$config" <<'CONF'
# Written by omarchy-setup-security-sshd once an SSH key was authorized.
# Delete this file and reload sshd to allow password logins again.
PasswordAuthentication no
KbdInteractiveAuthentication no
CONF
# Validate before reloading: a config sshd rejects would otherwise take the
# service down on its next restart, potentially stranding a remote owner.
if ! sudo sshd -t; then
echo -e "\e[31msshd rejected the hardening config; removing it and leaving passwords on.\e[0m" >&2
sudo rm -f "$config"
return 1
fi
# Syntax alone is insufficient because sshd uses the first value it reads for
# these settings. An earlier administrator rule could leave passwords enabled.
if ! effective_config=$(sudo sshd -T) ||
! grep -qxF "passwordauthentication no" <<<"$effective_config" ||
! grep -qxF "kbdinteractiveauthentication no" <<<"$effective_config"; then
echo -e "\e[31msshd did not apply the password-authentication restrictions; removing the ineffective config.\e[0m" >&2
sudo rm -f "$config"
return 1
fi
# Reload rather than restart so an administrator already connected keeps
# their session.
sudo systemctl reload sshd.service
}
echo -e "\e[32mSetting up SSH server access with key-based authentication.\n\e[0m"
setup_sshd
@@ -161,5 +203,8 @@ else
esac
fi
disable_password_auth
echo -e "\e[32m\nPerfect! The SSH server is running and your key is authorized.\e[0m"
echo "Password logins are off; this machine now accepts authorized keys only."
echo "You can now connect with: ssh $USER@$(hostname)"
-1
View File
@@ -1 +0,0 @@
%wheel ALL=(ALL) NOPASSWD: /usr/bin/asdcontrol
-1
View File
@@ -4,7 +4,6 @@ run_logged "$OMARCHY_INSTALL/hardware/dell-xps-touchpad-haptics.sh"
run_logged "$OMARCHY_INSTALL/hardware/surface.sh"
run_logged "$OMARCHY_INSTALL/hardware/network.sh"
run_logged "$OMARCHY_INSTALL/hardware/input-group.sh"
run_logged "$OMARCHY_INSTALL/hardware/set-wireless-regdom.sh"
run_logged "$OMARCHY_INSTALL/hardware/fix-fkeys.sh"
run_logged "$OMARCHY_INSTALL/hardware/fix-synaptic-touchpad.sh"
-11
View File
@@ -1,11 +0,0 @@
# Give this user privileged input access for dictation tools + xbox controllers to work.
# Recorded for provisioning first-boot user creation and factory reset, granted directly
# when the install user already exists (deferred-provisioning installs create the user at
# first boot instead).
provisioning_dir="${OMARCHY_PROVISIONING_DIR:-/var/lib/omarchy/provisioning}"
mkdir -p "$provisioning_dir"
grep -qxF input "$provisioning_dir/groups" 2>/dev/null || echo input >>"$provisioning_dir/groups"
if [[ -n ${OMARCHY_INSTALL_USER:-} ]] && getent passwd "$OMARCHY_INSTALL_USER" >/dev/null; then
usermod -aG input "$OMARCHY_INSTALL_USER"
fi
+18
View File
@@ -0,0 +1,18 @@
echo "Drop the default input group grant, which allowed unprivileged keylogging"
# Membership of `input` gives raw read/write access to /dev/input/event*: any
# process running as the user can capture keystrokes and synthesize input. The
# blanket grant is unnecessary: the Xbox-controller and ydotool installers add
# the group themselves when those features are deliberately installed.
#
# Preserve membership where one of those opt-in features is present; removing
# it there would break the feature the user chose to install.
if id -nG "$USER" | grep -qw input; then
if pacman -Qq xpadneo-dkms &>/dev/null || pacman -Qq ydotool &>/dev/null; then
echo "Keeping $USER in the input group: controller or ydotool support is installed."
else
sudo gpasswd -d "$USER" input >/dev/null
echo "Removed $USER from the input group. Log out and back in to apply."
omarchy-state set reboot-required
fi
fi
+64
View File
@@ -0,0 +1,64 @@
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/base-test.sh"
migration="$ROOT/migrations/1787865477.sh"
test_dir=$(mktemp -d)
trap 'rm -rf "$test_dir"' EXIT
stub_bin="$test_dir/bin"
mkdir -p "$stub_bin"
cat >"$stub_bin/id" <<'STUB'
#!/bin/bash
printf '%s\n' "${STUB_GROUPS:-wheel}"
STUB
cat >"$stub_bin/pacman" <<'STUB'
#!/bin/bash
[[ $1 == "-Qq" ]] || exit 2
[[ " ${STUB_PACKAGES:-} " == *" $2 "* ]]
STUB
cat >"$stub_bin/sudo" <<'STUB'
#!/bin/bash
exec "$@"
STUB
cat >"$stub_bin/gpasswd" <<'STUB'
#!/bin/bash
printf '%s\n' "$*" >>"${GPASSWD_CALLS:?}"
STUB
cat >"$stub_bin/omarchy-state" <<'STUB'
#!/bin/bash
printf '%s\n' "$*" >>"${STATE_CALLS:?}"
STUB
chmod +x "$stub_bin"/*
gpasswd_calls="$test_dir/gpasswd-calls"
state_calls="$test_dir/state-calls"
run_migration() {
rm -f "$gpasswd_calls" "$state_calls"
USER=tester STUB_GROUPS="$1" STUB_PACKAGES="${2:-}" \
GPASSWD_CALLS="$gpasswd_calls" STATE_CALLS="$state_calls" \
PATH="$stub_bin:$PATH" bash -euo pipefail "$migration"
}
run_migration "wheel input" >/dev/null
grep -qxF -- "-d tester input" "$gpasswd_calls" || fail "migration removes default input membership"
grep -qxF "set reboot-required" "$state_calls" || fail "migration flags the session change for reboot"
pass "migration removes the blanket input grant"
run_migration "wheel" >/dev/null
[[ ! -e $gpasswd_calls ]] || fail "migration does not remove an already-absent group"
[[ ! -e $state_calls ]] || fail "migration does not flag a reboot when nothing changed"
pass "migration is idempotent after input membership is gone"
run_migration "wheel input" xpadneo-dkms >/dev/null
[[ ! -e $gpasswd_calls ]] || fail "migration preserves input for controller support"
[[ ! -e $state_calls ]] || fail "preserved controller support does not flag a reboot"
run_migration "wheel input" ydotool >/dev/null
[[ ! -e $gpasswd_calls ]] || fail "migration preserves input for ydotool"
[[ ! -e $state_calls ]] || fail "preserved ydotool support does not flag a reboot"
pass "migration preserves deliberate input-group opt-ins"
+17 -43
View File
@@ -1,11 +1,8 @@
#!/bin/bash
#
# The install scripts that grant group memberships must record them in the provisioning
# groups file (for first-boot user creation and factory reset) and only call
# usermod when the install user actually exists.
#
# Docker is deliberately excluded: the docker group is root-equivalent, so it is
# no longer granted at install time (opt in with omarchy-setup-security-sudoless-docker).
# Privileged groups are never granted by the default install. Docker remains an
# explicit opt-in, and raw input-device access is granted only by the optional
# controller and ydotool installers.
set -euo pipefail
@@ -16,13 +13,7 @@ trap 'rm -rf "$TMPDIR"' EXIT
export OMARCHY_PROVISIONING_DIR="$TMPDIR/provisioning"
# Stub getent/usermod: the fake system knows only the user "existing".
mkdir -p "$TMPDIR/bin"
cat >"$TMPDIR/bin/getent" <<'STUB'
#!/bin/bash
[[ $1 == passwd && $2 == existing ]] && { echo "existing:x:1000:1000::/home/existing:/bin/bash"; exit 0; }
exit 2
STUB
cat >"$TMPDIR/bin/usermod" <<STUB
#!/bin/bash
echo "\$@" >>"$TMPDIR/usermod.calls"
@@ -44,48 +35,31 @@ cat >"$TMPDIR/bin/sudo" <<STUB
echo "\$@" >>"$TMPDIR/sudo.calls"
exec "\$@"
STUB
chmod +x "$TMPDIR/bin"/{getent,usermod,groupadd,install,find,sudo}
chmod +x "$TMPDIR/bin"/{usermod,groupadd,install,find,sudo}
export PATH="$TMPDIR/bin:$PATH"
export OMARCHY_PATH="$ROOT"
# No install user (deferred-provisioning install): groups recorded, usermod not called.
# A deferred-provisioning install records neither privileged group.
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/docker.sh"
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/hardware/input-group.sh"
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/browser-policy.sh"
[[ -f $OMARCHY_PROVISIONING_DIR/groups ]] || fail "groups file written without an install user"
grep -qxF input "$OMARCHY_PROVISIONING_DIR/groups" || fail "input group recorded"
! grep -qxF omarchy-browser-policy "$OMARCHY_PROVISIONING_DIR/groups" ||
fail "browser-policy group must not be recorded"
[[ ! -f $OMARCHY_PROVISIONING_DIR/groups ]] ||
! grep -Eq '^(docker|input)$' "$OMARCHY_PROVISIONING_DIR/groups" ||
fail "default install must not record docker or input groups"
[[ ! -f $TMPDIR/usermod.calls ]] || fail "usermod not called without an install user"
[[ ! -f $TMPDIR/groupadd.calls ]] || ! grep -F omarchy-browser-policy "$TMPDIR/groupadd.calls" >/dev/null ||
fail "browser-policy group is not created"
grep -F -- '-d -m 0755 -o root -g root /etc/chromium/policies/managed' "$TMPDIR/install.calls" >/dev/null ||
fail "browser-policy directory is created root-owned"
pass "deferred provisioning records groups without calling usermod"
pass "deferred provisioning records no privileged groups"
# The docker group is root-equivalent and must never be granted automatically.
! grep -qxF docker "$OMARCHY_PROVISIONING_DIR/groups" || fail "docker group must not be recorded"
pass "docker group is not recorded at install"
# Missing user (defensive): no usermod either.
OMARCHY_INSTALL_USER=ghost bash -eE "$ROOT/install/hardware/input-group.sh"
OMARCHY_INSTALL_USER=ghost bash -eE "$ROOT/install/config/browser-policy.sh"
[[ ! -f $TMPDIR/usermod.calls ]] || fail "usermod not called for a missing user"
pass "missing install user defers group grants"
# Re-running never duplicates entries.
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/hardware/input-group.sh"
[[ $(grep -cxF input "$OMARCHY_PROVISIONING_DIR/groups") == 1 ]] || fail "input group recorded once"
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/browser-policy.sh"
pass "group recording is idempotent"
# Existing user: usermod applies the recorded groups, and docker is never among them.
# The same remains true when an install user already exists.
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/config/docker.sh"
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/hardware/input-group.sh"
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/config/browser-policy.sh"
grep -qx -- "-aG input existing" "$TMPDIR/usermod.calls" || fail "usermod grants input to the install user"
! grep -q -- "omarchy-browser-policy" "$TMPDIR/usermod.calls" ||
fail "usermod must not grant browser-policy to the install user"
! grep -q -- "docker" "$TMPDIR/usermod.calls" || fail "usermod must not grant docker to the install user"
pass "existing install user gets input but never docker or browser-policy"
[[ ! -f $TMPDIR/usermod.calls ]] || fail "default install must not grant privileged groups"
pass "existing install user gets neither docker nor input access"
! grep -q 'hardware/input-group.sh' "$ROOT/install/hardware/all.sh" ||
fail "hardware setup must not call the removed input-group grant"
[[ ! -e $ROOT/install/hardware/input-group.sh ]] || fail "blanket input-group grant is removed"
pass "hardware setup has no blanket input-group grant"
+105
View File
@@ -0,0 +1,105 @@
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/base-test.sh"
test_dir=$(mktemp -d)
trap 'rm -rf "$test_dir"' EXIT
stub_bin="$test_dir/bin"
mkdir -p "$stub_bin"
cat >"$stub_bin/omarchy-pkg-add" <<'STUB'
#!/bin/bash
printf 'pkg %s\n' "$*" >>"${CALL_LOG:?}"
STUB
cat >"$stub_bin/omarchy-cmd-missing" <<'STUB'
#!/bin/bash
exit 0
STUB
cat >"$stub_bin/systemctl" <<'STUB'
#!/bin/bash
printf 'systemctl %s\n' "$*" >>"${CALL_LOG:?}"
STUB
cat >"$stub_bin/sshd" <<'STUB'
#!/bin/bash
case $1 in
-t)
[[ ${SSHD_SYNTAX_VALID:-1} == 1 ]]
;;
-T)
printf 'passwordauthentication %s\n' "${SSHD_PASSWORD_AUTH:-no}"
printf 'kbdinteractiveauthentication %s\n' "${SSHD_KBD_AUTH:-no}"
;;
*)
exit 2
;;
esac
STUB
cat >"$stub_bin/sudo" <<'STUB'
#!/bin/bash
case $1 in
install)
destination="${TEST_ROOT:?}${4:?}"
/usr/bin/mkdir -p "${destination%/*}"
/usr/bin/install -Dm644 /dev/stdin "$destination"
;;
rm)
/usr/bin/rm -f "${TEST_ROOT:?}${3:?}"
;;
*)
exec "$@"
;;
esac
STUB
chmod +x "$stub_bin"/*
ssh-keygen -q -t ed25519 -N "" -f "$test_dir/key"
public_key=$(<"$test_dir/key.pub")
run_setup() {
local scenario="$1"
local home="$test_dir/$scenario/home"
local root="$test_dir/$scenario/root"
mkdir -p "$home" "$root"
: >"$test_dir/$scenario.calls"
HOME="$home" TEST_ROOT="$root" CALL_LOG="$test_dir/$scenario.calls" \
SSHD_SYNTAX_VALID="${SSHD_SYNTAX_VALID:-1}" \
SSHD_PASSWORD_AUTH="${SSHD_PASSWORD_AUTH:-no}" \
SSHD_KBD_AUTH="${SSHD_KBD_AUTH:-no}" \
PATH="$stub_bin:$PATH" \
bash "$ROOT/bin/omarchy-setup-security-sshd" --key="$public_key"
}
output=$(run_setup success)
config="$test_dir/success/root/etc/ssh/sshd_config.d/10-omarchy-hardening.conf"
grep -qxF "PasswordAuthentication no" "$config" || fail "SSH setup disables password authentication"
grep -qxF "KbdInteractiveAuthentication no" "$config" || fail "SSH setup disables keyboard-interactive authentication"
grep -qxF "systemctl reload sshd.service" "$test_dir/success.calls" || fail "SSH setup reloads the validated config"
grep -q "Password logins are off" <<<"$output" || fail "SSH setup reports hardening after it succeeds"
pass "SSH setup authorizes a key and disables password logins"
if SSHD_PASSWORD_AUTH=yes run_setup ineffective >"$test_dir/ineffective.output" 2>&1; then
fail "SSH setup must fail when password authentication remains effective"
fi
[[ ! -e $test_dir/ineffective/root/etc/ssh/sshd_config.d/10-omarchy-hardening.conf ]] ||
fail "SSH setup removes an ineffective hardening config"
! grep -qF "systemctl reload sshd.service" "$test_dir/ineffective.calls" ||
fail "SSH setup must not reload ineffective hardening"
! grep -q "Password logins are off" "$test_dir/ineffective.output" ||
fail "SSH setup must not claim ineffective hardening succeeded"
pass "SSH setup verifies the effective daemon settings"
if SSHD_SYNTAX_VALID=0 run_setup invalid >"$test_dir/invalid.output" 2>&1; then
fail "SSH setup must fail when sshd rejects its config"
fi
[[ ! -e $test_dir/invalid/root/etc/ssh/sshd_config.d/10-omarchy-hardening.conf ]] ||
fail "SSH setup removes a rejected hardening config"
! grep -qF "systemctl reload sshd.service" "$test_dir/invalid.calls" ||
fail "SSH setup must not reload a rejected config"
! grep -q "Password logins are off" "$test_dir/invalid.output" ||
fail "SSH setup must not claim rejected hardening succeeded"
pass "SSH setup fails safely when sshd rejects the config"
+17 -10
View File
@@ -1,10 +1,7 @@
#!/bin/bash
#
# The docker group is root-equivalent, so no automatic path may grant it. These
# tests guard the paths that are not exercised by a fresh-install run: first-boot
# provisioning replaying a recorded (or factory-snapshot) group list, and the
# Quattro upgrade. Opting in stays a deliberate, warned step
# (omarchy-setup-security-sudoless-docker).
# Docker is root-equivalent, so no automatic path may grant it. Raw input access
# is likewise excluded unless a feature that explicitly needs it is installed.
set -euo pipefail
@@ -13,11 +10,15 @@ source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
# First-boot provisioning must never grant docker even when it is recorded (an
# older install, or a factory snapshot predating the opt-in default).
# First-boot provisioning must not replay old privileged defaults.
mkdir -p "$TMPDIR/bin"
printf '#!/bin/bash\nexit 0\n' >"$TMPDIR/bin/getent" # every group "exists"
chmod +x "$TMPDIR/bin/getent"
cat >"$TMPDIR/bin/pacman" <<'STUB'
#!/bin/bash
[[ $1 == "-Qq" ]] || exit 2
[[ " ${STUB_PACKAGES:-} " == *" $2 "* ]]
STUB
chmod +x "$TMPDIR/bin/getent" "$TMPDIR/bin/pacman"
export PATH="$TMPDIR/bin:$PATH"
PROVISIONING_DIR="$TMPDIR/prov"
@@ -29,9 +30,15 @@ eval "$(sed -n '/^user_groups() {/,/^}/p' "$ROOT/bin/omarchy-provision-owner")"
groups=$(user_groups)
[[ ",$groups," == *",wheel,"* ]] || fail "user_groups always includes wheel"
[[ ",$groups," == *",input,"* ]] || fail "user_groups includes recorded non-docker groups"
[[ ",$groups," != *",input,"* ]] || fail "user_groups must not replay the blanket input grant"
[[ ",$groups," == *",docker,"* ]] && fail "user_groups must never grant the docker group"
pass "first-boot user_groups includes recorded groups but never docker"
pass "first-boot user_groups replays neither privileged default"
groups=$(STUB_PACKAGES=xpadneo-dkms user_groups)
[[ ",$groups," == *",input,"* ]] || fail "user_groups keeps input for installed controller support"
groups=$(STUB_PACKAGES=ydotool user_groups)
[[ ",$groups," == *",input,"* ]] || fail "user_groups keeps input for installed ydotool support"
pass "first-boot user_groups keeps deliberate input-group opt-ins"
# The Quattro upgrade must not re-add the user to docker.
if rg -q 'usermod -aG docker' "$ROOT/bin/omarchy-upgrade-to-quattro"; then