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-03-04 20:59:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/sdbootutil (Old) and /work/SRC/openSUSE:Factory/.sdbootutil.new.561 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sdbootutil" Wed Mar 4 20:59:37 2026 rev:93 rq:1336011 version:1+git20260303.90d816d Changes: -------- --- /work/SRC/openSUSE:Factory/sdbootutil/sdbootutil.changes 2026-02-11 18:47:52.030907237 +0100 +++ /work/SRC/openSUSE:Factory/.sdbootutil.new.561/sdbootutil.changes 2026-03-04 20:59:41.306728375 +0100 @@ -1,0 +2,28 @@ +Tue Mar 03 10:21:30 UTC 2026 - Alberto Planas Dominguez <[email protected]> + +- Update to version 1+git20260303.90d816d: + * Allow predicted PCRs to be empty + * Use grubenv for set-timeout (bsc#1258944) + +------------------------------------------------------------------- +Wed Feb 25 13:00:27 UTC 2026 - Alberto Planas Dominguez <[email protected]> + +- Update to version 1+git20260225.fe2f59b (bsc#1258241): + * Use pcrlock predict to filter policy PCRs + * Drop hack to drop PCR9 using shift component + * Add sdbootutil config file + * Force back device for encypted rootfs + * Store backup under service ID (CVE-2026-25701) + +------------------------------------------------------------------- +Thu Feb 19 13:23:48 UTC 2026 - Alberto Planas Dominguez <[email protected]> + +- Update to version 1+git20260219.db678d7: + * Use boot loader's config file only when required + * Do not generate predictions if no boot entries + * Warn when no default entry is found + * Add rootfs and rootfs-data parameters + * Redirect stderr for findmnt + * sdbootutil.spec: Drop obsolete dependency on dialog + +------------------------------------------------------------------- Old: ---- sdbootutil-1+git20260210.81c4815.obscpio New: ---- sdbootutil-1+git20260303.90d816d.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ sdbootutil.spec ++++++ --- /var/tmp/diff_new_pack.8LiqUZ/_old 2026-03-04 20:59:42.546779556 +0100 +++ /var/tmp/diff_new_pack.8LiqUZ/_new 2026-03-04 20:59:42.546779556 +0100 @@ -18,7 +18,7 @@ %global rustflags '-Clink-arg=-Wl,-z,relro,-z,now' Name: sdbootutil -Version: 1+git20260210.81c4815 +Version: 1+git20260303.90d816d Release: 0 Summary: Bootctl wrapper for BLS boot loaders License: MIT @@ -31,7 +31,6 @@ BuildRequires: libopenssl-devel BuildRequires: systemd-rpm-macros Requires: %{name}-dracut-measure-pcr -Requires: dialog Requires: dracut-pcr-signature Requires: efibootmgr Requires: jq ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.8LiqUZ/_old 2026-03-04 20:59:42.618782527 +0100 +++ /var/tmp/diff_new_pack.8LiqUZ/_new 2026-03-04 20:59:42.622782693 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/openSUSE/sdbootutil.git</param> - <param name="changesrevision">81c48154d681e5d93625629081fe66aa838e8095</param></service></servicedata> + <param name="changesrevision">90d816d884019f7ffa0dc7b8e1dc866bfe7f922a</param></service></servicedata> (No newline at EOF) ++++++ sdbootutil-1+git20260210.81c4815.obscpio -> sdbootutil-1+git20260303.90d816d.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20260210.81c4815/sdbootutil new/sdbootutil-1+git20260303.90d816d/sdbootutil --- old/sdbootutil-1+git20260210.81c4815/sdbootutil 2026-02-10 13:47:27.000000000 +0100 +++ new/sdbootutil-1+git20260303.90d816d/sdbootutil 2026-03-03 11:19:37.000000000 +0100 @@ -43,6 +43,8 @@ arg_no_measure_pcr= arg_measure_pcr= arg_pcr= +arg_rootfs= +arg_rootfs_data= arg_force= have_snapshots= # for x in vmlinuz image vmlinux linux bzImage uImage Image zImage; do @@ -76,7 +78,7 @@ rollback=() -declare -g -A eventlog +declare -A eventlog tmpdir=$(mktemp -d -t sdbootutil.XXXXXX) cleanup() @@ -138,6 +140,10 @@ --pcr Comma seperated list of PCRs to enroll --devices Comma separated list of devices to enroll or unenroll (by default all (not ignored) devices are [un]enrolled) + --rootfs During bootloader installation, select the kind of 'root' + valid selectors + (uuid, partuuid, label, partlabel, device) + --rootfs-data Extra data when --rootfs is used --force Force certain operations inside a transaction -v, --verbose More verbose output --start-trace-code Create /var/log/sdbootutil.log to trace the code. @@ -298,16 +304,82 @@ is_config_file() { - [ -e /usr/etc/default/fde-tools ] || + [ -e /usr/etc/default/sdbootutil ] || + [ -e /etc/default/sdbootutil ] || + [ -e /usr/etc/default/fde-tools ] || [ -e /etc/default/fde-tools ] || [ -e /etc/sysconfig/fde-tools ] } +set_default_config_values() +{ + FDE_SEAL_PCR_LIST="$arg_pcr" + if is_installed && [ -z "${FDE_SEAL_PCR_LIST}" ]; then + if systemd-detect-virt -q; then + info "Virtualized systemd detected ($(systemd-detect-virt)). Dropping PCR0 and PCR2" + FDE_SEAL_PCR_LIST="" + else + FDE_SEAL_PCR_LIST="0,2," + fi + if is_sdboot; then + FDE_SEAL_PCR_LIST+="4,7,9" + elif is_grub2_bls; then + FDE_SEAL_PCR_LIST+="4,7,8,9" + else + err "Bootloader not detected" + fi + fi + + if is_rootfs_crypt; then + # `measure-pcr-validator` (PRC15) protect from + # impostor LUKS2 volumes, as it measures the volume + # key. But if there is a volume in a non-encrypted + # device (USB, for example) that has the same metadata + # (referenced by /etc/fstab) as the internal volume in + # the encrypted root device, then there is a chance + # that this will get mounted in /sysroot. systemd can + # measure elements from the file system (like UUID or + # /etc/machine-id) via [email protected], + # but this data is public and can be replicated + # + # See bsc#1229934 for more details + ROOTFS="device" + else + ROOTFS="uuid" + fi + ROOTFS="${arg_rootfs:-$ROOTFS}" +} + +create_default_config_file() +{ + ! is_config_file || return 0 + + set_default_config_values + cat <<-EOF > /etc/default/sdbootutil + # Default sdbootutil configuration file generated automatically + + # List of PCRs. For VMs PCRs 0 and 2 are dropped + FDE_SEAL_PCR_LIST="$FDE_SEAL_PCR_LIST" + + # Parameter used in the cmdline to find the root (device, [part]uuid, [part]label) + # For encrypted devices it is forced "device" + ROOTFS="$ROOTFS" + EOF +} + load_config_file() { local f - # Some old installations have /etc/sysconfig/fde-tools - for f in /usr/etc/default/fde-tools /etc/default/fde-tools /etc/sysconfig/fde-tools; do + + set_default_config_values + + # Prioritize sdbootutil configuration file, and use fde-tools + # as a fallback + for f in /usr/etc/default/sdbootutil \ + /etc/default/sdbootutil \ + /usr/etc/default/fde-tools \ + /etc/default/fde-tools \ + /etc/sysconfig/fde-tools; do [ ! -e "$f" ] || { # shellcheck disable=SC1090 . "$f" @@ -315,6 +387,16 @@ dbg_cat "$f" } done + + # Force back "device" for ROOTFS if is encrypted + if is_rootfs_crypt; then + [ "$ROOTFS" = "device" ] || info "Fix the /etc/default/sdbootutil to set ROOTFS as 'device'" + ROOTFS="device" + fi + + # If arguments are passed, use them + FDE_SEAL_PCR_LIST="${arg_pcr:-$FDE_SEAL_PCR_LIST}" + ROOTFS="${arg_rootfs:-$ROOTFS}" } is_secure_boot() @@ -368,7 +450,7 @@ is_transactional() { - findmnt --fstab / -O ro > /dev/null + findmnt --fstab / -O ro &> /dev/null } keyctl_add_with_timeout() @@ -458,14 +540,71 @@ dbg_var "parent_snapshot" } +is_rootfs_crypt() +{ + local device + read -r device < <(findmnt / -v -r -n -o SOURCE 2> /dev/null) + [ -n "$device" ] && [ "$(lsblk --noheadings -o TYPE "$device")" = "crypt" ] +} + +get_rootfs() +{ + local rootfs_data + + case "$ROOTFS" in + uuid) read -r rootfs_data < <(findmnt / -v -r -n -o UUID 2> /dev/null) ;; + label) read -r rootfs_data < <(findmnt / -v -r -n -o LABEL 2> /dev/null) ;; + partuuid) read -r rootfs_data < <(findmnt / -v -r -n -o PARTUUID 2> /dev/null) ;; + partlabel) read -r rootfs_data < <(findmnt / -v -r -n -o PARTLABEL 2> /dev/null) ;; + device) read -r rootfs_data < <(findmnt / -v -r -n -o SOURCE 2> /dev/null) ;; + *) + info "Can't determine rootfs ($ROOTFS). Using UUID as default" + ROOTFS="uuid" + read -r rootfs_data < <(findmnt / -v -r -n -o UUID 2> /dev/null) + ;; + esac + rootfs_data="${arg_rootfs_data:-$rootfs_data}" + + if [ "$ROOTFS" = "device" ]; then + echo "$rootfs_data" + else + echo "${ROOTFS^^}=$rootfs_data" + fi +} + +get_all_rootfs() +{ + local rootfs rootfs_data + + read -r rootfs_data < <(findmnt / -v -r -n -o SOURCE) + rootfs="$rootfs_data" + + read -r rootfs_data < <(findmnt / -v -r -n -o UUID) + [ -z "$rootfs_data" ] || rootfs="$rootfs|UUID=$rootfs_data" + + read -r rootfs_data < <(findmnt / -v -r -n -o LABEL) + [ -z "$rootfs_data" ] || rootfs="$rootfs|LABEL=$rootfs_data" + + read -r rootfs_data < <(findmnt / -v -r -n -o PARTUUID) + [ -z "$rootfs_data" ] || rootfs="$rootfs|PARTUUID=$rootfs_data" + + read -r rootfs_data < <(findmnt / -v -r -n -o PARTLABEL) + [ -z "$rootfs_data" ] || rootfs="$rootfs|PARTLABEL=$rootfs_data" + + echo "$rootfs" +} + sedrootflags() { local subvol="$1" + local root_param + root_param="$(get_rootfs)" + # - Delete everything before BOOT_IMAGE= and initrd= # (see https://github.com/openSUSE/sdbootutil/issues/182) # - Delete BOOT_IMAGE= and initrd= - # - Replace or add root= to refers to UUID or mapped device - # (if encrypted) + # - Replace or add root= to refers to [PART]{UUID, LABEL}, or + # mapped device # - Replace or add rootflags to point at correct subvolume # - Replace or add systemd.machine-id to match current # machine-id @@ -481,8 +620,6 @@ # already there). Since we always operate on the same line, # "empty" t jumps are used to reset the condition after very # s///. - local root_param="UUID=$root_uuid" - [ -z "$root_device_is_crypt" ] || root_param="$root_device" local sed_arguments=("-e s/[ \t]\+/ /g" "-e s/^.*\(initrd=[^ ]*\|BOOT_IMAGE=[^ ]*\)\s*/\1 /" "-e s/\<\(BOOT_IMAGE\|initrd\)=[^ ]* \?//" @@ -493,6 +630,7 @@ sed "${sed_arguments[@]}" } + entry_filter=("cat") update_entries() { @@ -507,8 +645,11 @@ local subvol="$1" local ext="${2:-}" + local root + root="$(get_all_rootfs)" + [ -z "$ext" ] || ext="|$ext" - update_entries jq "[.[]|select(has(\"options\"))|select(.options|test(\"root=(?:UUID=$root_uuid|$root_device) .*rootflags=subvol=$subvol\")$ext)]" + update_entries jq "[.[]|select(has(\"options\"))|select(.options|test(\"root=(?:$root) .*rootflags=subvol=$subvol\")$ext)]" } update_entries_for_snapshot() @@ -525,7 +666,10 @@ update_entries_for_this_system() { - update_entries jq "[.[]|select(has(\"options\"))|select(.options|test(\"root=(?:UUID=$root_uuid|$root_device)\"))]" + local root + root="$(get_all_rootfs)" + + update_entries jq "[.[]|select(has(\"options\"))|select(.options|test(\"root=(?:$root)\"))]" } entry_conf_file() @@ -640,7 +784,11 @@ # grubenv value) local default default="$(get_default_bootctl)" - set_default_entry "$default" + if [ -z "$default" ]; then + warn "Can't determine the new default entry" + else + set_default_entry "$default" + fi # This action will require to update the PCR predictions update_predictions=1 @@ -879,7 +1027,7 @@ # one extra snapshot if it is passed as a parameter, that # refers to the snapshot from where we are installing the # kernel - declare -A snapshots + local -A snapshots [ -z "$snapshot" ] || snapshots["$snapshot"]=1 [ -z "$root_snapshot" ] || snapshots["$root_snapshot"]=1 local id @@ -1754,13 +1902,14 @@ fi # Create boot menu entry if it does not exist - local drive partno - read -r drive partno _ < <(boot_root_drive_partno_dseq) - local escaped_entry="${entry//\//\\\\}" - [ -n "$arg_no_variables" ] || [ -n "$arg_portable" ] || efibootmgr | grep -q "Boot.*${boot_manager}.*${escaped_entry}" || efibootmgr -q --create --disk "$drive" --part "$partno" --label "${boot_manager} ($bldr_name)" --loader "$entry" || true + if [ -z "$arg_no_variables" ] && [ -z "$arg_portable" ] && mountpoint -q "$boot_root"; then + local drive partno + read -r drive partno _ < <(boot_root_drive_partno_dseq) + + local escaped_entry="${entry//\//\\\\}" + efibootmgr | grep -q "Boot.*${boot_manager}.*${escaped_entry}" || efibootmgr -q --create --disk "$drive" --part "$partno" --label "${boot_manager} ($bldr_name)" --loader "$entry" || true - # Make it the first option - if [ -z "$arg_no_variables" ] && [ -z "$arg_portable" ]; then + # Make it the first option local boot_order boot_order="$(efibootmgr | grep BootOrder)" boot_order="${boot_order#BootOrder: }" @@ -1815,13 +1964,27 @@ mv "$boot_root/loader/random-seed.new" "$boot_root/loader/random-seed" } +has_efivars() +{ + [ -d /sys/firmware/efi/efivars ] +} + bli_efi_var_get() { # BLI uses this vendor UUID local efi_var="/sys/firmware/efi/efivars/${1:?}-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" - if [ -e "$efi_var" ]; then - dd "if=$efi_var" bs=2 skip=2 conv=lcase status=none | tr -d '\0' - fi + [ ! -e "$efi_var" ] || dd "if=$efi_var" bs=2 skip=2 conv=lcase status=none | tr -d '\0' +} + +bli_efi_var_set() +{ + # BLI uses this vendor UUID + local efi_var="/sys/firmware/efi/efivars/${1:?}-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" + local value="${2:?}" + has_efivars || return 1 + [ -e "$efi_var" ] && chattr -i "$efi_var" + echo -ne "\x07\x00${value}\x00" | iconv -t UTF-16LE > "$efi_var" + chattr +i "$efi_var" } loader_conf_set() @@ -1883,22 +2046,24 @@ set_default_sdboot() { local id="${1:?}" - if ! bootctl set-default "$id" > "$tmpfile" 2>&1; then - if grep -q "Failed to update EFI variable" "$tmpfile" || - grep -q "Not booted with a supported boot loader" "$tmpfile" || - grep -q "Not booted with UEFI" "$tmpfile"; then - loader_conf_set "default" "$id" - else - err "$(cat "$tmpfile")" - fi + + if ! has_efivars || [ -n "$arg_no_variables" ]; then + 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 } set_default_grub2_bls() { local id="${1:?}" - set_default_sdboot "$id" - grubenv_set "default" "$id" + if systemd-analyze compare-versions "$(bootloader_version)" "<" "2.13" || ! has_efivars || [ -n "$arg_no_variables" ]; then + grubenv_set "default" "$id" + elif ! bli_efi_var_set "LoaderEntryDefault" "$id"; then + warn "EFI variable LoaderEntryDefault cannot be set. Falling back to configuration file" + grubenv_set "default" "$id" + fi } set_default_entry() @@ -1955,8 +2120,9 @@ get_default_grub2_bls() { local val - val="$(grubenv_get "default")" - [ -n "$val" ] || val="$(get_default_sdboot)" + val="$(bli_efi_var_get "LoaderEntryDefault")" + [ -n "$val" ] || val="$(grubenv_get "default")" + [ -n "$val" ] || val="$(get_default_bootctl)" [ -z "$val" ] || echo "$val" } @@ -1974,25 +2140,51 @@ set_timeout_sdboot() { local timeout="${1:?}" + # `bootctl set-timeout menu-hidden` writes "0", and + # "menu-disabled" write the full text. In both cases the menu + # is hidden. + # + # `bootctl set-timeout menu-force` writes 2^32-1 in the EFI + # variable (fix needs to be backported) (bsc#1258944) + [ "$timeout" = "0" ] && timeout="menu-disabled" [ "$timeout" = "-1" ] && timeout="menu-force" - if ! bootctl set-timeout "$timeout" > "$tmpfile" 2>&1; then - if grep -q "Failed to update EFI variable" "$tmpfile" || - grep -q "Not booted with a supported boot loader" "$tmpfile" || - grep -q "Not booted with UEFI" "$tmpfile"; then - loader_conf_set "timeout" "$timeout" - else - err "$(cat "$tmpfile")" - fi + + # `bootctl set-timeout menu-force` writes 2^32-1 in the EFI + # variable (fix needs to be backported) (bsc#1258944) + if ! has_efivars || [ -n "$arg_no_variables" ]; then + loader_conf_set "timeout" "$timeout" + elif ! bli_efi_var_set "LoaderConfigTimeout" "$timeout"; then + warn "EFI variable LoaderConfigTimeout cannot be set. Falling back to configuration file" + loader_conf_set "timeout" "$timeout" fi } set_timeout_grub2_bls() { local timeout="${1:?}" - set_timeout_sdboot "$timeout" - [ "$timeout" = "menu-disabled" ] || [ "$timeout" = "menu-hidden" ] && timeout=0 - [ "$timeout" = "menu-force" ] && timeout=-1 - grubenv_set "timeout" "$timeout" + # `bootctl set-timeout menu-hidden` writes "0", and + # "menu-disabled" write the full text. In both cases the menu + # is hidden. + # + # `bootctl set-timeout menu-force` writes 2^32-1 in the EFI + # variable (fix needs to be backported) (bsc#1258944) + # + # We map the same string that works in grub2-bls with the + # downstream patch + [ "$timeout" = "menu-disabled" ] && timeout="menu-hidden" + [ "$timeout" = "0" ] && timeout="menu-hidden" + [ "$timeout" = "-1" ] && timeout="menu-force" + + if systemd-analyze compare-versions "$(bootloader_version)" "<" "2.13" || ! has_efivars || [ -n "$arg_no_variables" ]; then + [ "$timeout" = "menu-disabled" ] || [ "$timeout" = "menu-hidden" ] && timeout=0 + [ "$timeout" = "menu-force" ] && timeout=-1 + grubenv_set "timeout" "$timeout" + elif ! bli_efi_var_set "LoaderConfigTimeout" "$timeout"; then + warn "EFI variable LoaderConfigTimeout cannot be set. Falling back to configuration file" + [ "$timeout" = "menu-disabled" ] || [ "$timeout" = "menu-hidden" ] && timeout=0 + [ "$timeout" = "menu-force" ] && timeout=-1 + grubenv_set "timeout" "$timeout" + fi } set_timeout() @@ -2016,16 +2208,18 @@ local val val="$(bli_efi_var_get "LoaderConfigTimeout")" [ -n "$val" ] || val="$(loader_conf_get "timeout")" - if [ "$val" = 4294967295 ]; then - val=-1 - fi + [ "$val" = "menu-disabled" ] || [ "$val" = "menu-hidden" ] && val=0 + [ "$val" = 4294967295 ] || [ "$val" = "menu-force" ] && val=-1 [ -z "$val" ] || echo "$val" } get_timeout_grub2_bls() { local val - val="$(grubenv_get "timeout")" + val="$(bli_efi_var_get "LoaderConfigTimeout")" + [ -n "$val" ] || val="$(grubenv_get "timeout")" + [ "$val" = "menu-disabled" ] || [ "$val" = "menu-hidden" ] && val=0 + [ "$val" = 4294967295 ] || [ "$val" = "menu-force" ] && val=-1 [ -z "$val" ] || echo "$val" } @@ -2282,7 +2476,7 @@ # # When using systemd-boot or GRUB2-BLS >= 2.14, the cmdline is # send to the kernel via UEFI with null termination (double - # \0, as is UTF-16 enconding), but this is missing in + # \x00, as is UTF-16 enconding), but this is missing in # GRUB2-BLS <= 2.12 echo -n "$cmdline" > "$tmpdir/cmdline" if is_sdboot; then @@ -2324,7 +2518,7 @@ if is_sdboot; then # We cannot use lock-kernel-cmdline, as it ignore # --pcr=12, and assign PCR 9 in any case - echo -ne "$cmdline\0" > "$tmpdir/cmdline" + echo -ne "$cmdline\x00" > "$tmpdir/cmdline" iconv -t UTF-16LE -o "$tmpdir/cmdline.utf16" "$tmpdir/cmdline" pcrlock \ lock-raw \ @@ -2405,10 +2599,12 @@ locks+=("$tmpdir/entry-$n.pcrlock") done mkdir -p /var/lib/pcrlock.d/643-grub2-bls-entry-files.pcrlock.d - jq --slurp '{"records": [.[].records[0]]}' \ - "${locks[@]}" \ - > "/var/lib/pcrlock.d/643-grub2-bls-entry-files.pcrlock.d/generated$suffix.pcrlock" - rm "${locks[@]}" + [ "${#locks[@]}" -eq 0 ] || { + jq --slurp '{"records": [.[].records[0]]}' \ + "${locks[@]}" \ + > "/var/lib/pcrlock.d/643-grub2-bls-entry-files.pcrlock.d/generated$suffix.pcrlock" + rm "${locks[@]}" + } } pcrlock_sdboot() @@ -2620,20 +2816,16 @@ # will be asked. To resolve this we can drop PCR#9 when there # is a new kernel and allow the rollback without a password, # and lock on PCR#9 during boot time, via the - # sdbootutil-update-predictions service + # sdbootutil-update-predictions service. + # + # As systemd-pcrlock does not drop a PCR that exceed the + # PolicyPR limit, we need to first create a prediction and + # count the values local limit=1 is_transactional || limit=3 - # If the system is transactional, drop the shift variation. - # If there is a new kernel, only the newest one will be - # measured (sort_by) and the current one that is in the event - # log will not be present in any variation. This will make - # pcrlock lost the track and drop the component. But if there - # is not new kernel or initrd, then the only variation will be - # found in the event log - # Join the kernel and the initrd in a single component - is_transactional || shift_component 710-grub2-bls-kernel-initrd-entry + shift_component 710-grub2-bls-kernel-initrd-entry n=0 while read -r linux; do read -r initrd @@ -2728,6 +2920,58 @@ fi } +get_final_pcrs() +{ + local pcrs="$1" + + # Generate a JSON prediction, to get the final PCRs that will + # participate in the policy. To avoid the PolicyOR limit, we + # filter the PCRs with more that 8 values + local output + output="$(pcrlock --pcr="$pcrs" --json=short predict 2>"$tmpfile")" + local pcrlock_status=$? + + if [ "$pcrlock_status" -ne 0 ]; then + err "Error creating the systemd-pcrlock prediction!\n$(cat "$tmpfile")" + fi + + # If no PCRs are included, we are starting from a very + # misaligned event log (initial installation, for example) + [ ! "$output" = "{}" ] || { + echo "$pcrs" + return 0 + } + + # PCRs that participate in the policy + local pcrs_policy + pcrs_policy="$(jq -r '[.sha256[] | select(.values | length <= 8) | .pcr] | join(",")' <<<"$output")" + + # PCRs dropped because they have more than 8 values + local pcrs_policyor + pcrs_policyor="$(jq -r '[.sha256[] | select(.values | length > 8) | .pcr] | join(",")' <<<"$output")" + + local i + local -A pcrs_policy_table + while read -r -d ',' i; do + pcrs_policy_table[$i]=1 + done <<<"$pcrs_policy" + + local -A pcrs_policy_missing_table + while read -r -d ',' i; do + if [ -z "${pcrs_policy_table[$i]}" ]; then + pcrs_policy_missing_table[$i]=1 + fi + done <<<"$pcrs" + + local pcrs_policy_missing + pcrs_policy_missing="$(IFS=","; echo "${!pcrs_policy_missing_table[*]}")" + [ -z "$pcrs_policy_missing" ] || info "PCRs $pcrs_policy_missing dropped from the policy (component mapping)" + [ -z "$pcrs_policyor" ] || info "PCRs $pcrs_policyor dropped from the policy (PolicyOR)" + [ "$pcrs" = "$pcrs_policy" ] || info "Final PCRs list ($pcrs -> $pcrs_policy)" + + echo "$pcrs_policy" +} + generate_tpm2_predictions_pcrlock() { local pcrs="$FDE_SEAL_PCR_LIST" @@ -2852,12 +3096,15 @@ extra=("--recovery-pin=show") fi + local final_pcrs + final_pcrs="$(get_final_pcrs "$pcrs")" + local output - output="$(PIN="$pin" pcrlock --pcr="$pcrs" "${extra[@]}" make-policy)" + output="$(PIN="$pin" pcrlock --pcr="$final_pcrs" "${extra[@]}" make-policy 2>"$tmpfile")" local pcrlock_status=$? - if [ $pcrlock_status -ne 0 ]; then - echo "Error creating the systemd-pcrlock policy!" + if [ "$pcrlock_status" -ne 0 ]; then + warn "Error creating the systemd-pcrlock policy!\n$(cat "$tmpfile")" return 1 elif echo "$output" | grep -q "recovery PIN"; then local split @@ -3139,13 +3386,11 @@ # situation but fail during the initial enrollment. This is # because we generate the prediction first and later we do the # enrollment - is_config_file || { - warn "/etc/sysconfig/fde-tools not found (manual enrollment?)" + [ -n "$FDE_SEAL_PCR_LIST" ] || { + warn "FDE_SEAL_PCR_LIST no found in /etc/default/sdbootutil (manual enrollment?)" warn "No TPM2 predictions generated" return 0 } - load_config_file - [ -z "$arg_pcr" ] || FDE_SEAL_PCR_LIST="$arg_pcr" if is_pcr_oracle; then generate_tpm2_predictions_pcr_oracle @@ -3654,27 +3899,6 @@ # early. Also we need to set the PCRs used to assest the # system status if [ "$arg_method" = "tpm2" ] || [ "$arg_method" = "tpm2+pin" ]; then - load_config_file - [ -z "$arg_pcr" ] || FDE_SEAL_PCR_LIST="$arg_pcr" - - if [ -z "${FDE_SEAL_PCR_LIST}" ]; then - if systemd-detect-virt -q; then - info "Virtualized systemd detected ($(systemd-detect-virt)). Dropping PCR0 and PCR2" - FDE_SEAL_PCR_LIST="" - else - FDE_SEAL_PCR_LIST="0,2," - fi - if is_sdboot; then - FDE_SEAL_PCR_LIST+="4,7,9" - elif is_grub2_bls; then - FDE_SEAL_PCR_LIST+="4,7,8,9" - else - err "Bootloader not detected" - fi - fi - - is_config_file || echo "FDE_SEAL_PCR_LIST=${FDE_SEAL_PCR_LIST}" >> /etc/default/fde-tools - if { ! have_pcrlock || [ -n "$arg_signed_policy" ]; } && have_pcr_oracle; then # Once the RSA key is present, then # is_pcr_oracle is true @@ -3954,6 +4178,8 @@ [measure-pcr]="" [pcr]="_none" [devices]="_devices" + [rootfs]="_rootfs" + [rootfs-data]="_rootfs_data" [force]="" ) opts_long="" @@ -4009,6 +4235,8 @@ --measure-pcr) arg_measure_pcr=1; shift ;; --pcr) arg_pcr="$2"; shift 2 ;; --devices) IFS=',' read -r -a tracked_devices <<<"$2"; shift 2 ;; + --rootfs) arg_rootfs="$2"; shift 2 ;; + --rootfs-data) arg_rootfs_data="$2"; shift 2 ;; --force) arg_force=1; shift ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; @@ -4034,9 +4262,7 @@ [ -n "$arg_esp_path" ] && export SYSTEMD_ESP_PATH="$arg_esp_path" eval_bootctl -read -r root_uuid root_device < <(findmnt / -v -r -n -o UUID,SOURCE) -root_device_is_crypt= -[ "$(lsblk --noheadings -o TYPE "$root_device")" = "crypt" ] && root_device_is_crypt=1 + root_subvol="" subvol_prefix="" if [ "$(stat -f -c %T /)" = "btrfs" ] && [ -d /.snapshots ]; then @@ -4061,13 +4287,11 @@ [ -n "$arg_arch" ] && firmware_arch="$arg_arch" [ -n "$boot_root" ] || err "No ESP detected. Legacy system?" -[ -n "$root_uuid" ] || err "Can't determine root UUID" [ -n "$root_subvol" ] || [ -z "$have_snapshots" ] || err "Can't determine root subvolume" -[ -n "$root_device" ] || err "Can't determine root device" [ -n "$firmware_arch" ] || err "Can't determine firmware arch" set_image_name -mountpoint -q "$boot_root" || err "$boot_root is not a valid mountpoint" +mountpoint -q "$boot_root" || warn "$boot_root is not a valid mountpoint" dbg_var "root_snapshot" dbg_var "boot_root" @@ -4116,6 +4340,17 @@ arg_no_variables=1 fi +# If there is a config file, load it. If not, but the bootloader was +# installed, create a default one (using the CLI arguments). If not, +# use some default values. +if is_config_file; then + load_config_file +elif is_installed; then + create_default_config_file +else + set_default_config_values +fi + # Keep initial components before they are replaced by some actions # (new initrd, new entry, etc) if [ "$SDB_ADD_INITIAL_COMPONENT" = "1" ]; then @@ -4124,7 +4359,8 @@ case "$1" in install) - install_bootloader "${2:-$root_snapshot}" ;; + install_bootloader "${2:-$root_snapshot}" + create_default_config_file ;; needs-update) bootloader_needs_update "${2:-$root_snapshot}" ;; update) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20260210.81c4815/sdbootutil-update-predictions.service new/sdbootutil-1+git20260303.90d816d/sdbootutil-update-predictions.service --- old/sdbootutil-1+git20260210.81c4815/sdbootutil-update-predictions.service 2026-02-10 13:47:27.000000000 +0100 +++ new/sdbootutil-1+git20260303.90d816d/sdbootutil-update-predictions.service 2026-03-03 11:19:37.000000000 +0100 @@ -6,16 +6,16 @@ Type=oneshot RemainAfterExit=yes KeyringMode=shared -PrivateTmp=no -ExecStartPre=/usr/bin/sh -c 'cp -a /var/lib/pcrlock.d /tmp/pcrlock.d.bak' +PrivateTmp=yes +ExecStartPre=/usr/bin/sh -c 'mkdir "/tmp/$INVOCATION_ID"; cp -a /var/lib/pcrlock.d /tmp/$INVOCATION_ID/pcrlock.d' ExecStart=/usr/bin/sdbootutil -v update-predictions ExecStopPost=/usr/bin/sh -c '\ - if [ "$EXIT_STATUS" != "0" ]; then \ - echo "Command failed (Status: $EXIT_STATUS). Restoring backup..."; \ + if [ "$SERVICE_RESULT" != "success" ]; then \ + echo "Command failed. Reason: $SERVICE_RESULT (Status: $EXIT_STATUS). Restoring backup..."; \ rm -rf /var/lib/pcrlock.d/*; \ - cp -a /tmp/pcrlock.d.bak/. /var/lib/pcrlock.d/; \ + cp -a "/tmp/$INVOCATION_ID/pcrlock.d/." /var/lib/pcrlock.d/; \ fi; \ - rm -rf /tmp/pcrlock.d.bak' + rm -rf "/tmp/$INVOCATION_ID/pcrlock.d"' ImportCredential=sdbootutil-update-predictions.* [Install] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20260210.81c4815/sdbootutil.spec new/sdbootutil-1+git20260303.90d816d/sdbootutil.spec --- old/sdbootutil-1+git20260210.81c4815/sdbootutil.spec 2026-02-10 13:47:27.000000000 +0100 +++ new/sdbootutil-1+git20260303.90d816d/sdbootutil.spec 2026-03-03 11:19:37.000000000 +0100 @@ -31,7 +31,6 @@ BuildRequires: libopenssl-devel BuildRequires: systemd-rpm-macros Requires: %{name}-dracut-measure-pcr -Requires: dialog Requires: dracut-pcr-signature Requires: efibootmgr Requires: jq ++++++ sdbootutil.obsinfo ++++++ --- /var/tmp/diff_new_pack.8LiqUZ/_old 2026-03-04 20:59:42.842791774 +0100 +++ /var/tmp/diff_new_pack.8LiqUZ/_new 2026-03-04 20:59:42.850792103 +0100 @@ -1,5 +1,5 @@ name: sdbootutil -version: 1+git20260210.81c4815 -mtime: 1770727647 -commit: 81c48154d681e5d93625629081fe66aa838e8095 +version: 1+git20260303.90d816d +mtime: 1772533177 +commit: 90d816d884019f7ffa0dc7b8e1dc866bfe7f922a
