From 5822cd01865e977c2d343f49513f6ac621ad007f Mon Sep 17 00:00:00 2001 From: Glenn Washburn Date: Fri, 27 Feb 2026 13:49:26 -0600 Subject: [PATCH 1/2] dom0-update: In download mode, only send specifically requested packages to dom0 Save output of the package manager command. Then, if called with an action that downloads packages, parse out the requested packages and only send those to dom0. Fallback to the old method if --clean was specified. This fixes an issue where packages could be installed that were not intended or where packages could not be installed due to missing dependencies from packages not explicitly requested by the user. Fixes QubesOS/qubes-issues#10716 --- .../qubes-download-dom0-updates.sh | 67 +++++++++++++++++-- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/package-managers/qubes-download-dom0-updates.sh b/package-managers/qubes-download-dom0-updates.sh index ff860d18..83acd9ab 100755 --- a/package-managers/qubes-download-dom0-updates.sh +++ b/package-managers/qubes-download-dom0-updates.sh @@ -168,16 +168,68 @@ if [ "$UPDATE_ACTION" = "download" ]; then fi set -e +set -o pipefail -"${UPDATE_COMMAND[@]}" "${OPTS[@]}" "${PKGLIST[@]}" +"${UPDATE_COMMAND[@]}" "${OPTS[@]}" "${PKGLIST[@]}" | \ + tee "$DOM0_UPDATES_DIR/download.out" +# Collect rpms from various download locations into one directory find "$DOM0_UPDATES_DIR/var/cache" -name '*.rpm' -print0 2>/dev/null |\ xargs -0 -r ln -f -t "$DOM0_UPDATES_DIR/packages/" -if ls "$DOM0_UPDATES_DIR"/packages/*.rpm > /dev/null 2>&1; then +case "$UPDATE_ACTION" in + # Never send package to dom0 for the following commands. This by no + # means is an exhaustive list, just some common ones. + changelog|list|search) ;; + # TODO: Look for any other commands that download packages and add + # NOTE: For now, use the fallback for distro-sync because its output + # may have some untested corner cases. So being conservative. + downgrade|download|install|upgrade) + RPMS=$( + grep '^ ' "$DOM0_UPDATES_DIR/download.out" | + tail -n +2 | + while read -r PKG ARCH VER _REPO _SIZE; do + # Assumption: Package names do not contain spaces + F="$PKG-${VER##*:}.$ARCH.rpm" + if [ -f "$DOM0_UPDATES_DIR"/packages/"$F" ]; then + echo "$F" + else + # Did not find package that was supposed to be downloaded... bail + echo "Package $F requested but not downloaded" >&2 + exit 1 + fi + done + ) || RET=$? + if [ -z "$RPMS" ]; then + cat >&2 <&2 + fi + if [ "${RET:-0}" -ne 0 ] || [ "$CLEAN" = "1" ]; then + # An error occured in determining or finding requested packages + # or --clean was specified, unset RPM to fallback to old method. + RPMS= + fi + + ;& + # Fallback to previous implementation of uploading all verified rpms + # for all other actions and above failure condition. + *) + if [ -z "$RPMS" ]; then + RPMS=$(for P in "$DOM0_UPDATES_DIR"/packages/*.rpm; do echo "${P##*/}"; done) + fi + ;; +esac + +if [ -n "$RPMS" ]; then if [ -n "$SIGNATURE_REGEX" ]; then rpmkeys_error=0 - for pkg in "$DOM0_UPDATES_DIR"/packages/*.rpm; do + for rpmfile in $RPMS; do + pkg="$DOM0_UPDATES_DIR"/packages/"$rpmfile" rpmkeys_exit_code=0 output="$(rpmkeys --root "$DOM0_UPDATES_DIR" --checksig "$pkg")" \ || rpmkeys_exit_code="$?" @@ -185,7 +237,7 @@ if ls "$DOM0_UPDATES_DIR"/packages/*.rpm > /dev/null 2>&1; then echo "ERROR: could not verify $pkg" >&2 rpmkeys_error=1 rm "$pkg" - elif ! echo "$output" |grep -Pq "$SIGNATURE_REGEX"; then + elif ! echo "$output" | grep -Pq "$SIGNATURE_REGEX"; then echo "ERROR: missing or invalid signature for $pkg" >&2 rpmkeys_error=1 rm "$pkg" @@ -201,11 +253,14 @@ if ls "$DOM0_UPDATES_DIR"/packages/*.rpm > /dev/null 2>&1; then cmd="/usr/lib/qubes/qrexec-client-vm dom0 qubes.ReceiveUpdates /usr/lib/qubes/qfile-agent" qrexec_exit_code=0 - $cmd "$DOM0_UPDATES_DIR"/packages/*.rpm || { qrexec_exit_code=$? ; true; }; + rpmfiles=$(for rpmfile in $RPMS; do echo "$DOM0_UPDATES_DIR"/packages/"$rpmfile"; done) + # shellcheck disable=SC2086 + $cmd $rpmfiles || { qrexec_exit_code=$? ; true; }; if [ ! "$qrexec_exit_code" = "0" ]; then - echo "'$cmd $DOM0_UPDATES_DIR/packages/*.rpm' failed with exit code ${qrexec_exit_code}!" >&2 + echo "'$cmd $rpmfiles' failed with exit code ${qrexec_exit_code}!" >&2 exit "$qrexec_exit_code" fi else echo "No packages downloaded" >&2 fi +rm -f "$DOM0_UPDATES_DIR/download.out" From 62bfccd90c0a371f102dbb1e739d17acbd7df577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 22 Apr 2026 20:23:53 +0200 Subject: [PATCH 2/2] dom0-update: fix handling empty download list If there are no downloaded packages, do not assign literal "*.rpm" to the RPMS variable - the later part of the scripts would actually try to send a file with this name, and fail. --- package-managers/qubes-download-dom0-updates.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/package-managers/qubes-download-dom0-updates.sh b/package-managers/qubes-download-dom0-updates.sh index 83acd9ab..1143cb77 100755 --- a/package-managers/qubes-download-dom0-updates.sh +++ b/package-managers/qubes-download-dom0-updates.sh @@ -220,7 +220,13 @@ EOF # for all other actions and above failure condition. *) if [ -z "$RPMS" ]; then - RPMS=$(for P in "$DOM0_UPDATES_DIR"/packages/*.rpm; do echo "${P##*/}"; done) + RPMS=$( + for P in "$DOM0_UPDATES_DIR"/packages/*.rpm; do + if [ -e "$P" ]; then + echo "${P##*/}" + fi + done + ) fi ;; esac