From 5c20f338d6d39e95c77c4a852583c571bcd121ae Mon Sep 17 00:00:00 2001 From: Lubos Kocman Date: Tue, 19 May 2026 15:49:37 +0200 Subject: [PATCH 1/2] Prevent passing of a malicious command via DIALOGCMD env --- opensuse-migration-tool | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/opensuse-migration-tool b/opensuse-migration-tool index d8570e9..6f00f8e 100755 --- a/opensuse-migration-tool +++ b/opensuse-migration-tool @@ -63,9 +63,11 @@ for tool in "${REQUIRED_TOOLS[@]}"; do fi done -if [[ -n "${DIALOGCMD:-}" ]] && command -v "$DIALOGCMD" >/dev/null 2>&1; then - DIALOGCMD=$(command -v "$DIALOGCMD") -elif DIALOGCMD=$(command -v susedialog 2>/dev/null); then +# Only auto-detect susedialog or dialog, ignore untrusted DIALOGCMD env var from users +# This prevents privilege escalation via sudo DIALOGCMD injection +unset DIALOGCMD + +if DIALOGCMD=$(command -v susedialog 2>/dev/null); then : elif DIALOGCMD=$(command -v dialog 2>/dev/null); then : @@ -188,7 +190,9 @@ function check_x86_64_v2_support() { # Elevated permissions check unless DRYRUN is set if [ -z "${DRYRUN:-}" ]; then if [ "$EUID" -ne 0 ]; then - exec sudo DIALOGCMD="$DIALOGCMD" "$0" "$@" + # Re-run with sudo, let the elevated script re-detect DIALOGCMD + # This prevents environment variable injection attacks + exec sudo "$0" "$@" fi # Requires elevated permissions or test will always fail From b038142b612b14db122f502ae2b31072800eceb2 Mon Sep 17 00:00:00 2001 From: Lubos Kocman Date: Wed, 20 May 2026 10:06:30 +0200 Subject: [PATCH 2/2] Drop dialog and set dialogcmd after sudo --- opensuse-migration-tool | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/opensuse-migration-tool b/opensuse-migration-tool index 6f00f8e..a16f026 100755 --- a/opensuse-migration-tool +++ b/opensuse-migration-tool @@ -63,20 +63,6 @@ for tool in "${REQUIRED_TOOLS[@]}"; do fi done -# Only auto-detect susedialog or dialog, ignore untrusted DIALOGCMD env var from users -# This prevents privilege escalation via sudo DIALOGCMD injection -unset DIALOGCMD - -if DIALOGCMD=$(command -v susedialog 2>/dev/null); then - : -elif DIALOGCMD=$(command -v dialog 2>/dev/null); then - : -else - echo "Neither susedialog nor dialog is installed." - echo "Please run: sudo zypper install susedialog" - exit 1 -fi - # Ensure Bash version is 4.0+ if ((BASH_VERSINFO[0] < 4)); then echo "This script requires Bash 4.0 or higher." >&2 @@ -190,15 +176,30 @@ function check_x86_64_v2_support() { # Elevated permissions check unless DRYRUN is set if [ -z "${DRYRUN:-}" ]; then if [ "$EUID" -ne 0 ]; then - # Re-run with sudo, let the elevated script re-detect DIALOGCMD - # This prevents environment variable injection attacks - exec sudo "$0" "$@" + # Re-run with sudo in a clean environment. + # Keep only terminal-related vars needed by dialog. + exec sudo env -i \ + PATH="/usr/sbin:/usr/bin:/sbin:/bin" \ + TERM="${TERM:-linux}" \ + COLORTERM="${COLORTERM:-}" \ + "$0" "$@" fi # Requires elevated permissions or test will always fail test -w / || { echo "Please run the tool inside 'transactional-update shell' on Immutable systems."; exit 1; } fi +# Resolve susedialog only after privilege handling. +# This prevents using a value resolved in an unprivileged context in the elevated run. +unset DIALOGCMD +if DIALOGCMD=$(command -v susedialog 2>/dev/null); then + : +else + echo "susedialog is required but not installed." + echo "Please run: sudo zypper install susedialog" + exit 1 +fi + # System-specific options if [[ "$NAME" == "openSUSE Leap Micro" ]]; then