Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package sdbootutil for openSUSE:Factory checked in at 2026-10-30 18:58:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/sdbootutil (Old) and /work/SRC/openSUSE:Factory/.sdbootutil.new.1255 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sdbootutil" Fri Oct 30 18:58:02 2026 rev:117 rq: version:1+git20261026.4e266f0 Changes: -------- --- /work/SRC/openSUSE:Factory/sdbootutil/sdbootutil.changes 2026-10-29 18:18:17.754534384 +0100 +++ /work/SRC/openSUSE:Factory/.sdbootutil.new.1255/sdbootutil.changes 2026-10-30 18:58:05.330406960 +0100 @@ -2,14 +1,0 @@ -Wed Oct 28 15:50:21 UTC 2026 - Alberto Planas Dominguez <[email protected]> - -- Update to version 1+git20261028.5233b70: - * Enroll recovery key if no one is provided via combustion - -------------------------------------------------------------------- -Tue Oct 27 19:26:41 UTC 2026 - Alberto Planas Dominguez <[email protected]> - -- Update to version 1+git20261027.f17cbce: - * Support new kernel/initrd order for PCR9 in grub2 2.16 - * Use the preferred boot entry in systemd-boot - * Serialize concurrent sdbootutil runs - -------------------------------------------------------------------- Old: ---- sdbootutil-1+git20261028.5233b70.obscpio New: ---- sdbootutil-1+git20261026.4e266f0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ sdbootutil.spec ++++++ --- /var/tmp/diff_new_pack.XPitjJ/_old 2026-10-30 18:58:07.428494815 +0100 +++ /var/tmp/diff_new_pack.XPitjJ/_new 2026-10-30 18:58:07.429494857 +0100 @@ -55,7 +55,7 @@ %{nil} Name: sdbootutil -Version: 1+git20261028.5233b70 +Version: 1+git20261026.4e266f0 Release: 0 Summary: Bootctl wrapper for BLS boot loaders License: MIT ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.XPitjJ/_old 2026-10-30 18:58:07.614502604 +0100 +++ /var/tmp/diff_new_pack.XPitjJ/_new 2026-10-30 18:58:07.626503107 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/openSUSE/sdbootutil.git</param> - <param name="changesrevision">5233b701840f4b91bbed367e194d238dddaa11f8</param></service></servicedata> + <param name="changesrevision">4e266f09ced4ed9a44f290f2cb34b91bae9ac6ef</param></service></servicedata> (No newline at EOF) ++++++ sdbootutil-1+git20261028.5233b70.obscpio -> sdbootutil-1+git20261026.4e266f0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20261028.5233b70/doc/raw-disk-image-architecture.md new/sdbootutil-1+git20261026.4e266f0/doc/raw-disk-image-architecture.md --- old/sdbootutil-1+git20261028.5233b70/doc/raw-disk-image-architecture.md 2026-10-28 16:48:49.000000000 +0100 +++ new/sdbootutil-1+git20261026.4e266f0/doc/raw-disk-image-architecture.md 2026-10-26 12:44:49.000000000 +0100 @@ -826,7 +826,7 @@ | `firstboot.timezone` | `jeos-firstboot` | Skips the timezone dialog | | `sdbootutil-enroll.current-pw` | `sdbootutil-enroll` | Existing password/passphrase needed to authorize enrolling a *new* factor on an already-enrolled device | | `sdbootutil-enroll.pw` | `sdbootutil-enroll`, `jeos-firstboot-enroll` | Enroll a password keyslot | -| `sdbootutil-enroll.rk` | `sdbootutil-enroll` | Enroll a recovery-key keyslot. Implied when no `sdbootutil-enroll.*` method is given and a device is still opened only by the transient enrollment key | +| `sdbootutil-enroll.rk` | `sdbootutil-enroll` | Enroll a recovery-key keyslot | | `sdbootutil-enroll.tpm2` | `sdbootutil-enroll`, `jeos-firstboot-enroll` | Enroll a TPM2 keyslot (no PIN) | | `sdbootutil-enroll.tpm2+pin` | `sdbootutil-enroll`, `jeos-firstboot-enroll` | Enroll a TPM2 keyslot; value is the PIN | | `sdbootutil-enroll.fido2` | `sdbootutil-enroll`, `jeos-firstboot-enroll` | Enroll a FIDO2 keyslot | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20261028.5233b70/sdbootutil new/sdbootutil-1+git20261026.4e266f0/sdbootutil --- old/sdbootutil-1+git20261028.5233b70/sdbootutil 2026-10-28 16:48:49.000000000 +0100 +++ new/sdbootutil-1+git20261026.4e266f0/sdbootutil 2026-10-26 12:44:49.000000000 +0100 @@ -3187,14 +3187,6 @@ chattr +i "$efi_var" } -bli_efi_var_unset() -{ - local efi_var="/sys/firmware/efi/efivars/${1:?}-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" - [ -e "$efi_var" ] || return 0 - chattr -i "$efi_var" - rm -f "$efi_var" -} - loader_conf_set() { local key="${1:?}" @@ -3210,12 +3202,6 @@ fi } -loader_conf_unset() -{ - local key="${1:?}" - [ ! -e "${esp_root}/loader/loader.conf" ] || sed -i -e "/^$key /d" "${esp_root}/loader/loader.conf" -} - loader_conf_get() { local key="${1:?}" @@ -3264,39 +3250,16 @@ fi } -# systemd-boot boots the default entry even when boot counting marked -# it as bad, so a snapshot that never boots correctly is tried -# forever. The preferred entry (systemd 260) is skipped when it is -# bad, and the boot loader moves to the first entry that is not marked -# as preferred -sdboot_has_preferred() -{ - local features - features="$(od -An -t u8 -j 4 -N 8 /sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f 2> /dev/null)" || return 1 - (( (features >> 19) & 1 )) -} - set_default_sdboot() { local id="${1:?}" - # The entry is the preferred or the default one, never both: a - # bad preferred entry is skipped, and then the default one is - # booted, even when it is the same bad entry - local key="default" stale="preferred" - if sdboot_has_preferred; then - key="preferred" - stale="default" - fi - if ! has_efivars || [ -n "$arg_no_variables" ]; then - loader_conf_set "$key" "$id" - elif ! bli_efi_var_set "LoaderEntry${key^}" "$id"; then - warn "EFI variable LoaderEntry${key^} cannot be set. Falling back to configuration file" - loader_conf_set "$key" "$id" + loader_conf_set "default" "$id" + elif ! bli_efi_var_set "LoaderEntryDefault" "$id"; then + warn "EFI variable LoaderEntryDefault cannot be set. Falling back to configuration file" + loader_conf_set "default" "$id" fi - loader_conf_unset "$stale" - [ -n "$arg_no_variables" ] || bli_efi_var_unset "LoaderEntry${stale^}" } set_default_grub2_bls() @@ -3388,10 +3351,8 @@ { local val if has_efivars && [ -z "$arg_no_variables" ]; then - val="$(bli_efi_var_get "LoaderEntryPreferred")" - [ -n "$val" ] || val="$(bli_efi_var_get "LoaderEntryDefault")" + val="$(bli_efi_var_get "LoaderEntryDefault")" fi - [ -n "$val" ] || val="$(loader_conf_get "preferred")" [ -n "$val" ] || val="$(loader_conf_get "default")" [ -n "$val" ] || val="$(get_default_bootctl)" [ -z "$val" ] || echo "$val" @@ -4096,13 +4057,7 @@ local cmdline="$4" local suffix="$5" - # GRUB2-BLS >= 2.16 measures the initrd when the kernel loads it, - # and the kernel measures the cmdline before that - local initrd_in_place= - systemd-analyze compare-versions "$(bootloader_version)" "<" "2.16" || initrd_in_place=1 - - local elements=("$linux") - [ -n "$initrd_in_place" ] || elements+=("$initrd") + local elements=("$linux" "$initrd") [ -z "$devicetree" ] || elements+=("$devicetree") local locks=() local n=0 @@ -4139,16 +4094,6 @@ locks+=("$tmpdir/element-$n.pcrlock") rm "$tmpdir/cmdline" - if [ -n "$initrd_in_place" ]; then - n=$((n+1)) - pcrlock \ - lock-raw \ - --pcr=9 \ - --pcrlock "$tmpdir/element-$n.pcrlock" \ - "$initrd" 2> /dev/null - locks+=("$tmpdir/element-$n.pcrlock") - fi - n=$((n+1)) pcrlock \ lock-kernel-initrd \ @@ -7837,23 +7782,6 @@ opts_long="${opts_long%,}" } -# Two runs at the same time race over the ESP, the boot entries and -# /var/lib/pcrlock.d. It happens at boot, when health-checker calls -# set-default-snapshot while sdbootutil-update-predictions.service is -# running. The lock is released when the process exits. Without -# permissions to take it the command would fail later anyway -# -# Like in the snapper plugin the directory is only for root: any user -# that can open the lock can also hold it, and block every run -take_lock() -{ - { mkdir -p /run/sdbootutil && chmod 700 /run/sdbootutil; } 2> /dev/null || return 0 - exec {lock_fd}> /run/sdbootutil/lock || return 0 - flock -n "$lock_fd" && return 0 - info "Waiting for another sdbootutil to finish" - flock -w 600 "$lock_fd" || err "Another sdbootutil has been running for 10 minutes" -} - ####### main ####### if [ "$1" = "_print_bash_completion_data" ]; then @@ -7944,11 +7872,6 @@ err "unknown command $1" fi -case "$1" in - is-installed|needs-update|list-*|status|show-entry|is-bootable|get-*|print-loader-path|bootloader) ;; - *) take_lock ;; -esac - [ -n "$arg_esp_path" ] && export SYSTEMD_ESP_PATH="$arg_esp_path" eval_bootctl diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20261028.5233b70/sdbootutil-enroll new/sdbootutil-1+git20261026.4e266f0/sdbootutil-enroll --- old/sdbootutil-1+git20261028.5233b70/sdbootutil-enroll 2026-10-28 16:48:49.000000000 +0100 +++ new/sdbootutil-1+git20261026.4e266f0/sdbootutil-enroll 2026-10-26 12:44:49.000000000 +0100 @@ -172,21 +172,20 @@ recovery_pin= get_credential recovery_pin "sdbootutil-enroll.recovery-pin" -# Without a single credential nothing was requested. But a device that -# still has the keyslot of disk-encryption-tool is opened only by a key -# that nobody saw, and its initrd does not know about /etc/crypttab, so -# the next boot waits forever for the root device. Enroll a recovery -# key as if it was requested: it is shown in the issue file, and the -# initrd is regenerated -if [ -z "$rk$pw$tpm2_pin$tpm2$fido2" ]; then - while read -r dev; do - cryptsetup luksDump --dump-json-metadata "$dev" 2> /dev/null \ - | jq -e 'any(.tokens[]?; .type == "enrollment-key")' > /dev/null \ - && rk=1 - done < <(sdbootutil list-devices) - [ -n "$rk" ] || exit 0 - echo "No enrollment method requested. Enrolling a recovery key" >&2 -fi +# Without a single credential there is nothing to enroll, and the +# keyslot that disk-encryption-tool left behind would be wiped without +# anything to replace it. Not wiping it does not make the machine +# bootable either, as that key is random and is never shown to anyone, +# but it is still the better end: the key is in the keyring while this +# boot lasts, so it can be piped out and enrolled by hand. A device +# with no keyslot at all is lost even with the key in hand. +# +# This is not an error: the service is enabled by the image, while the +# credentials come from the deployment +[ -n "$rk$pw$tpm2_pin$tpm2$fido2" ] || { + echo "No enrollment method requested. The device is still opened only by the key that disk-encryption-tool generated, readable from %user:cryptenroll until this boot ends" >&2 + exit 0 +} # A method that fails must not be mistaken for one that worked: the # keyslot that disk-encryption-tool left behind is wiped at the end of diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20261028.5233b70/tests/README.md new/sdbootutil-1+git20261026.4e266f0/tests/README.md --- old/sdbootutil-1+git20261028.5233b70/tests/README.md 2026-10-28 16:48:49.000000000 +0100 +++ new/sdbootutil-1+git20261026.4e266f0/tests/README.md 2026-10-26 12:44:49.000000000 +0100 @@ -124,22 +124,6 @@ that does not exist yet, and whose first requirement is a way to put a guest back. -## Enrollment service (`tests/enroll`) - -`sdbootutil-enroll` decides what to enroll from the credentials and from -the LUKS2 headers that disk-encryption-tool left behind. `tests/enroll` -runs the real script against LUKS2 headers in image files, with -`sdbootutil` replaced by a stub that enrolls them with `cryptsetup`, in -a user and mount namespace with a private `/run`. It does not need -root. - -```console -$ tests/enroll -ok enrolls a recovery key when nothing was requested -... -5 cases, all passed -``` - ## Adding a scenario A scenario is a bash script in `scenarios/`, run on the guest with diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20261028.5233b70/tests/enroll new/sdbootutil-1+git20261026.4e266f0/tests/enroll --- old/sdbootutil-1+git20261028.5233b70/tests/enroll 2026-10-28 16:48:49.000000000 +0100 +++ new/sdbootutil-1+git20261026.4e266f0/tests/enroll 1970-01-01 01:00:00.000000000 +0100 @@ -1,295 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: Copyright 2026 SUSE LLC -# -# Tests for sdbootutil-enroll: which methods it asks sdbootutil for, -# given the credentials and the LUKS2 headers that disk-encryption-tool -# left behind, what it shows in the issue file, and which keyslots it -# wipes at the end. -# -# The script runs for real, against LUKS2 headers in image files, with -# `sdbootutil` replaced by a stub that lists those images and enrolls -# them with cryptsetup. It runs in a user and mount namespace with a -# private /run, so nothing reaches the issue files of the host. -# -# Usage: -# tests/enroll [-h] -# -# Does not need root. It uses the real %user:cryptenroll keyring entry, -# so it refuses to start when it is already there. - -set -e -shopt -s nullglob - -here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -top="$(dirname "$here")" - -PATH="$PATH:/usr/sbin:/sbin" - -# The key that disk-encryption-tool generates, and the recovery key that -# the stub enrolls -BOOTSTRAP="bootstrap-password" -RECOVERY="recovery-key-of-the-stub" - -[ "${1:-}" != "-h" ] && [ "${1:-}" != "--help" ] || { - sed -n '4,19p' "${BASH_SOURCE[0]}" | sed 's/^# \?//' - exit 0 -} - -skip() -{ - echo "SKIP: $*" - exit 77 -} - -die() -{ - echo "ERROR: $*" >&2 - exit 1 -} - -for cmd in cryptsetup systemd-cryptenroll keyctl jq unshare; do - command -v "$cmd" > /dev/null || skip "$cmd is not installed" -done -unshare -rm true 2> /dev/null || skip "unprivileged user namespaces are not available" -keyctl id %user:cryptenroll &> /dev/null && \ - die "%user:cryptenroll is in the keyring. Purge it first: keyctl purge user cryptenroll" - -workdir="$(mktemp -d -t sdbootutil-enroll.XXXXXX)" - -cleanup_enroll() -{ - rm -rf "$workdir" - keyctl purge user cryptenroll &> /dev/null || true -} -trap cleanup_enroll EXIT - -####### the stubs ####### - -mkdir "$workdir/bin" - -# have_luks2 asks lsblk, that does not see image files -cat > "$workdir/bin/lsblk" <<-'EOF' - #!/bin/bash - echo crypto_LUKS -EOF - -# Every call is logged. The enrollments add a keyslot to every listed -# device, authorized by the key in %user:cryptenroll, as the real one -# does through systemd-cryptenroll -cat > "$workdir/bin/sdbootutil" <<-EOF - #!/bin/bash - echo "\$*" >> "$workdir/calls" - add_key() - { - local dev - while read -r dev; do - cryptsetup luksAddKey --batch-mode --force-password \\ - --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \\ - --key-file <(keyctl pipe %user:cryptenroll) \\ - "\$dev" <(echo -n "\$1") || exit 1 - done < "$workdir/devices" - } - case "\$1 \$2" in - "list-devices "*) cat "$workdir/devices" ;; - "enroll --method=recovery-key") add_key "$RECOVERY"; echo "Recovery key: $RECOVERY" ;; - "enroll --method=password") add_key "\$PW" ;; - *) exit 1 ;; - esac -EOF -chmod +x "$workdir/bin/lsblk" "$workdir/bin/sdbootutil" - -####### the fixtures ####### - -# A device as disk-encryption-tool leaves it: a single keyslot, with the -# key in %user:cryptenroll, marked with the "enrollment-key" token -new_device() -{ - local img="$workdir/$1.img" - truncate -s 32M "$img" - cryptsetup luksFormat --type luks2 --batch-mode --force-password \ - --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \ - "$img" <<<"$BOOTSTRAP" - echo '{"type":"enrollment-key","keyslots":["0"]}' | cryptsetup token import "$img" - echo "$img" >> "$workdir/devices" -} - -credential() -{ - mkdir -p "$workdir/creds" - echo "$2" > "$workdir/creds/sdbootutil-enroll.$1" -} - -# Run sdbootutil-enroll with a private /run, and without the -# reconfig_system flag or the issue-generator of the host -run_enroll() -{ - # shellcheck disable=SC2016 # expanded by the inner bash - unshare -rm bash -c ' - mount -t tmpfs tmpfs /run - [ ! -d /var/lib/YaST2 ] || mount -t tmpfs tmpfs /var/lib/YaST2 - [ ! -e /usr/sbin/issue-generator ] || mount --bind /dev/null /usr/sbin/issue-generator - rc=0 - PATH="$1/bin:$PATH" CREDENTIALS_DIRECTORY="$1/creds" "$2/sdbootutil-enroll" || rc=$? - cat /run/issue.d/* > "$1/issue" 2> /dev/null - exit "$rc" - ' - "$workdir" "$top" > "$workdir/out" 2>&1 -} - -####### the assertions ####### - -fail() -{ - echo " $*" - case_failed=1 -} - -is() -{ - [ "$2" = "$3" ] || fail "$1: expected '$2', got '$3'" -} - -says() -{ - grep -qF -- "$3" "$2" 2> /dev/null || fail "$1: '$3' was not said" -} - -says_not() -{ - ! grep -qF -- "$3" "$2" 2> /dev/null || fail "$1: '$3' was said, and should not" -} - -opens() -{ - cryptsetup luksOpen --test-passphrase --disable-external-tokens \ - "$workdir/$1.img" <<<"$2" &> /dev/null || \ - fail "$1: '$2' does not open the device" -} - -opens_not() -{ - ! cryptsetup luksOpen --test-passphrase --disable-external-tokens \ - "$workdir/$1.img" <<<"$2" &> /dev/null || \ - fail "$1: '$2' still opens the device" -} - -####### the cases ####### - -# The bug: the deployment requested nothing, and the device was left -# with a key that nobody saw, and with an initrd that does not ask for it -t_no_credentials() -{ - new_device root - run_enroll - is "exit status" 0 "$?" - - says "calls" "$workdir/calls" "enroll --method=recovery-key --no-reuse-initrd" - says "issue file" "$workdir/issue" "Recovery key: $RECOVERY" - opens root "$RECOVERY" - opens_not root "$BOOTSTRAP" -} - -# Every disk that disk-encryption-tool encrypted shares its key, and -# sdbootutil enrolls all of them in a single call -t_multiple_disks() -{ - new_device root - new_device home - run_enroll - is "exit status" 0 "$?" - - is "recovery key enrollments" 1 "$(grep -c "enroll --method=recovery-key" "$workdir/calls" 2> /dev/null)" - opens root "$RECOVERY" - opens home "$RECOVERY" - opens_not root "$BOOTSTRAP" - opens_not home "$BOOTSTRAP" -} - -# The enroll module of jeos-firstboot runs before, and leaves the key -# in the keyring after it wiped the keyslot -t_already_enrolled() -{ - new_device root - cryptsetup luksAddKey --batch-mode --force-password \ - --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \ - --key-file <(echo -n "$BOOTSTRAP") \ - "$workdir/root.img" <(echo -n "jeos-password") - systemd-cryptenroll --wipe-slot=0 "$workdir/root.img" &> /dev/null - run_enroll - is "exit status" 0 "$?" - - says_not "calls" "$workdir/calls" "enroll" - [ ! -s "$workdir/issue" ] || fail "issue file: written, and should not" -} - -# A requested method is the only one enrolled -t_password() -{ - new_device root - credential pw "requested-password" - run_enroll - is "exit status" 0 "$?" - - says "calls" "$workdir/calls" "enroll --method=password --no-reuse-initrd" - says_not "calls" "$workdir/calls" "enroll --method=recovery-key" - opens root "requested-password" - opens_not root "$BOOTSTRAP" -} - -# Without the key of disk-encryption-tool there is nothing to do -t_no_keyring() -{ - new_device root - keyctl purge user cryptenroll &> /dev/null - run_enroll - is "exit status" 0 "$?" - - [ ! -e "$workdir/calls" ] || fail "calls: sdbootutil was called" - opens root "$BOOTSTRAP" -} - -####### the runner ####### - -run_case() -{ - local fn="$1"; shift - local desc="$*" - local rc=0 - - rm -rf "$workdir"/{*.img,devices,calls,issue,out,creds} - keyctl purge user cryptenroll &> /dev/null || true - echo -n "$BOOTSTRAP" | keyctl padd user cryptenroll @u > /dev/null - - ( set +e; case_failed=; "$fn"; [ -z "$case_failed" ] ) || rc=$? - - total=$((total + 1)) - if [ "$rc" = 0 ]; then - echo "ok $desc" - else - failed=$((failed + 1)) - echo "FAIL $desc" - sed 's/^/ | /' "$workdir/out" 2> /dev/null || true - fi -} - -total=0 -failed=0 - -while read -r fn desc; do - [ -n "$fn" ] || continue - run_case "$fn" "$desc" -done <<-'EOF' - t_no_credentials enrolls a recovery key when nothing was requested - t_multiple_disks enrolls the same recovery key in every disk - t_already_enrolled enrolls nothing when the enrollment key was already wiped - t_password enrolls only the requested method - t_no_keyring does nothing without the key of disk-encryption-tool -EOF - -echo -if [ "$failed" = 0 ]; then - echo "$total cases, all passed" -else - echo "$total cases, $failed failed" - exit 1 -fi ++++++ sdbootutil.obsinfo ++++++ --- /var/tmp/diff_new_pack.XPitjJ/_old 2026-10-30 18:58:08.196526976 +0100 +++ /var/tmp/diff_new_pack.XPitjJ/_new 2026-10-30 18:58:08.209527520 +0100 @@ -1,5 +1,5 @@ name: sdbootutil -version: 1+git20261028.5233b70 -mtime: 1793202529 -commit: 5233b701840f4b91bbed367e194d238dddaa11f8 +version: 1+git20261026.4e266f0 +mtime: 1793015089 +commit: 4e266f09ced4ed9a44f290f2cb34b91bae9ac6ef
