Re-sign historical UKIs before changing USB boot policy

This commit is contained in:
acrogenesis committed 2026-09-18 12:43:29 -06:00
1 parent db6ab5a8bf
commit de72b64872
3 files changed
+445

No files matched your search

+188
View File
@@ -381,6 +381,188 @@ usb_authorization_rewrite_snapshot_manifest() {
mv -f "$temporary" "$manifest"
}
usb_authorization_verify_signature() {
# sbctl verify can return zero for unsigned or unreadable files. Check its
# structured result, including the exact path, instead of just the exit code.
if ! sbctl verify --json "$1" | jq -e --arg file "$1" \
'length == 1 and .[0].file_name == $file and .[0].is_signed == 1' >/dev/null; then
echo "Cannot verify the Secure Boot signature of $1 using this machine's signing keys." >&2
return 1
fi
}
# Called with Limine's boot-partition lock held. Prepare signed copies of
# conflicting historical UKIs before changing the selected boot policy.
usb_authorization_reconcile_archived_images() (
local expected="$1" config="$2" esp="$3" machine_id="$4"
local cache="${5:-/var/cache/boot/$machine_id/lss/snapshots.json}"
local history="$esp/$machine_id/limine_history" staging manifest names name image
local cmdline hash_command old_digest new_digest old_hash new_hash replacement index=0
local published=0 committed=0 section layout image_base image_size alignment address
local -a manifests=() originals=()
usb_authorization_secure_boot_enabled || return 0
[[ -d $history ]] || return 0
staging=$(mktemp -d "$esp/.omarchy-usb-uki.XXXXXXXXXX") || return 1
trap '
if (( published && ! committed )); then
for ((index=0; index<${#originals[@]}; index++)); do
cp --preserve=mode,ownership "$staging/original.$index" "${originals[index]}" || true
done
limine-enroll-config >/dev/null 2>&1 || true
fi
rm -rf "$staging"
' EXIT
for manifest in "$history/snapshots.json" "$history/snapshots.json.old" "$cache"; do
[[ -f $manifest ]] || continue
jq -e '.jsonFormatVersion == "1.3.0" and (.snapshotEntries | type == "array")' "$manifest" >/dev/null || return 1
manifests+=("$manifest")
done
(( ${#manifests[@]} )) || return 0
names=$(jq -sr '[.[] | .snapshotEntries[] | .. | objects | .imageDetails? // empty | .[] | .fileHashName] | unique[]' "${manifests[@]}") || return 1
printf '[]\n' >"$staging/replacements.json"
while IFS= read -r name; do
[[ -n $name ]] || continue
# Only image names, never arbitrary paths supplied by a manifest.
if [[ $name == */* || $name == "." || $name == ".." ]]; then
echo "Invalid archived kernel image name: $name" >&2
return 1
fi
image="$history/$name"
[[ -f $image && ! -L $image ]] || continue
: >"$staging/cmdline"
objcopy -O binary --only-section=.cmdline "$image" "$staging/cmdline" 2>/dev/null || continue
cmdline=$(tr '\0' '\n' <"$staging/cmdline")
[[ -n $cmdline ]] || continue
if usb_authorization_cmdline_has_parameter "$cmdline" "$kernel_parameter"; then
[[ $expected == "disabled" ]] || continue
else
[[ $expected == "enabled" ]] || continue
fi
# Multi-profile images and signed PCR policies need their original builder.
# Do not silently invalidate their additional boot/unlock guarantees.
for section in .profile .pcrsig; do
objcopy -O binary --only-section="$section" "$image" "$staging/section" || return 1
if [[ -s $staging/section ]]; then
echo "Rebuild archived image $image with its original signing policy before changing USB boot protection ($section)." >&2
return 1
fi
done
if [[ ! $name =~ ^(.+)_(sha1|sha256|b3|xxh)_([0-9a-f]+)$ ]]; then
echo "Cannot verify the content hash of archived image $image." >&2
return 1
fi
case "${BASH_REMATCH[2]}" in
sha1) hash_command=sha1sum ;;
sha256) hash_command=sha256sum ;;
b3) hash_command=b3sum ;;
xxh) hash_command=xxhsum ;;
esac
old_digest=${BASH_REMATCH[3]}
new_digest=$("$hash_command" "$image") || return 1
if [[ ${new_digest%% *} != "$old_digest" ]]; then
echo "Archived image hash mismatch: $image" >&2
return 1
fi
# Verify the old signature before signing a modified copy with this machine's key.
usb_authorization_verify_signature "$image" || return 1
cp "$image" "$staging/unsigned.efi" || return 1
sbattach --remove "$staging/unsigned.efi" || return 1
# Preserve the embedded boot arguments and change only our exact USB
# parameter. Do not turn a signed command line into an external override.
printf '%s' "$cmdline" | jq -Rrs --arg parameter "$kernel_parameter" --arg expected "$expected" '
[scan("[^[:space:]]+|[[:space:]]+") | select(. != $parameter)]
| join("") | sub("[[:space:]]+$"; "")
| if $expected == "enabled" then . + " " + $parameter else . end
' >"$staging/new-cmdline" || return 1
printf '\0' >>"$staging/new-cmdline"
# objcopy --update-section retains PE VirtualSize and can truncate a longer
# command line. Add a fresh section after the existing virtual image instead.
layout=$(objdump -p "$staging/unsigned.efi" | awk '
$1 == "ImageBase" { base = $2 }
$1 == "SizeOfImage" { size = $2 }
$1 == "SectionAlignment" { alignment = $2 }
END {
if (base !~ /^[0-9a-fA-F]+$/ || size !~ /^[0-9a-fA-F]+$/ || alignment !~ /^[0-9a-fA-F]+$/) exit 1
print "0x" base, "0x" size, "0x" alignment
}
') || return 1
read -r image_base image_size alignment <<<"$layout"
(( alignment > 0 )) || return 1
address=$((image_base + (image_size + alignment - 1) / alignment * alignment))
objcopy --remove-section=.cmdline "$staging/unsigned.efi" "$staging/without-cmdline.efi" || return 1
objcopy --add-section .cmdline="$staging/new-cmdline" \
--change-section-vma .cmdline="$address" \
--set-section-flags .cmdline=alloc,load,readonly,data,contents \
"$staging/without-cmdline.efi" "$staging/image.efi" || return 1
sbctl sign "$staging/image.efi" || return 1
usb_authorization_verify_signature "$staging/image.efi" || return 1
objcopy -O binary --only-section=.cmdline "$staging/image.efi" "$staging/cmdline" || return 1
cmp -s "$staging/cmdline" "$staging/new-cmdline" || return 1
new_digest=$("$hash_command" "$staging/image.efi") || return 1
replacement="${name%"$old_digest"}${new_digest%% *}"
old_hash=$(b2sum "$image") || return 1
new_hash=$(b2sum "$staging/image.efi") || return 1
# Publish copies first: every old reference remains usable until its manifest changes.
if [[ -e $history/$replacement || -L $history/$replacement ]]; then
[[ ! -L $history/$replacement ]] && cmp -s "$staging/image.efi" "$history/$replacement" || return 1
else
mv "$staging/image.efi" "$history/$replacement" || return 1
fi
jq --arg old "$name" --arg new "$replacement" \
--arg old_hash "${old_hash%% *}" --arg new_hash "${new_hash%% *}" \
'. + [{old: $old, new: $new, old_hash: $old_hash, new_hash: $new_hash}]' \
"$staging/replacements.json" >"$staging/next.json" || return 1
mv "$staging/next.json" "$staging/replacements.json" || return 1
done <<<"$names"
jq -e 'length > 0' "$staging/replacements.json" >/dev/null || return 0
originals=("$config" "${manifests[@]}")
for ((index=0; index<${#originals[@]}; index++)); do
cp --preserve=mode,ownership "${originals[index]}" "$staging/original.$index" || return 1
cp --preserve=mode,ownership "${originals[index]}" "$staging/updated.$index" || return 1
# Update cached menu lines, structured image metadata, restore paths and
# both hashes. The new file name remains a valid Limine content address.
if (( index == 0 )); then
jq -Rrs --slurpfile replacements "$staging/replacements.json" '
split("\n") | map(reduce $replacements[0][] as $r (. ;
if contains($r.old) then split($r.old) | join($r.new) | split($r.old_hash) | join($r.new_hash)
else . end)) | join("\n")
' "$staging/original.$index" >"$staging/updated.$index" || return 1
else
jq --slurpfile replacements "$staging/replacements.json" '
walk(if type == "string" then
reduce $replacements[0][] as $r (. ; split($r.old) | join($r.new) | split($r.old_hash) | join($r.new_hash))
else . end)
' "$staging/original.$index" >"$staging/updated.$index" || return 1
fi
done
published=1
for ((index=0; index<${#originals[@]}; index++)); do
mv -f "$staging/updated.$index" "${originals[index]}" || return 1
done
limine-enroll-config || return 1
committed=1
)
usb_authorization_prepare_archived_images() (
local expected="$1" config="$2" esp="$3" machine_id="${4:-$(</etc/machine-id)}"
usb_authorization_secure_boot_enabled || return 0
# Package hooks acquire the boot lock too; install this optional tool before
# taking it, never while rewriting archived images.
if omarchy-cmd-missing sbattach; then
omarchy-pkg-add sbsigntools || return 1
fi
exec 9>/run/lock/boot-partition.lock
flock --timeout 30 9 || return 1
limine-snapper-sync --no-mutex --no-hooks || return 1
usb_authorization_reconcile_archived_images "$expected" "$config" "$esp" "$machine_id"
)
usb_authorization_sync_and_verify() (
local expected="$1" config="$2" esp="$3"
local machine_id="${4:-$(</etc/machine-id)}" manifest
@@ -392,6 +574,7 @@ usb_authorization_sync_and_verify() (
# Recover/upgrade the manifest first, including backups if necessary.
limine-snapper-sync --no-mutex --no-hooks || return 1
usb_authorization_reconcile_archived_images "$expected" "$config" "$esp" "$machine_id" || return 1
for manifest in \
"$esp/$machine_id/limine_history/snapshots.json" \
"$esp/$machine_id/limine_history/snapshots.json.old" \
@@ -433,6 +616,7 @@ main() {
exit 1
fi
usb_authorization_prepare_archived_images enabled "$limine_conf" "$boot_path" || exit 1
usb_authorization_enable_snapshot_setting "$limine_defaults"
if [[ ! -e $drop_in ]]; then
@@ -468,6 +652,10 @@ main() {
exit 1
fi
had_drop_in=1
fi
usb_authorization_prepare_archived_images disabled "$limine_conf" "$boot_path" || exit 1
if (( had_drop_in )); then
rm -f "$drop_in"
fi
+2
View File
@@ -25,6 +25,8 @@ For machines whose disk unlock and recovery never depend on any USB devices, _Se
Older snapshots created before USBGuard was installed and enabled keep all USB disabled even after startup, including keyboards, network adapters, and storage. Trusting the devices connected now does not make them available in those snapshots. Enable boot-time protection only if you can unlock and recover the machine without any USB devices. _Remove > Security > USB at Boot_ restores the normal early-boot behavior while keeping USBGuard active after startup.
With Secure Boot enabled, changing USB boot protection may require access to your signing keys to update older snapshot boot images. If an image uses a custom measured-boot policy or multiple boot profiles, rebuild it with its original signing setup before retrying.
## Changing your passwords
You have two passwords on an encrypted install: the one that unlocks the drive at boot, and the one you log in and `sudo` with. Both can be changed under _Update > Password_ in the Omarchy menu — _Drive Encryption_ for the first, _User_ for the second. Changing the drive password asks for the current one first, so have it handy.
+255
View File
@@ -0,0 +1,255 @@
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
source "$ROOT/bin/omarchy-usb-authorization-boot"
scratch=$(mktemp -d)
trap 'rm -rf "$scratch"' EXIT
machine=12345678901234567890123456789012
export calls="$scratch/calls"
: >"$calls"
# Optional integration run uses real sbctl keys and sbattach in isolated paths.
sbctl() {
printf '%s\n' "$1" >>"$calls"
[[ ${SIGN_FAIL:-0} != 1 || $1 != sign ]] || return 1
[[ ${VERIFY_FAIL:-0} != 1 || $1 != verify ]] || return 1
if [[ -n ${USB_TEST_SBCTL_CONFIG:-} ]]; then
/usr/bin/sbctl --config "$USB_TEST_SBCTL_CONFIG" "$@"
elif [[ $1 == verify ]]; then
jq -n --arg file "${!#}" --argjson signed "${TEST_SIGNED:-1}" '[{file_name: $file, is_signed: $signed}]'
fi
}
sbattach() {
if [[ -n ${USB_TEST_SBATTACH:-} ]]; then
"$USB_TEST_SBATTACH" "$@"
fi
}
omarchy-cmd-missing() { return 1; }
limine-enroll-config() { [[ ${ENROLL_FAIL:-0} != 1 ]]; }
usb_authorization_secure_boot_enabled() { [[ ${SECURE_BOOT:-1} == 1 ]]; }
fixture() {
local embedded="$1" hash digest image_base
esp="$scratch/case-$RANDOM"
history="$esp/$machine/limine_history"
manifest="$history/snapshots.json"
cache="$esp/cache.json"
config="$esp/limine.conf"
mkdir -p "$history"
printf '%s\0' "$embedded" >"$esp/cmdline"
cp /usr/lib/systemd/boot/efi/linuxx64.efi.stub "$esp/image.efi"
image_base=$(objdump -p "$esp/image.efi" | awk '$1 == "ImageBase" {print "0x" $2}')
objcopy --add-section .cmdline="$esp/cmdline" --change-section-vma .cmdline="$((image_base + 0x100000))" "$esp/image.efi"
if [[ -n ${USB_TEST_SBCTL_CONFIG:-} ]]; then
sbctl sign "$esp/image.efi" >/dev/null
fi
digest=$(sha256sum "$esp/image.efi"); digest=${digest%% *}
old_name="test.efi_sha256_$digest"
cp "$esp/image.efi" "$history/$old_name"
hash=$(b2sum "$esp/image.efi"); hash=${hash%% *}
printf '/Omarchy\ncomment: machine-id=%s\n //snapshot\n comment: kernel-id=linux\n path: boot():/%s/limine_history/%s#%s\n cmdline: %s rootflags=subvol=/snapshot\n' \
"$machine" "$machine" "$old_name" "$hash" "$embedded" >"$config"
jq -n --arg name "$old_name" --arg hash "$hash" --arg machine "$machine" --arg cmdline "$embedded" '
def kernel:
{imageDetails: [{fileHashName: $name, fileName: "test.efi",
snapshotFilePathLine: "/" + $machine + "/limine_history/" + $name + "#" + $hash,
filePathLine: "/EFI/Linux/test.efi#" + $hash, properties: {HASH: "#" + $hash}}],
cmdlineDetails: [{cmdline: $cmdline, snapshotCmdline: $cmdline + " rootflags=subvol=/snapshot"}],
allInConfig: ["path: boot():/EFI/Linux/test.efi#" + $hash, "cmdline: " + $cmdline],
allInSnapshotConfig: ["comment: kernel-id=linux", "path: boot():/" + $machine + "/limine_history/" + $name + "#" + $hash, "cmdline: " + $cmdline + " rootflags=subvol=/snapshot"], subKernels: []};
{jsonFormatVersion: "1.3.0", snapshotEntries: [{kernelEntries: [kernel | .subKernels = [kernel]]}]}
' >"$manifest"
cp "$manifest" "$manifest.old"
cp "$manifest" "$cache"
cp "$manifest" "$esp/before.json"
cp "$config" "$esp/before.conf"
: >"$calls"
}
for expected in enabled disabled; do
old='quiet'
[[ $expected != disabled ]] || old+=' usbcore.authorized_default=0'
fixture "$old"
usb_authorization_reconcile_archived_images "$expected" "$config" "$esp" "$machine" "$cache"
new_name=$(jq -r '.snapshotEntries[0].kernelEntries[0].imageDetails[0].fileHashName' "$manifest")
[[ $new_name != "$old_name" && -f $history/$new_name ]] || fail "conflicting archives get new content-addressed copies"
cmp "$history/$old_name" "$esp/image.efi" || fail "original archived image remains unchanged"
digest=$(sha256sum "$history/$new_name")
[[ $new_name == *"${digest%% *}" ]] || fail "replacement name matches its content hash"
objcopy -O binary --only-section=.cmdline "$history/$new_name" "$esp/section"
embedded=$(tr '\0' '\n' <"$esp/section")
wanted=quiet
[[ $expected != enabled ]] || wanted+=' usbcore.authorized_default=0'
[[ $embedded == "$wanted" ]] || fail "replacement must preserve embedded boot arguments and change only USB policy"
objcopy -O binary --only-section=.text "$history/$old_name" "$esp/text.before"
objcopy -O binary --only-section=.text "$history/$new_name" "$esp/text.after"
cmp "$esp/text.before" "$esp/text.after" || fail "archive conversion must not alter executable code"
[[ $(grep -c '^sign$' "$calls") == 1 && $(grep -c '^verify$' "$calls") == 2 ]] || fail "deduplicated image must be verified before and after signing"
for file in "$manifest" "$manifest.old" "$cache"; do
! grep -Fq "$old_name" "$file" || fail "no old image references may survive in manifests"
usb_authorization_rewrite_snapshot_manifest "$expected" "$file"
# Both cached and structured restore representations must regenerate valid entries.
for format in cached structured; do
{
printf '/Omarchy\ncomment: machine-id=%s\n //snapshot\n' "$machine"
if [[ $format == cached ]]; then
jq -r '.snapshotEntries[0].kernelEntries[0].allInSnapshotConfig[]' "$file"
else
printf 'comment: kernel-id=linux\n'
jq -r '.snapshotEntries[0].kernelEntries[0].subKernels[0] | "path: boot():" + .imageDetails[0].snapshotFilePathLine, "cmdline: " + .cmdlineDetails[0].snapshotCmdline' "$file"
fi
} >"$esp/regenerated.conf"
usb_authorization_verify_boot_entries "$expected" "$esp/regenerated.conf" "$esp" "$machine" enabled || fail "regenerated $format $expected snapshot must verify"
done
done
usb_authorization_rewrite_boot_cmdlines "$expected" "$config" "$machine"
usb_authorization_verify_boot_entries "$expected" "$config" "$esp" "$machine" enabled || fail "$expected archive transition must verify under Secure Boot"
usb_authorization_reconcile_archived_images "$expected" "$config" "$esp" "$machine" "$cache"
[[ $(grep -c '^sign$' "$calls") == 1 ]] || fail "retry must not resign an already-compatible archive"
if [[ -n ${USB_TEST_SBCTL_CONFIG:-} ]]; then
usb_authorization_verify_signature "$history/$new_name"
fi
pass "USB $expected transition updates signed history and all cached/structured references"
done
fixture quiet
old_hash=$(b2sum "$esp/image.efi"); old_hash=${old_hash%% *}
printf ' //current\n comment: kernel-id=current\n path: boot():/image.efi#%s\n cmdline: quiet\n' "$old_hash" >>"$config"
usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache"
grep -Fq "path: boot():/image.efi#$old_hash" "$config" || fail "preflight must not rewrite hashes of unchanged current images sharing archive content"
pass "USB archive preflight preserves unchanged current-image hashes"
fixture 'quiet rd.test="two spaces"'
usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache"
new_name=$(jq -r '.snapshotEntries[0].kernelEntries[0].imageDetails[0].fileHashName' "$manifest")
objcopy -O binary --only-section=.cmdline "$history/$new_name" "$esp/section"
[[ $(tr '\0' '\n' <"$esp/section") == 'quiet rd.test="two spaces" usbcore.authorized_default=0' ]] || fail "unrelated quoted arguments must retain their whitespace"
pass "USB archive policy changes preserve unrelated embedded arguments and executable code"
for failure in SIGN_FAIL VERIFY_FAIL ENROLL_FAIL; do
fixture quiet
if (export "$failure=1"; usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache") >"$esp/failure.log" 2>&1; then
fail "$failure must prevent publication"
fi
cmp "$config" "$esp/before.conf" || fail "$failure must preserve the original boot menu"
for file in "$manifest" "$manifest.old" "$cache"; do
cmp "$file" "$esp/before.json" || fail "$failure must preserve every manifest"
done
cmp "$history/$old_name" "$esp/image.efi" || fail "$failure must preserve the archived image"
done
pass "USB archive signing, verification and enrollment failures preserve original references"
fixture quiet
printf corrupt >>"$history/$old_name"
if usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache" >"$esp/hash-failure" 2>&1; then
fail "corrupt original archive must never be signed"
fi
[[ ! -s $calls ]] || fail "hash failure must occur before signing"
cmp "$config" "$esp/before.conf"
SECURE_BOOT=0 usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache"
[[ ! -s $calls ]] || fail "non-Secure-Boot transitions must not rewrite archive images"
pass "USB archive conversion rejects corruption and skips non-Secure-Boot systems"
if [[ -z ${USB_TEST_SBCTL_CONFIG:-} ]]; then
fixture quiet
if TEST_SIGNED=0 usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache" >"$esp/unsigned" 2>&1; then
fail "a false-success sbctl result cannot authorize signing"
fi
! grep -qx sign "$calls" || fail "an unsigned original must not be resigned"
fi
for missing in menu manifest; do
fixture quiet
if [[ $missing == menu ]]; then
sed -i '/cmdline:/d' "$config"
else
jq '.snapshotEntries[0].kernelEntries[0].cmdlineDetails = []' "$manifest" >"$esp/modified"
mv "$esp/modified" "$manifest"
fi
usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache" || fail "embedded-only $missing must support policy changes"
usb_authorization_rewrite_boot_cmdlines enabled "$config" "$machine"
usb_authorization_verify_boot_entries enabled "$config" "$esp" "$machine" enabled || fail "embedded-only $missing must retain a valid command line"
done
for section in .profile .pcrsig; do
fixture quiet
printf protected >"$esp/protected"
objcopy --add-section "$section=$esp/protected" "$history/$old_name" 2>/dev/null
if usb_authorization_reconcile_archived_images enabled "$config" "$esp" "$machine" "$cache" >"$esp/protected-failure" 2>&1; then
fail "a $section image must require its original builder"
fi
grep -Fq "($section)" "$esp/protected-failure" || fail "unsupported signing policies need an actionable error"
[[ ! -s $calls ]] || fail "unsupported signing policies must not be resigned"
done
pass "USB archive conversion requires authentic signatures and preserves boot/unlock requirements"
# Package hooks use this same lock. Installing the optional signature tool
# must finish before preparation takes the lock, while sync must run under it.
fixture quiet
prepare=$(declare -f usb_authorization_prepare_archived_images)
prepare=${prepare//\/run\/lock\/boot-partition.lock/$scratch\/preflight.lock}
eval "$prepare"
omarchy-cmd-missing() { return 0; }
omarchy-pkg-add() {
flock --nonblock "$scratch/preflight.lock" true || fail "package installation must precede the boot lock"
printf 'package\n' >>"$calls"
}
limine-snapper-sync() {
[[ $* == '--no-mutex --no-hooks' ]] || fail "preparation must use the already-held lock"
if flock --nonblock "$scratch/preflight.lock" true; then
fail "snapshot synchronization must hold the boot lock"
fi
}
usb_authorization_prepare_archived_images enabled "$config" "$esp" "$machine"
grep -qx package "$calls" || fail "missing signature tooling must be installed before preparing archives"
pass "USB archive preparation installs optional tools before taking Limine's lock"
# The disposable Lab runs the actual root-only main function with only boot paths
# and external build/sync commands redirected into this fixture.
if [[ ${USB_TEST_MAIN:-0} == 1 ]]; then
(( EUID == 0 )) || fail "main-path fixtures require the disposable guest's root"
usb_authorization_prepare_archived_images() {
usb_authorization_reconcile_archived_images "$1" "$2" "$3" "$machine" "$cache"
}
limine-mkinitcpio() { return 0; }
usb_authorization_sync_and_verify() {
local file
for file in "$manifest" "$manifest.old" "$cache"; do
usb_authorization_rewrite_snapshot_manifest "$1" "$file" || return 1
done
usb_authorization_rewrite_boot_cmdlines "$1" "$2" "$machine" || return 1
usb_authorization_verify_boot_entries "$1" "$2" "$3" "$machine" enabled
}
for action in enable disable; do
old=quiet
[[ $action != disable ]] || old+=' usbcore.authorized_default=0'
fixture "$old"
drop_in="$esp/entry-tool/usb-authorization.conf"
limine_defaults="$esp/defaults"
limine_conf="$config"
boot_path="$esp"
printf '# fixture defaults\n' >"$limine_defaults"
if [[ $action == disable ]]; then
mkdir -p "${drop_in%/*}"
printf '%s\n' "$setting" >"$drop_in"
usb_authorization_enable_snapshot_setting "$limine_defaults"
fi
cp "$limine_defaults" "$esp/defaults.before"
if (export SIGN_FAIL=1; main "$action") >"$esp/main-failed" 2>&1; then
fail "$action must stop if archive preparation fails"
fi
cmp "$limine_defaults" "$esp/defaults.before" || fail "$action failure must precede snapshot-setting changes"
if [[ $action == enable ]]; then
[[ ! -e $drop_in ]] || fail "enable preflight failure must not create the boot setting"
else
[[ $(<"$drop_in") == "$setting" ]] || fail "disable preflight failure must preserve the boot setting"
fi
(main "$action")
if [[ $action == enable ]]; then
[[ $(<"$drop_in") == "$setting" ]] || fail "successful enable sets the boot policy"
else
[[ ! -e $drop_in ]] || fail "successful disable clears the boot policy"
fi
pass "USB $action main path prepares archives before changing boot policy"
done
fi