From a3498644fc4d324ed52ca879e1509e0ac55525fc Mon Sep 17 00:00:00 2001 From: MickLesk Date: Mon, 23 Mar 2026 21:22:58 +0100 Subject: [PATCH] fix: harden shell scripts against injection and insecure permissions Security fixes across multiple files: - install.func: Quote command substitutions in mkdir/systemctl to prevent word splitting and globbing on GETTY_OVERRIDE path - build.func: Escape sed special chars (& \) in current_os/hostname/ip before using them as sed replacement strings in update_motd_ip - build.func: Escape regex metacharacters (. |) in $LANG before sed use - build.func: Validate render_gid/video_gid as numeric before sed injection - build.func: Use HTTPS for Alpine APK repositories instead of HTTP - tools.func: Verify GPG dearmor output is non-empty (-s check) - tools.func: Tighten GPU device permissions from 666 to 660 (owner+group) - tools.func: Add chgrp render for /dev/kfd (AMD ROCm) - shinobi-install.sh: chmod 777 -> 644 on version.json - tasmoadmin-install.sh: chmod 777 -> 775 on tmp/data directories - runtipi.sh: chmod 666 -> 660 on settings.json --- install/shinobi-install.sh | 2 +- install/tasmoadmin-install.sh | 2 +- misc/build.func | 17 ++++++++++++++--- misc/install.func | 6 +++--- misc/tools.func | 9 +++++---- tools/addon/runtipi.sh | 2 +- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/install/shinobi-install.sh b/install/shinobi-install.sh index a5ffe1c94..383325016 100644 --- a/install/shinobi-install.sh +++ b/install/shinobi-install.sh @@ -35,7 +35,7 @@ cd Shinobi gitVersionNumber=$(git rev-parse HEAD) theDateRightNow=$(date) touch version.json -chmod 777 version.json +chmod 644 version.json echo '{"Product" : "'"Shinobi"'" , "Branch" : "'"master"'" , "Version" : "'"$gitVersionNumber"'" , "Date" : "'"$theDateRightNow"'" , "Repository" : "'"https://gitlab.com/Shinobi-Systems/Shinobi.git"'"}' >version.json msg_ok "Cloned Shinobi" diff --git a/install/tasmoadmin-install.sh b/install/tasmoadmin-install.sh index 2186e11b5..9f84f719b 100644 --- a/install/tasmoadmin-install.sh +++ b/install/tasmoadmin-install.sh @@ -23,7 +23,7 @@ fetch_and_deploy_gh_release "tasmoadmin" "TasmoAdmin/TasmoAdmin" "prebuild" "lat msg_info "Configuring TasmoAdmin" rm -rf /etc/php/8.4/apache2/conf.d/10-opcache.ini chown -R www-data:www-data /var/www/tasmoadmin -chmod 777 /var/www/tasmoadmin/tmp /var/www/tasmoadmin/data +chmod 775 /var/www/tasmoadmin/tmp /var/www/tasmoadmin/data cat </etc/apache2/sites-available/tasmoadmin.conf ServerName tasmoadmin diff --git a/misc/build.func b/misc/build.func index 10aac9927..b8483ca0d 100644 --- a/misc/build.func +++ b/misc/build.func @@ -221,6 +221,11 @@ update_motd_ip() { local current_hostname="$(hostname)" local current_ip="$(hostname -I | awk '{print $1}')" + # Escape sed special chars in replacement strings (& \ |) + current_os="${current_os//\\/\\\\}"; current_os="${current_os//&/\\&}" + current_hostname="${current_hostname//\\/\\\\}"; current_hostname="${current_hostname//&/\\&}" + current_ip="${current_ip//\\/\\\\}"; current_ip="${current_ip//&/\\&}" + # Update only if values actually changed if ! grep -q "OS:.*$current_os" "$PROFILE_FILE" 2>/dev/null; then sed -i "s|OS:.*|OS: \${GN}$current_os\${CL}\\\"|" "$PROFILE_FILE" @@ -4076,8 +4081,8 @@ EOF if [ "$var_os" == "alpine" ]; then sleep 3 pct exec "$CTID" -- /bin/sh -c 'cat </etc/apk/repositories -http://dl-cdn.alpinelinux.org/alpine/latest-stable/main -http://dl-cdn.alpinelinux.org/alpine/latest-stable/community +https://dl-cdn.alpinelinux.org/alpine/latest-stable/main +https://dl-cdn.alpinelinux.org/alpine/latest-stable/community EOF' pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses jq" >>"$BUILD_LOG" 2>&1 || { msg_error "Failed to install base packages in Alpine container" @@ -4086,7 +4091,9 @@ EOF' else sleep 3 LANG=${LANG:-en_US.UTF-8} - pct exec "$CTID" -- bash -c "sed -i \"/$LANG/ s/^# //\" /etc/locale.gen" + local LANG_ESC="${LANG//./\\.}" + LANG_ESC="${LANG_ESC//|/\\|}" + pct exec "$CTID" -- bash -c "sed -i \"/$LANG_ESC/ s/^# //\" /etc/locale.gen" pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \ echo LANG=\$locale_line >/etc/default/locale && \ locale-gen >/dev/null && \ @@ -4759,6 +4766,10 @@ fix_gpu_gids() { pct stop "$CTID" >/dev/null 2>&1 sleep 1 + # Validate GIDs are numeric before sed + [[ "$render_gid" =~ ^[0-9]+$ ]] || render_gid="104" + [[ "$video_gid" =~ ^[0-9]+$ ]] || video_gid="44" + # Update dev entries with correct GIDs sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG" sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG" diff --git a/misc/install.func b/misc/install.func index 94f005b26..024e0633d 100644 --- a/misc/install.func +++ b/misc/install.func @@ -309,14 +309,14 @@ customize() { if [[ "$PASSWORD" == "" ]]; then msg_info "Customizing Container" GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf" - mkdir -p $(dirname $GETTY_OVERRIDE) - cat <$GETTY_OVERRIDE + mkdir -p "$(dirname "$GETTY_OVERRIDE")" + cat <"$GETTY_OVERRIDE" [Service] ExecStart= ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM EOF systemctl daemon-reload - systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//') + systemctl restart "$(basename "$(dirname "$GETTY_OVERRIDE")" | sed 's/\.d//')" msg_ok "Customized Container" fi echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update diff --git a/misc/tools.func b/misc/tools.func index 2e54b86e1..62bc83b6a 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -242,7 +242,7 @@ download_gpg_key() { # Process based on mode if [[ "$mode" == "dearmor" ]]; then - if gpg --dearmor --yes -o "$output" <"$temp_key" 2>/dev/null; then + if gpg --dearmor --yes -o "$output" <"$temp_key" 2>/dev/null && [[ -s "$output" ]]; then rm -f "$temp_key" debug_log "GPG key installed (dearmored): $output" return 0 @@ -5192,7 +5192,7 @@ _setup_gpu_permissions() { for nvidia_dev in /dev/nvidia*; do [[ -e "$nvidia_dev" ]] && { chgrp video "$nvidia_dev" 2>/dev/null || true - chmod 666 "$nvidia_dev" 2>/dev/null || true + chmod 660 "$nvidia_dev" 2>/dev/null || true } done if [[ -d /dev/nvidia-caps ]]; then @@ -5200,7 +5200,7 @@ _setup_gpu_permissions() { for caps_dev in /dev/nvidia-caps/*; do [[ -e "$caps_dev" ]] && { chgrp video "$caps_dev" 2>/dev/null || true - chmod 666 "$caps_dev" 2>/dev/null || true + chmod 660 "$caps_dev" 2>/dev/null || true } done fi @@ -5217,7 +5217,8 @@ _setup_gpu_permissions() { # /dev/kfd permissions (AMD ROCm) if [[ -e /dev/kfd ]]; then - chmod 666 /dev/kfd 2>/dev/null || true + chgrp render /dev/kfd 2>/dev/null || true + chmod 660 /dev/kfd 2>/dev/null || true msg_info "AMD ROCm compute device configured" fi diff --git a/tools/addon/runtipi.sh b/tools/addon/runtipi.sh index 064605752..d4ba9bddb 100644 --- a/tools/addon/runtipi.sh +++ b/tools/addon/runtipi.sh @@ -150,7 +150,7 @@ function install() { curl -fsSL "https://raw.githubusercontent.com/runtipi/runtipi/master/scripts/install.sh" -o "install.sh" chmod +x install.sh $STD ./install.sh - chmod 666 /opt/runtipi/state/settings.json 2>/dev/null || true + chmod 660 /opt/runtipi/state/settings.json 2>/dev/null || true rm -f /opt/install.sh msg_ok "Installed ${APP}"