Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package sdbootutil for openSUSE:Factory checked in at 2024-07-17 15:14:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/sdbootutil (Old) and /work/SRC/openSUSE:Factory/.sdbootutil.new.17339 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sdbootutil" Wed Jul 17 15:14:01 2024 rev:23 rq:1186164 version:1+git20240704.a2c5a26 Changes: -------- --- /work/SRC/openSUSE:Factory/sdbootutil/sdbootutil.changes 2024-05-16 17:12:47.090723892 +0200 +++ /work/SRC/openSUSE:Factory/.sdbootutil.new.17339/sdbootutil.changes 2024-07-17 15:14:32.236723195 +0200 @@ -1,0 +2,30 @@ +Thu Jul 04 12:02:17 UTC 2024 - [email protected] + +- Update to version 1+git20240704.a2c5a26: + * Complain if fde-tools is missing + * Remove rpm scriptlets + * Remove is_transactional check + * Call regenerate-initrd-posttrans + * Remove pcrlock files older than 1 week + * Measure initial state from backup + * Remove useless TODO comments + * Rename variable to SDB_ADD_INITIAL_COMPONENT + * Fix transactional check + * Add system / snapper as prefix for tw/grub2-bls + * Compose the entry file name in a single place + * Make 'invert' a generic case + * Make free space for new kernel / initrd + * Replace match with test in jq + * grub: add grub drive in initrd path + * grub: blscfg is included in the image + * Fix pcrlock_manual_raw call + * Add emacs .dir-locals.el + * Show success message + * Use a recovery pin for re-enrollment + * grub2: entries predictions as a single component + * grub2: remove duplicate function + * Add blscfg.mod in the ESP and update predictions + * grub2: generate pcrlock predictions + * Fix some typos + +------------------------------------------------------------------- Old: ---- sdbootutil-1+git20240514.56dc89c.obscpio New: ---- sdbootutil-1+git20240704.a2c5a26.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ sdbootutil.spec ++++++ --- /var/tmp/diff_new_pack.MHPg7U/_old 2024-07-17 15:14:32.984750328 +0200 +++ /var/tmp/diff_new_pack.MHPg7U/_new 2024-07-17 15:14:32.984750328 +0200 @@ -27,7 +27,7 @@ %define git_version %{nil} %endif Name: sdbootutil -Version: 1+git20240514.56dc89c%{git_version} +Version: 1+git20240704.a2c5a26%{git_version} Release: 0 Summary: script to install shim with sd-boot License: MIT @@ -44,6 +44,7 @@ Requires: dracut-pcr-signature Supplements: (systemd-boot and shim) Requires: (%{name}-snapper if (snapper and btrfsprogs)) +Requires: (%{name}-tukit if read-only-root-fs) ExclusiveArch: aarch64 ppc64le riscv64 x86_64 %description @@ -59,19 +60,14 @@ %description snapper Plugin scripts for snapper to handle BLS config files -%package rpm-scriptlets -Summary: Scripts to create boot entries on kernel updates +%package tukit +Summary: plugin script for tukit +Requires: %{name} = %{version} Requires: sdbootutil >= %{version}-%{release} -# make sure to not replace scriptlets with nops on systems that -# use grub2 -Conflicts: grub2 -Conflicts: suse-kernel-rpm-scriptlets -Provides: suse-kernel-rpm-scriptlets -Obsoletes: %{name}-filetriggers < %{version} - -%description rpm-scriptlets -Scriptlets that call sdbootutil to create boot entries when -kernels are installed or removed +Requires: tukit + +%description tukit +Plugin scripts for tukit to handle BLS config files %package kernel-install Summary: Hook script for kernel-install @@ -95,25 +91,18 @@ install -D -m 644 "$i" %{buildroot}%{_unitdir}/"$i" done -mkdir -p %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets -for a in rpm; do - install -m 755 "$a-script" %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets - for b in post posttrans postun pre preun; do - ln -s "$a-script" %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets/$a-$b - done -done -for a in cert inkmp kmp; do - for b in post posttrans postun pre preun; do - ln -s /bin/true %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets/$a-$b - done -done - # snapper install -d -m755 %{buildroot}%{_prefix}/lib/snapper/plugins for i in 10-sdbootutil.snapper; do install -m 755 $i %{buildroot}%{_prefix}/lib/snapper/plugins/$i done +# tukit +install -d -m755 %{buildroot}%{_prefix}/lib/tukit/plugins +for i in 10-sdbootutil.tukit; do + install -m 755 $i %{buildroot}%{_prefix}/lib/tukit/plugins/$i +done + # kernel-install install -d -m755 %{buildroot}%{_prefix}/lib/kernel/install.d for i in 50-sdbootutil.install; do @@ -143,15 +132,16 @@ %{_bindir}/sdbootutil %{_unitdir}/sdbootutil-update-predictions.service -%files rpm-scriptlets -%dir %{_prefix}/lib/module-init-tools -%{_prefix}/lib/module-init-tools/* - %files snapper %dir %{_prefix}/lib/snapper %dir %{_prefix}/lib/snapper/plugins %{_prefix}/lib/snapper/plugins/* +%files tukit +%dir %{_prefix}/lib/tukit +%dir %{_prefix}/lib/tukit/plugins +%{_prefix}/lib/tukit/plugins/* + %files kernel-install %dir %{_prefix}/lib/kernel %dir %{_prefix}/lib/kernel/install.d ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.MHPg7U/_old 2024-07-17 15:14:33.032752069 +0200 +++ /var/tmp/diff_new_pack.MHPg7U/_new 2024-07-17 15:14:33.036752214 +0200 @@ -3,6 +3,6 @@ <param name="url">https://github.com/lnussel/sdbootutil.git</param> <param name="changesrevision">708592a5033bb41d14e378172466ae9e90dfb3c4</param></service><service name="tar_scm"> <param name="url">https://github.com/openSUSE/sdbootutil.git</param> - <param name="changesrevision">56dc89ccb5823154450c9164d1b8f3e256709284</param></service></servicedata> + <param name="changesrevision">a2c5a26866076afd91446dea57a44ac91746a4bf</param></service></servicedata> (No newline at EOF) ++++++ sdbootutil-1+git20240514.56dc89c.obscpio -> sdbootutil-1+git20240704.a2c5a26.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20240514.56dc89c/.dir-locals.el new/sdbootutil-1+git20240704.a2c5a26/.dir-locals.el --- old/sdbootutil-1+git20240514.56dc89c/.dir-locals.el 1970-01-01 01:00:00.000000000 +0100 +++ new/sdbootutil-1+git20240704.a2c5a26/.dir-locals.el 2024-07-04 14:00:45.000000000 +0200 @@ -0,0 +1 @@ +((sh-mode . ((sh-basic-offset . 8)))) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20240514.56dc89c/10-sdbootutil.snapper new/sdbootutil-1+git20240704.a2c5a26/10-sdbootutil.snapper --- old/sdbootutil-1+git20240514.56dc89c/10-sdbootutil.snapper 2024-05-14 14:11:26.000000000 +0200 +++ new/sdbootutil-1+git20240704.a2c5a26/10-sdbootutil.snapper 2024-07-04 14:00:45.000000000 +0200 @@ -46,6 +46,10 @@ if is_transactional; then /usr/bin/sdbootutil add-all-kernels "$num" || : /usr/bin/sdbootutil update "$num" || : + + if [ -e /usr/lib/module-init-tools/regenerate-initrd-posttrans ]; then + /usr/lib/module-init-tools/regenerate-initrd-posttrans + fi fi /usr/bin/sdbootutil set-default-snapshot "$num" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20240514.56dc89c/10-sdbootutil.tukit new/sdbootutil-1+git20240704.a2c5a26/10-sdbootutil.tukit --- old/sdbootutil-1+git20240514.56dc89c/10-sdbootutil.tukit 1970-01-01 01:00:00.000000000 +0100 +++ new/sdbootutil-1+git20240704.a2c5a26/10-sdbootutil.tukit 2024-07-04 14:00:45.000000000 +0200 @@ -0,0 +1,31 @@ +#!/bin/bash + +shopt -s extglob nullglob +set -e + +callExt_post() +{ + path="$1" + + if [ -e "$path"/run/regenerate-initrd ]; then + cp -a "$path"/run/regenerate-initrd /run + fi +} + +h() +{ + echo "Available commands:" + echo "${!commands[@]}" +} + +declare -A commands + +commands['callExt-post']=callExt_post +commands['help']=h + +cmd="$1" +shift +[ -n "$cmd" ] || cmd=help +if [ "${#commands[$cmd]}" -gt 0 ]; then + ${commands[$cmd]} "$@" +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20240514.56dc89c/rpm-script new/sdbootutil-1+git20240704.a2c5a26/rpm-script --- old/sdbootutil-1+git20240514.56dc89c/rpm-script 2024-05-14 14:11:26.000000000 +0200 +++ new/sdbootutil-1+git20240704.a2c5a26/rpm-script 1970-01-01 01:00:00.000000000 +0100 @@ -1,106 +0,0 @@ -#!/bin/sh - -op=${0##*-} - -name="" -version="" -release="" -kernelrelease="" -flavor="" -variant="" -usrmerged="0" -image="" -certs="" - -while true ; do - case $1 in - --name) - name="$2" - shift - ;; - --version) - version="$2" - shift - ;; - --release) - release="$2" - shift - ;; - - --kernelrelease) - kernelrelease="$2" - shift - ;; - --flavor) - flavor="$2" - shift - ;; - --variant) - variant="$2" - shift - ;; - - --usrmerged) - # legacy - shift - ;; - --image) - image="$2" - shift - ;; - --certs) - certs="$2" - shift - ;; - - *) break - ;; - esac - shift -done - -[ -z "$KERNEL_PACKAGE_SCRIPT_DEBUG" ] || \ - echo "$op" name: "$name" version: "$version" release: "$release" \ - kernelrelease: "$kernelrelease" flavor: "$flavor" variant: "$variant" \ - usrmerged: "$usrmerged" image: "$image" certs: "$certs" -- "$@" >&2 - -script_rc=0 - -case $op in - pre) - [ -z "$certs" ] || /usr/lib/module-init-tools/kernel-scriptlets/cert-"$op" --ca-check 1 --certs "$certs" "$@" || script_rc=$? - ;; - post) - if [ ! -e /.buildenv ] ; then - /usr/sbin/depmod -a "$kernelrelease-$flavor" - if [ -z "$TRANSACTIONAL_UPDATE" ]; then - /usr/bin/sdbootutil --image="$image" add-kernel "$kernelrelease-$flavor" - # make sure to select the latest kernel - /usr/bin/sdbootutil set-default-snapshot - [ -e /usr/lib/systemd/system/purge-kernels.service ] && { :>/boot/do_purge_kernels || :; } - fi - fi - [ -z "$certs" ] || /usr/lib/module-init-tools/kernel-scriptlets/cert-"$op" --ca-check 1 --certs "$certs" "$@" || script_rc=$? - ;; - preun) - [ -z "$certs" ] || /usr/lib/module-init-tools/kernel-scriptlets/cert-"$op" --ca-check 1 --certs "$certs" "$@" || script_rc=$? - ;; - postun) - # can't check $1 as kernel is usually multiversion. So need to check if - # that particular kernel was actually removed from disk. - if [ ! -e /.buildenv ] && [ ! -e /lib/modules/"$kernelrelease-$flavor/$image" ] ; then - [ -z "$TRANSACTIONAL_UPDATE" ] && /usr/bin/sdbootutil --image="$image" remove-kernel "$kernelrelease-$flavor" - [ -z "$certs" ] || /usr/lib/module-init-tools/kernel-scriptlets/cert-"$op" --ca-check 1 --certs "$certs" "$@" - fi - ;; - posttrans) - ;; - *) - echo Unknown scriptlet "$op" >&2 - exit 255 - ;; -esac - -exit $script_rc - -# vim: set sts=4 sw=4 ts=8 noet: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20240514.56dc89c/sdbootutil new/sdbootutil-1+git20240704.a2c5a26/sdbootutil --- old/sdbootutil-1+git20240514.56dc89c/sdbootutil 2024-05-14 14:11:26.000000000 +0200 +++ new/sdbootutil-1+git20240704.a2c5a26/sdbootutil 2024-07-04 14:00:45.000000000 +0200 @@ -20,6 +20,7 @@ arg_no_variables= arg_no_reuse_initrd= arg_no_random_seed= +arg_ask_pin= have_snapshots= # for x in vmlinuz image vmlinux linux bzImage uImage Image zImage; do image= @@ -59,6 +60,7 @@ trap cleanup EXIT entryfile="$tmpdir/entries.json" +initialentryfile="$tmpdir/initial_entries.json" snapperfile="$tmpdir/snapper.json" tmpfile="$tmpdir/tmp" @@ -74,6 +76,7 @@ --entry-keys Comma separated list of keys --no-variables Do not update UEFI variables --no-reuse-initrd Always regenerate initrd + --ask-pin Ask recovery PIN for re-enrollment -v, --verbose More verbose output -h, --help This screen @@ -137,8 +140,9 @@ snapshots Open snapshots menu entries Open entry menu - Vairables: + Variables: SYSTEMD_COLORS Set 0 to disable colored output + PIN Recovery PIN / password (re-enrollment) EOF exit 0 } @@ -228,13 +232,15 @@ } # Given the number of total item pairs, outputs the number of items to display at once -menuheight() { +menuheight() +{ local height=$(($1 / 2)) [ "$height" -le "$dh_menu" ] || height="$dh_menu" echo "$height" } -stty_size() { +stty_size() +{ # shellcheck disable=SC2046 set -- $(stty size 2>/dev/null) LINES="$1" @@ -252,7 +258,9 @@ # check whether it's a transactional system is_transactional() { - [ "$(stat -f -c %T /etc)" = "overlayfs" ] + # For running systems we can have this tests instead: + # [ "$(stat -f -c %T /etc)" = "overlayfs" ] + grep -q "^overlay /etc" /etc/fstab } subvol_is_ro() @@ -265,7 +273,8 @@ return 1 } -detect_parent() { +detect_parent() +{ local subvol="$1" [ -n "$have_snapshots" ] || return 0 parent_uuid="$(btrfs subvol show "${subvol#"${subvol_prefix}"}" | sed -ne 's/\s*Parent UUID:\s*//p')" @@ -316,7 +325,10 @@ update_entries_for_subvol() { local subvol="$1" - update_entries jq "[.[]|select(has(\"options\"))|select(.options|match(\"root=UUID=$root_uuid .*rootflags=subvol=$subvol\"))]" + local ext="${2:-}" + + [ -z "$ext" ] || ext="|$ext" + update_entries jq "[.[]|select(has(\"options\"))|select(.options|test(\"root=UUID=$root_uuid .*rootflags=subvol=$subvol\")$ext)]" } update_entries_for_snapshot() @@ -325,15 +337,48 @@ update_entries_for_subvol "${subvol_prefix}/.snapshots/$n/snapshot" } +update_entries_for_snapshot_invert() +{ + local n="$1" + update_entries_for_subvol "${subvol_prefix}/.snapshots/$n/snapshot" "not" +} + update_entries_for_this_system() { - update_entries jq "[.[]|select(has(\"options\"))|select(.options|match(\"root=UUID=$root_uuid\"))]" + update_entries jq "[.[]|select(has(\"options\"))|select(.options|test(\"root=UUID=$root_uuid\"))]" +} + +entry_conf_file() +{ + local kernel_version="${1:?}" + local snapshot="$2" + local tries="$3" + + # GRUB2 with the BLS patches does not follow the expected + # ordering rules, using only rpmvercmp() with the entry + # filename. To provide an order we add a prefix ("system") + # for entries that are not RO, making it newer that any other + # entry name that start with the "snapper" prefix: + # ("system" > "snapper"). + local prefix="" + local subvol="" + [ -z "$have_snapshots" ] || subvol="${subvol_prefix}/.snapshots/${snapshot}/snapshot" + if ! is_transactional && is_grub2; then + if ! subvol_is_ro "$subvol"; then + prefix="system" + else + prefix="snapper" + fi + fi + + echo "${prefix:+$prefix-}$entry_token-$kernel_version${snapshot:+-$snapshot}${tries:++$tries}.conf" } -find_conf_file() { +find_conf_file() +{ local kernel_version="${1:?}" local snapshot="$2" - local id="$entry_token-$kernel_version${snapshot:+-$snapshot}.conf" + local id="$(entry_conf_file "$kernel_version" "$snapshot")" update_entries_for_snapshot "$snapshot" @@ -393,7 +438,7 @@ local kernel_version="$2" [ -n "$kernel_version" ] || err "Missing kernel version" settle_entry_token "${snapshot}" - local id="$entry_token-$kernel_version${snapshot:+-$snapshot}.conf" + local id="$(entry_conf_file "$kernel_version" "$snapshot")" run_command_output bootctl unlink "$id" # This action will require to update the PCR predictions @@ -489,7 +534,8 @@ done } -reuse_initrd() { +reuse_initrd() +{ local snapshot="$1" local subvol="$2" local kernel_version="${3:?}" @@ -560,6 +606,60 @@ [ -n "$os_release_VERSION" ] || title="$title $os_release_VERSION_ID" } +pending_kernel_size() +{ + echo $(($(stat -c %s "$1") / 1024 + 1)) +} + +pending_initrds_size() +{ + local size=0 + local i=0 + while [ -e "$1/initrd-$i" ]; do + size=$((size + $(stat -c %s "$1/initrd-$i"))) + ((++i)) + done + echo $((size / 1024 + 1)) +} + +boot_free_space() +{ + echo $(($(findmnt -n -b -o AVAIL --target "$boot_root") / 1024)) +} + +select_entries_for_free_space() +{ + local snapshot="$1" + + update_entries_for_snapshot_invert "$(regex_entries_ids_for_prediction "$snapshot")" +} + +make_free_space() +{ + local snapshot="$1" + + # Calculate the free space and the required size. All sizes + # are in Kb to avoid big numbers + local free_space total_size + total_size=$(($(pending_kernel_size "$src") + $(pending_initrds_size "$tmpdir"))) + + select_entries_for_free_space "$snapshot" + + local id + while read -r id; do + free_space="$(boot_free_space)" + if [ "$total_size" -gt "$free_space" ]; then + log_info "Removing boot entry $id" + bootctl unlink "$id" + else + return 0 + fi + done < <(jq -r 'reverse|.[]|.id' < "$entryfile") + + free_space="$(boot_free_space)" + [ "$total_size" -lt "$free_space" ] +} + install_kernel() { local snapshot="$1" @@ -609,6 +709,8 @@ is_transactional && umount_etc "${snapshot_dir}" fi + make_free_space "$snapshot" || err "No free space in $boot_root for new kernel" + local boot_options= for i in /etc/kernel/cmdline /usr/lib/kernel/cmdline /proc/cmdline; do [ -f "$i" ] || continue @@ -676,7 +778,7 @@ tries= fi - loader_entry="$boot_root/loader/entries/$entry_token-$kernel_version${snapshot:+-$snapshot}${tries:++$tries}.conf" + loader_entry="$boot_root/loader/entries/$(entry_conf_file "$kernel_version" "$snapshot" "$tries")" install_with_rollback "$tmpdir/entry.conf" "$loader_entry" || failed="bootloader entry" rm -f "$tmpdir/entry.conf" fi @@ -766,7 +868,7 @@ local kernel_version="$2" [ -n "$kernel_version" ] || err "Missing kernel version" settle_entry_token "${snapshot}" - local id="$entry_token-$kernel_version${snapshot:+-$snapshot}.conf" + local id="$(entry_conf_file "$kernel_version" "$snapshot")" local conf conf="$(find_conf_file "${kernel_version}" "${snapshot}")" @@ -905,7 +1007,7 @@ list_snapshots() { - [ -n "$have_snapshots" ] || { log_info "System does no support snapshots."; return 0; } + [ -n "$have_snapshots" ] || { log_info "System does not support snapshots."; return 0; } update_snapper 2>"$tmpfile" || err "$(cat "$tmpfile")" local n=0 @@ -923,7 +1025,7 @@ show_snapper() { - [ -n "$have_snapshots" ] || { log_info "System does no support snapshots."; return 0; } + [ -n "$have_snapshots" ] || { log_info "System does not support snapshots."; return 0; } if ! update_snapper 2>"$tmpfile"; then d --title "Error" --textbox "$tmpfile" 0 0 exit 1 @@ -975,7 +1077,8 @@ done } -calc_chksum() { +calc_chksum() +{ # shellcheck disable=SC2046 set -- $(sha1sum "$1") chksum="$1" @@ -1118,11 +1221,11 @@ case "$action" in entries) - update_entries jq "[.[]|select(has(\"linux\"))|select(.linux|match(\"${kernelfiles[$n]}\"))]" + update_entries jq "[.[]|select(has(\"linux\"))|select(.linux|test(\"${kernelfiles[$n]}\"))]" show_entries "Entries for kernel ${kernelfiles[$n]#/*/}" ;; show) - show_entry ".[]|select(.id|match(\"$id\"))" + show_entry ".[]|select(.id|test(\"$id\"))" break # might have selected delete so refresh ;; install) @@ -1279,6 +1382,9 @@ # * rsync the theme in /boot/efi # * grub memdisk, removing unused modules (fs, # crypto, LVM, RAID) + # + # NOTE: if this file change, update the linearized + # version in pcrlock_grub2_exec_cmdline [ -e "$boot_root$boot_dst/grub.cfg" ] || cat > "$boot_root$boot_dst/grub.cfg" <<-EOF timeout=8 function load_video { @@ -1358,7 +1464,7 @@ set_default_snapshot() { - [ -n "$have_snapshots" ] || { log_info "System does no support snapshots."; return 0; } + [ -n "$have_snapshots" ] || { log_info "System does not support snapshots."; return 0; } local num="${1:?}" local configs update_entries_for_snapshot "$num" @@ -1377,30 +1483,35 @@ set_default_entry "${configs[0]}" } -# TODO: Maybe share this code outside -have_pcrlock() { +have_pcrlock() +{ [ -e /usr/lib/systemd/systemd-pcrlock ] } -pcrlock() { +pcrlock() +{ SYSTEMD_LOG_LEVEL="${SYSTEMD_LOG_LEVEL:-warning}" /usr/lib/systemd/systemd-pcrlock "$@" } -# TODO: Maybe share this code outside -is_pcr_oracle() { +is_pcr_oracle() +{ [ -e /etc/systemd/tpm2-pcr-public-key.pem ] && \ [ -e /etc/systemd/tpm2-pcr-private-key.pem ] && \ [ -e /usr/bin/pcr-oracle ] } -# TODO: Maybe share this code outside -select_entries_for_prediction() +regex_entries_ids_for_prediction() { + local snapshot="$1" + # Get the numbers for the last three snapshots [ -s "$snapperfile" ] || update_snapper - # Select the default and the active snapshots + # Select the default and the active snapshots. Also include + # one extra snapshot if is passed as a parameter, that refers + # the snapshot from where we are installing the kernel declare -A snapshots + [ -z "$snapshot" ] || snapshots["$snapshot"]=1 local id while read -r id; do snapshots[$id]=1 @@ -1412,9 +1523,14 @@ for id in $LAST_WORKING_SNAPSHOTS; do snapshots[$id]=1 done + else + while read -r id; do + if [ "${#snaphosts[@]}" -lt 3 ]; then + snapshots[$id]=1 + fi + done < <(jq -r '.root|sort_by(.date)[-2:]|.[]|.number' "$snapperfile") fi - log_info "Creating predictions for snapshots: ${!snapshots[*]}" local re if [ "${#snapshots[@]}" = 1 ]; then re="${!snapshots[*]}" @@ -1422,12 +1538,23 @@ IFS='|' eval re='"(:?${!snapshots[*]})"' fi - update_entries_for_snapshot "$re" + echo "$re" +} + +select_entries_for_prediction() +{ + update_entries_for_snapshot "$(regex_entries_ids_for_prediction)" } +backup_initial_components() +{ + select_entries_for_prediction + mv "$entryfile" "$initialentryfile" + cp -a "$boot_root/." "$tmpdir" +} -# TODO: Maybe share this code outside -pcrlock_manual_initrd() { +pcrlock_manual_raw() +{ local pcr="$1" local pcrlock="$2" local initrd="$3" @@ -1445,8 +1572,8 @@ echo ']}]}' >> "$pcrlock" } -# TODO: Maybe share this code outside -pcrlock_cmdline_initrd() { +pcrlock_sdboot_cmdline_initrd() +{ local cmdline="$1" local initrd="$2" local suffix="$3" @@ -1461,7 +1588,7 @@ pcrlock \ lock-kernel-initrd \ --pcrlock="$tmpdir/initrd.pcrlock" \ - "${boot_root}/$initrd" 2> /dev/null || pcrlock_manual_initrd 9 "$tmpdir/initrd.pcrlock" "${boot_root}/$initrd" + "$initrd" 2> /dev/null || pcrlock_manual_raw 9 "$tmpdir/initrd.pcrlock" "$initrd" jq --slurp '{"records": [.[].records[0]]}' \ "$tmpdir/cmdline.pcrlock" \ "$tmpdir/initrd.pcrlock" \ @@ -1482,46 +1609,101 @@ rm "$tmpdir/cmdline.utf16" } -# TODO: Maybe share this code outside -generate_tpm2_predictions_pcrlock() +pcrlock_grub2_kernel_initrd() { - local pcrs="$1" + local linux="$1" + local initrd="$2" + local suffix="$3" - # Select the affected entries - select_entries_for_prediction + local elements=( "$linux" "$initrd" ) + local locks=() + local n=0 + for element in "${elements[@]}"; do + n=$((n+1)) + pcrlock \ + lock-raw \ + --pcr=9 \ + --pcrlock "$tmpdir/element-$n.pcrlock" \ + "$element" 2> /dev/null || pcrlock_manual_raw 9 "$tmpdir/element-$n.pcrlock" "$element" + locks+=( "$tmpdir/element-$n.pcrlock" ) + done + jq --slurp '{"records": [.[].records[0]]}' \ + ${locks[@]} \ + > "/var/lib/pcrlock.d/710-grub2-kernel-initrd-entry.pcrlock.d/kernel-initrd-$suffix.pcrlock" + rm ${locks[@]} +} - # Remove all the generated measurements. This will keep the - # predictions at minimum and decrease the combinations - rm -fr /var/lib/pcrlock.d/* +pcrlock_grub2_exec_cmdline() +{ + local linux="$1" + local cmdline="$2" + local initrd="$3" + local suffix="$4" + # Serialization of the executed lines. It depends on the + # config file and the hard-coded commands generated for each + # bls entry (like the call to load_video or loading gzio). + local lines=("timeout=8" + "insmod bli" + "blscfg" + "load_video" + "true" + "set gfxpayload=keep" + "insmod gzio") + lines+=( "$linux" "$cmdline" "$initrd" ) - pcrlock lock-firmware-code - pcrlock lock-firmware-config - # If secure boot is disabled, this can fail. There is patch - # for the policy generation, and for the authority is planned - /usr/lib/systemd/systemd-pcrlock lock-secureboot-policy || true - /usr/lib/systemd/systemd-pcrlock lock-secureboot-authority || true - # uses / by default - pcrlock lock-gpt + local locks=() + local n=0 + for line in "${lines[@]}"; do + n=$((n+1)) + echo -n "$line" > "$tmpdir/line" + pcrlock \ + lock-raw \ + --pcr=8 \ + --pcrlock "$tmpdir/line-$n.pcrlock" \ + "$tmpdir/line" + locks+=( "$tmpdir/line-$n.pcrlock" ) + rm "$tmpdir/line" + done + jq --slurp '{"records": [.[].records[0]]}' \ + ${locks[@]} \ + > "/var/lib/pcrlock.d/650-grub2-entry-exec-cmdline.pcrlock.d/exec-cmdline-$suffix.pcrlock" + rm ${locks[@]} +} - # 630-shim-efi-application is not part of the pcrlock standards - # TODO: move to shim-pcrlock.rpm - pcrlock \ - lock-pe \ - --pcrlock=/var/lib/pcrlock.d/630-shim-efi-application.pcrlock.d/generated.pcrlock \ - "${boot_root}${boot_dst}/shim.efi" +pcrlock_grub2_entry_files() +{ + local entries="${1:-$entryfile}" + local suffix="${2:+-$2}" + local base="${3}" + local locks=() + local n=0 + while read -r i; do + n=$((n+1)) + if [ -n "$base" ]; then + i="${i#/boot/efi}" + i="$base$i" + fi + pcrlock \ + lock-raw \ + --pcr=9 \ + --pcrlock="$tmpdir/entry-$n.pcrlock" \ + "$i" + locks+=( "$tmpdir/entry-$n.pcrlock" ) + done < <(jq --raw-output 'map(.path) | .[]' "$entries") - # 640-boot-loader-efi-application is not part of the pcrlock - # standards - # This is measuing the systemd-boot EFI binary (named grub.efi) - # TODO: move to systemd-boot-pcrlock.rpm - pcrlock \ - lock-pe \ - --pcrlock=/var/lib/pcrlock.d/640-boot-loader-efi-application.pcrlock.d/generated.pcrlock \ - "${boot_root}${boot_dst}/grub.efi" + jq --slurp '{"records": [.[].records[0]]}' \ + ${locks[@]} \ + > "/var/lib/pcrlock.d/643-grub2-entry-files.pcrlock.d/generated$suffix.pcrlock" + rm ${locks[@]} +} - if [ -e "$boot_root/loader/loader.conf" ]; then +pcrlock_sdboot() +{ + # 641-sdboot-loader-conf.pcrlock is not part of the pcrlock + # standards + if [ -e "{$boot_root}/loader/loader.conf" ]; then pcrlock \ - lock-raw /boot/efi/loader/loader.conf \ + lock-raw "{$boot_root}/loader/loader.conf" \ --pcr=5 \ --pcrlock=/var/lib/pcrlock.d/641-sdboot-loader-conf.pcrlock fi @@ -1544,29 +1726,188 @@ while read -r cmdline; do read -r initrd n=$((n+1)) - pcrlock_cmdline_initrd "initrd=$cmdline" "$initrd" "$n" - done < <(jq --raw-output '.[] | ([(.initrd[0] | sub("/"; "\\"; "g")), .options] | join(" ")), .initrd[0]' "$entryfile") - + pcrlock_sdboot_cmdline_initrd "initrd=$cmdline" "${boot_root}$initrd" "$n" + done < <(jq --raw-output '.[] | ([(.initrd[0] | sub("/"; "\\"; "g")), .options] | join(" ")), .initrd[0]' "$entryfile" +) # Generate variation for 710-kernel-cmdline-initrd-entry # component that contains the current cmdline and the current # initrd, even if this will never be used again. This is # required because disk-encryption-tool generates a new initrd # during the first boot, making the event log impossible to # align for systemd-pcrlock - if [ "$SDB_ADD_INITIAL_CMDLINE" = "1" ]; then - read -r cmdline < /proc/cmdline - local initrd="${cmdline#*initrd=}"; initrd="${initrd%% *}"; initrd="${initrd//\\//}" - pcrlock_cmdline_initrd "$cmdline" "$initrd" "0" || warn "Not all PCRs are registered in the policy" + if [ "$SDB_ADD_INITIAL_COMPONENT" = "1" ]; then + while read -r cmdline; do + read -r initrd + pcrlock_sdboot_cmdline_initrd "initrd=$cmdline" "${tmpdir}$initrd" "0" + done < <(jq --raw-output '.[] | ([(.initrd[0] | sub("/"; "\\"; "g")), .options] | join(" ")), .initrd[0]' "$initialentryfile") + fi +} + +pcrlock_grub2() +{ + # 641-grub2-grub-cfg.pcrlock is not part of the pcrlock + # standards + if [ -e "${boot_root}${boot_dst}/grub.cfg" ]; then + pcrlock \ + lock-raw "${boot_root}${boot_dst}/grub.cfg" \ + --pcr=9 \ + --pcrlock=/var/lib/pcrlock.d/641-grub2-grub-cfg.pcrlock + fi + + # 642-grub2-bli-mod.pcrlock is not part of the pcrlock + # standards + pcrlock \ + lock-raw "${boot_root}${boot_dst}/$(uname -m)-efi/bli.mod" \ + --pcr=9 \ + --pcrlock=/var/lib/pcrlock.d/642-grub2-bli-mod.pcrlock + + # 643-grub2-entry-files.pcrlock is not part of the pcrlock + # standards + mkdir -p /var/lib/pcrlock.d/643-grub2-entry-files.pcrlock.d + pcrlock_grub2_entry_files + if [ "$SDB_ADD_INITIAL_COMPONENT" = "1" ]; then + pcrlock_grub2_entry_files "$initialentryfile" "0" "$tmpdir" fi - pcrlock --pcr="$pcrs" make-policy + blkpart="$(findmnt -nvo SOURCE "$boot_root")" + read -r partno < "/sys/class/block/${blkpart##*/}"/partition + # Once we are out of the BIOS / EFI, the numeration cannot be + # done without device.map. It is safe to assume that the ESP + # is always the first disk (hd0) + grub_drive="(hd0,gpt$partno)" + + # Join all the executed lines, and the cmdline in a single + # pcrlock file + mkdir -p /var/lib/pcrlock.d/650-grub2-entry-exec-cmdline.pcrlock.d + n=0 + while read -r options; do + read -r kernel + read -r initrd + n=$((n+1)) + pcrlock_grub2_exec_cmdline "linux ${grub_drive}$kernel $options" \ + "${grub_drive}$kernel $options" \ + "initrd ${grub_drive}$initrd" "$n" + done < <(jq --raw-output '.[] | .options, .linux, .initrd[0]' "$entryfile") + + # Generate variation for 650-grub2-entry-exec-cmdline + # component that contains the current cmdline and the current + # initrd, even if this will never be used again. This is + # required because disk-encryption-tool generates a new initrd + # during the first boot, making the event log impossible to + # align for systemd-pcrlock + if [ "$SDB_ADD_INITIAL_COMPONENT" = "1" ]; then + while read -r options; do + read -r kernel + read -r initrd + pcrlock_grub2_exec_cmdline "linux ${grub_drive}$kernel $options" \ + "${grub_drive}$kernel $options" \ + "initrd ${grub_drive}$initrd" "0" + done < <(jq --raw-output '.[] | .options, .linux, .initrd[0]' "$initialentryfile") + fi + + # Join the kernel and the initrd in a single component + mkdir -p /var/lib/pcrlock.d/710-grub2-kernel-initrd-entry.pcrlock.d + n=0 + while read -r kernel; do + read -r initrd + n=$((n+1)) + pcrlock_grub2_kernel_initrd "$boot_root$kernel" "$boot_root$initrd" "$n" + done < <(jq --raw-output '.[] | .linux, .initrd[0]' "$entryfile") + + # Generate variation for 710-grub2-kernel-initrd-entry for the + # same reason than before. + if [ "$SDB_ADD_INITIAL_COMPONENT" = "1" ]; then + while read -r kernel; do + read -r initrd + pcrlock_grub2_kernel_initrd "$tmpdir$kernel" "$tmpdir$initrd" "0" + done < <(jq --raw-output '.[] | .linux, .initrd[0]' "$initialentryfile") + fi +} + +generate_tpm2_predictions_pcrlock() +{ + local pcrs="$1" + + # Select the affected entries + select_entries_for_prediction + + # Remove older (1 week) generated measurements. This will + # keep the predictions at minimum and decrease the + # combinations. Removing all can be a problem in certain + # conditions. For example, after the first boot some pcrlock + # files contain hashes for the original ESP assets, that are + # required for the event log aligment. + [ ! -d /var/lib/pcrlock.d ] || find /var/lib/pcrlock.d -name '*.pcrlock' -type f -mtime +7 -delete + + pcrlock lock-firmware-code + pcrlock lock-firmware-config + # If secure boot is disabled, this can fail. There is patch + # for the policy generation, and for the authority is planned + /usr/lib/systemd/systemd-pcrlock lock-secureboot-policy &> /dev/null || true + /usr/lib/systemd/systemd-pcrlock lock-secureboot-authority &> /dev/null || true + # uses / by default + pcrlock lock-gpt + + # 630-shim-efi-application is not part of the pcrlock standards + # TODO: move to shim-pcrlock.rpm + pcrlock \ + lock-pe \ + --pcrlock=/var/lib/pcrlock.d/630-shim-efi-application.pcrlock.d/generated.pcrlock \ + "${boot_root}${boot_dst}/shim.efi" + + # 640-boot-loader-efi-application is not part of the pcrlock + # standards + # This is measuing the systemd-boot EFI binary (named grub.efi) + # TODO: move to systemd-boot-pcrlock.rpm + pcrlock \ + lock-pe \ + --pcrlock=/var/lib/pcrlock.d/640-boot-loader-efi-application.pcrlock.d/generated.pcrlock \ + "${boot_root}${boot_dst}/grub.efi" + + if is_sdboot; then + pcrlock_sdboot + elif is_grub2; then + pcrlock_grub2 + fi + + # If the prediction fails, the system will ask for a password, + # but we can do a re-enrollment using the recovery PIN. To + # register a recovery PIN disk-encryption-tool will call this + # script deploying in the @u keyring a "cryptsetup" entry. + # For re-enrollments we can use the same entry, the PIN + # environment variable, or the --ask-pin parameter. + local pin + local extra=() + local keyid="$(keyctl id %user:cryptenroll 2> /dev/null)" || true + if [ -n "$keyid" ]; then + pin="$(keyctl pipe "$keyid")" + extra=("--recovery-pin=yes") + elif [ -n "$PIN" ]; then + pin="$PIN" + extra=("--recovery-pin=yes") + elif [ -n "$arg_ask_pin" ]; then + read -s -p "Recovery PIN: " pin + extra=("--recovery-pin=yes") + fi + + PIN="$pin" pcrlock --pcr="$pcrs" "${extra[@]}" make-policy || { + echo "Error creating the policy!" + if [ -z "$pin" ]; then + echo "Please, provide the recovery PIN to register the new policy" + else + echo "Provided PIN incorrect or TPM2 locked after too many retries" + fi + } # Publish the assets in the ESP, so can be imported by # dracut-pcr-signature - [ -e /var/lib/systemd/pcrlock.json ] && cp /var/lib/systemd/pcrlock.json "${boot_root}${boot_dst}" + [ -e /var/lib/systemd/pcrlock.json ] && cp /var/lib/systemd/pcrlock.json "${boot_root}${boot_dst}" && { + echo "NVIndex policy created" + } } -get_pcrs() { +get_pcrs() +{ local pcrs local jq_pcr='.tokens[]|select(.type == "systemd-tpm2")|."tpm2_pubkey_pcrs"|join(",")' # We can have multiple devices, each one of them with @@ -1577,7 +1918,6 @@ done <<<$(blkid -t TYPE=crypto_LUKS -o device) } -# TODO: Maybe share this code outside generate_tpm2_predictions_pcr_oracle() { local entry @@ -1621,11 +1961,11 @@ # Publish the assets in the ESP, so can be imported by # dracut-pcr-signature cp /etc/systemd/tpm2-pcr-public-key.pem "${boot_root}${boot_dst}" - [ -e /etc/systemd/tpm2-pcr-signature.json ] && cp /etc/systemd/tpm2-pcr-signature.json "${boot_root}${boot_dst}" + [ -e /etc/systemd/tpm2-pcr-signature.json ] && cp /etc/systemd/tpm2-pcr-signature.json "${boot_root}${boot_dst}" && { + echo "Signed policy created" + } } - -# TODO: Maybe share this code outside generate_tpm2_predictions() { [ -e /etc/crypttab ] || return 0 @@ -1634,7 +1974,7 @@ if is_pcr_oracle; then generate_tpm2_predictions_pcr_oracle elif have_pcrlock; then - [ -e /etc/sysconfig/fde-tools ] || return 0 + [ -e /etc/sysconfig/fde-tools ] || { log_info "/etc/sysconfig/fde-tools not found. System not enrolled"; return 0; } # shellcheck disable=SC1091 . /etc/sysconfig/fde-tools @@ -1671,7 +2011,7 @@ ####### main ####### -getopttmp=$(getopt -o hc:v --long help,flicker,verbose,esp-path:,entry-token:,arch:,image:,entry-keys:,no-variables,no-reuse-initrd,no-random-seed,all -n "${0##*/}" -- "$@") +getopttmp=$(getopt -o hc:v --long help,flicker,verbose,esp-path:,entry-token:,arch:,image:,entry-keys:,no-variables,no-reuse-initrd,no-random-seed,ask-pin,all -n "${0##*/}" -- "$@") eval set -- "$getopttmp" while true ; do @@ -1687,6 +2027,7 @@ --no-variables) arg_no_variables=1; shift ;; --no-reuse-initrd) arg_no_reuse_initrd=1; shift ;; --no-random-seed) arg_no_random_seed=1; shift ;; + --ask-pin) arg_ask_pin=1; shift ;; --all) arg_all_entries=1; shift ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; @@ -1751,6 +2092,12 @@ err "Bootloader not detected" fi +# Keep initial components before they are replaced by some actions +# (new initrd, new entry, etc) +if [ "$SDB_ADD_INITIAL_COMPONENT" = "1" ]; then + backup_initial_components +fi + if [ "$1" = "install" ]; then install_bootloader "${2:-$root_snapshot}" elif [ "$1" = "needs-update" ]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sdbootutil-1+git20240514.56dc89c/sdbootutil.spec new/sdbootutil-1+git20240704.a2c5a26/sdbootutil.spec --- old/sdbootutil-1+git20240514.56dc89c/sdbootutil.spec 2024-05-14 14:11:26.000000000 +0200 +++ new/sdbootutil-1+git20240704.a2c5a26/sdbootutil.spec 2024-07-04 14:00:45.000000000 +0200 @@ -44,6 +44,7 @@ Requires: dracut-pcr-signature Supplements: (systemd-boot and shim) Requires: (%{name}-snapper if (snapper and btrfsprogs)) +Requires: (%{name}-tukit if read-only-root-fs) ExclusiveArch: aarch64 ppc64le riscv64 x86_64 %description @@ -59,19 +60,14 @@ %description snapper Plugin scripts for snapper to handle BLS config files -%package rpm-scriptlets -Summary: Scripts to create boot entries on kernel updates +%package tukit +Summary: plugin script for tukit +Requires: %{name} = %{version} Requires: sdbootutil >= %{version}-%{release} -# make sure to not replace scriptlets with nops on systems that -# use grub2 -Conflicts: grub2 -Conflicts: suse-kernel-rpm-scriptlets -Provides: suse-kernel-rpm-scriptlets -Obsoletes: %{name}-filetriggers < %{version} - -%description rpm-scriptlets -Scriptlets that call sdbootutil to create boot entries when -kernels are installed or removed +Requires: tukit + +%description tukit +Plugin scripts for tukit to handle BLS config files %package kernel-install Summary: Hook script for kernel-install @@ -95,25 +91,18 @@ install -D -m 644 "$i" %{buildroot}%{_unitdir}/"$i" done -mkdir -p %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets -for a in rpm; do - install -m 755 "$a-script" %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets - for b in post posttrans postun pre preun; do - ln -s "$a-script" %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets/$a-$b - done -done -for a in cert inkmp kmp; do - for b in post posttrans postun pre preun; do - ln -s /bin/true %{buildroot}%{_prefix}/lib/module-init-tools/kernel-scriptlets/$a-$b - done -done - # snapper install -d -m755 %{buildroot}%{_prefix}/lib/snapper/plugins for i in 10-sdbootutil.snapper; do install -m 755 $i %{buildroot}%{_prefix}/lib/snapper/plugins/$i done +# tukit +install -d -m755 %{buildroot}%{_prefix}/lib/tukit/plugins +for i in 10-sdbootutil.tukit; do + install -m 755 $i %{buildroot}%{_prefix}/lib/tukit/plugins/$i +done + # kernel-install install -d -m755 %{buildroot}%{_prefix}/lib/kernel/install.d for i in 50-sdbootutil.install; do @@ -143,15 +132,16 @@ %{_bindir}/sdbootutil %{_unitdir}/sdbootutil-update-predictions.service -%files rpm-scriptlets -%dir %{_prefix}/lib/module-init-tools -%{_prefix}/lib/module-init-tools/* - %files snapper %dir %{_prefix}/lib/snapper %dir %{_prefix}/lib/snapper/plugins %{_prefix}/lib/snapper/plugins/* +%files tukit +%dir %{_prefix}/lib/tukit +%dir %{_prefix}/lib/tukit/plugins +%{_prefix}/lib/tukit/plugins/* + %files kernel-install %dir %{_prefix}/lib/kernel %dir %{_prefix}/lib/kernel/install.d ++++++ sdbootutil.obsinfo ++++++ --- /var/tmp/diff_new_pack.MHPg7U/_old 2024-07-17 15:14:33.152756422 +0200 +++ /var/tmp/diff_new_pack.MHPg7U/_new 2024-07-17 15:14:33.152756422 +0200 @@ -1,5 +1,5 @@ name: sdbootutil -version: 1+git20240514.56dc89c -mtime: 1715688686 -commit: 56dc89ccb5823154450c9164d1b8f3e256709284 +version: 1+git20240704.a2c5a26 +mtime: 1720094445 +commit: a2c5a26866076afd91446dea57a44ac91746a4bf
