Defer USB enrollment until owner provisioning completes

This commit is contained in:
acrogenesis committed 2026-09-16 16:05:59 -06:00
1 parent 54bacefbf4
commit 67d173c9f9
5 files changed
+85 -29

No files matched your search

+6 -6
View File
@@ -747,12 +747,6 @@ create_user() {
echo "%wheel ALL=(ALL:ALL) ALL" >/etc/sudoers.d/00-omarchy-wheel
chmod 440 /etc/sudoers.d/00-omarchy-wheel
if omarchy-pkg-present usbguard; then
source "$OMARCHY_PATH/install/helpers/usb-authorization.sh"
usb_authorization_add_user "$username"
systemctl try-restart usbguard.service
fi
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
for dir in "${BROWSER_POLICY_MANAGED_DIRS[@]}"; do
[[ -d $dir || -L $dir ]] || continue
@@ -1040,6 +1034,12 @@ run_provisioning() {
limine-update
fi
if omarchy-pkg-present usbguard; then
log_step "enrolling the owner's USB devices"
source "$OMARCHY_PATH/install/helpers/usb-authorization.sh"
usb_authorization_provision_owner "$username"
fi
log_step "cleaning up provisioning state"
cleanup_oem_state
log_step "first-boot setup complete"
+9 -13
View File
@@ -1,5 +1,12 @@
echo "Configure USB device authorization"
# A deferred install has only the builder's peripherals attached. The owner
# needs working input before there is an account or a session for approvals.
if [[ -z ${OMARCHY_INSTALL_USER:-} ]]; then
systemctl disable usbguard.service
return 0
fi
rules_file="${OMARCHY_USB_AUTHORIZATION_RULES_FILE:-/etc/usbguard/rules.conf}"
daemon_config="${OMARCHY_USB_AUTHORIZATION_DAEMON_CONFIG:-/etc/usbguard/usbguard-daemon.conf}"
@@ -7,21 +14,10 @@ source "$OMARCHY_INSTALL/helpers/usb-authorization.sh"
usb_authorization_require_secure_settings "$daemon_config"
if [[ ! -s $rules_file ]]; then
policy=$(mktemp "${TMPDIR:-/tmp}/omarchy-usb-policy.XXXXXXXXXX")
chmod 600 "$policy"
if usb_authorization_generate_policy "$policy"; then
install -Dm600 -o root -g root "$policy" "$rules_file"
rm -f "$policy"
else
rm -f "$policy"
return 1
fi
usb_authorization_install_policy "$rules_file"
fi
if [[ -n ${OMARCHY_INSTALL_USER:-} ]]; then
usb_authorization_add_user "$OMARCHY_INSTALL_USER"
fi
usb_authorization_add_user "$OMARCHY_INSTALL_USER"
# Installs are followed by a reboot, so enable the daemon without starting it
# in the live ISO's chroot.
+32 -5
View File
@@ -49,11 +49,11 @@ usb_authorization_require_secure_setting() {
usb_authorization_require_secure_settings() {
local config="$1"
usb_authorization_require_secure_setting "$config" ImplicitPolicyTarget block
usb_authorization_require_secure_setting "$config" PresentDevicePolicy apply-policy
usb_authorization_require_secure_setting "$config" InsertedDevicePolicy apply-policy
usb_authorization_require_secure_setting "$config" AuthorizedDefault none
usb_authorization_require_secure_setting "$config" RestoreControllerDeviceState false
usb_authorization_require_secure_setting "$config" ImplicitPolicyTarget block || return 1
usb_authorization_require_secure_setting "$config" PresentDevicePolicy apply-policy || return 1
usb_authorization_require_secure_setting "$config" InsertedDevicePolicy apply-policy || return 1
usb_authorization_require_secure_setting "$config" AuthorizedDefault none || return 1
usb_authorization_require_secure_setting "$config" RestoreControllerDeviceState false || return 1
}
usb_authorization_generate_policy() {
@@ -85,6 +85,33 @@ usb_authorization_add_user() {
--exceptions=listen
}
usb_authorization_install_policy() {
local rules="$1" policy status=0
policy=$(mktemp "${TMPDIR:-/tmp}/omarchy-usb-policy.XXXXXXXXXX") || return 1
if usb_authorization_generate_policy "$policy"; then
install -Dm600 -o root -g root "$policy" "$rules" || status=$?
else
status=1
fi
rm -f "$policy"
return "$status"
}
usb_authorization_provision_owner() {
local user="$1"
local rules="${2:-/etc/usbguard/rules.conf}"
local config="${3:-/etc/usbguard/usbguard-daemon.conf}"
usb_authorization_require_secure_settings "$config" || return 1
# Enroll the owner's hardware, replacing any policy inherited from the
# builder. Do this only after the interactive provisioning steps finish.
usb_authorization_install_policy "$rules" || return 1
usb_authorization_add_user "$user" || return 1
systemctl enable usbguard.service || return 1
systemctl restart usbguard.service
}
usb_authorization_trust_present_devices() {
local line id
local count=0
+2
View File
@@ -13,6 +13,8 @@ Omarchy takes security extremely seriously. This is meant to be an operating sys
USB device authorization is enabled by default. Omarchy uses USBGuard to trust the devices connected during installation and block USB devices it has not seen before. When a device is blocked, click the persistent notification and choose whether to allow it once, always allow it, or keep it blocked.
On a preinstalled machine that asks you to create your account at first boot, USB protection starts at the end of that setup. It trusts the devices connected then, so your keyboard works throughout account setup even if it differs from the installer's keyboard.
You can turn the protection off from _Remove > Security > USB Device Authorization_. _Setup > Security > USB Device Authorization_ turns it back on with the existing trusted-device policy.
Only approve hardware you recognize. A malicious USB device can forge the manufacturer, model, serial number, and device class shown during review. Permanent approval is a convenience for accessories you control, not proof of the device's identity.
+36 -5
View File
@@ -62,7 +62,7 @@ generate-policy)
echo 'usbguard <generate-policy>' >>"$CALLS"
[[ ${GENERATE_FAIL:-0} == 0 ]] || exit 1
if [[ ${GENERATE_EMPTY:-0} == 0 ]]; then
echo 'allow id 1d6b:0002 name "Linux Foundation root hub" hash "root"'
printf '%s\n' "${GENERATED_RULE:-allow id 1d6b:0002 name \"Linux Foundation root hub\" hash \"root\"}"
fi
;;
list-devices)
@@ -357,10 +357,8 @@ grep -Fq 'config/usb-authorization.sh' "$ROOT/install/config/all.sh" ||
fail "fresh installs configure the USB authorization policy"
grep -Fq 'omarchy-usb-authorization.service' "$ROOT/install/user/first-run/enable-user-units.sh" ||
fail "fresh installs enable the USB approval watcher"
grep -Fq 'usb_authorization_add_user "$username"' "$ROOT/bin/omarchy-provision-owner" ||
fail "deferred provisioning grants the new owner approval access"
grep -Fq 'systemctl try-restart usbguard.service' "$ROOT/bin/omarchy-provision-owner" ||
fail "deferred provisioning reloads the new owner ACL"
grep -Fq 'usb_authorization_provision_owner "$username"' "$ROOT/bin/omarchy-provision-owner" ||
fail "deferred provisioning enrolls the owner before finishing"
grep -Fqx 'omarchy-setup-security-usb-authorization --yes' "$ROOT/migrations/1789433473.sh" ||
fail "existing installs enable USB authorization during migration"
@@ -391,6 +389,39 @@ fi
! grep -Fq 'systemctl <enable usbguard.service>' "$calls" || fail "failed enumeration must not enable USBGuard"
pass "fresh installation distinguishes no USB hardware from enumeration failure"
: >"$rules"
: >"$calls"
OMARCHY_INSTALL_USER="" bash -euo pipefail -c 'source "$OMARCHY_INSTALL/config/usb-authorization.sh"' >"$scratch/install-deferred-output"
[[ ! -s $rules ]] || fail "deferred installation must not enroll the builder's hardware"
! grep -q '^usbguard' "$calls" || fail "deferred installation must not enumerate or grant owner ACLs"
grep -Fqx 'systemctl <disable usbguard.service>' "$calls" || fail "deferred installation leaves enforcement disabled"
! grep -Fq 'systemctl <enable usbguard.service>' "$calls" || fail "deferred installation must not enable enforcement"
source "$ROOT/install/helpers/usb-authorization.sh"
echo 'allow id 1234:0001 name "Builder keyboard" hash "builder"' >"$rules"
owner_rule='allow id 1234:0002 name "Owner keyboard" hash "owner"'
: >"$calls"
GENERATED_RULE="$owner_rule" usb_authorization_provision_owner owner "$rules" "$daemon_config"
[[ $(<"$rules") == "$owner_rule" ]] || fail "owner enrollment must replace inherited builder trust"
grep -Fqx 'usbguard <add-user> <owner> <--devices=list,listen,modify> <--policy=list> <--exceptions=listen>' "$calls" ||
fail "owner provisioning grants approval access"
[[ $(tail -2 "$calls") == $'systemctl <enable usbguard.service>\nsystemctl <restart usbguard.service>' ]] ||
fail "enforcement starts only after owner policy and ACL setup"
: >"$calls"
if GENERATE_FAIL=1 usb_authorization_provision_owner owner "$rules" "$daemon_config" >"$scratch/owner-failed" 2>&1; then
fail "owner enrollment must reject enumeration failure"
fi
[[ $(<"$rules") == "$owner_rule" ]] || fail "failed enrollment preserves the old policy"
! grep -q '^systemctl' "$calls" || fail "failed owner enrollment must not enable enforcement"
: >"$calls"
sed 's/ImplicitPolicyTarget=block/ImplicitPolicyTarget=allow/' "$daemon_config" >"$scratch/insecure-daemon.conf"
if usb_authorization_provision_owner owner "$rules" "$scratch/insecure-daemon.conf" >"$scratch/owner-insecure" 2>&1; then
fail "owner enrollment rejects insecure settings even when called in a conditional"
fi
[[ ! -s $calls ]] || fail "invalid settings must prevent all enrollment changes"
pass "deferred installs enroll owner hardware before enabling enforcement"
malicious_rule='block id 07a6:8513 name "$(touch '"$scratch"'/injected)" hash "attacker" with-interface 02:06:00'
export BLOCKED_DEVICE_RULE="$malicious_rule"
notification_count=$(grep -c '^notification' "$calls" || true)