Files
debianito-post-install/modules/firmware.sh
T
stornic56 54257d5a8a Security hardening & DRY refactoring
- Fixed command injection in desktop_display.sh by converting word-splitting loops to safe array-based iteration for LightDM/GDM3 configuration and XFCE package installation.
- Added symlink detection guard before repository file operations in repos.sh to prevent TOCTOU attacks during restore_previous_repos().
- Hardened SUDO_USER resolution with awk validation against /etc/passwd to prevent root fallback and ensure real login users are targeted for sudoers configuration.
- Implemented algorithm (lz4/zstd) and size validation before ZRAM configuration writes in zram.sh to reject invalid inputs.
- Protected grep MemTotal read from /proc/meminfo with 2>/dev/null and default assignment under set -u.
- Added || true guards around apt-cache madison pipelines in firmware.sh, kernel.sh, gpu.sh, and utils.sh to prevent pipefail aborts when backports unavailable.
- Wrapped whiptail installation in if/else blocks to allow offline error messages instead of script termination under set -e.
- Fixed grep -c output duplication in swap.sh with proper || true pattern and default variable assignment.
- Replaced unquoted $cleaned loops with array conversion using while read for secure package iteration across gaming, desktop_display, firmware, and kernel modules.
- Anchored sed regex patterns to space-delimited "main" components to prevent mirror URL corruption in sources.list editing.
- Escaped % characters in _msg() function before passing to whiptail to prevent printf format interpretation crashes.
- Consolidated package version helpers into canonical wrappers: _get_pkg_version, _get_installed_version, _get_backports_version for consistent apt/dpkg queries.
- Created _install_if_missing() and _install_pkg() with proper error handling that respects set -e while providing user feedback on installation failures.
- Removed 6 dead code functions (~51 lines): check_system_time, sync_system_time, get_cpu_summary, get_ram_summary, pkg_versions, get_backports_kernel_version.
- Added detect_displayserver and detect_audio_server to refresh_system_state() for complete state refresh when returning from menus.
- Enhanced _on_interrupt() trap handler to kill lingering apt/dpkg child processes and clean /tmp/debianito.* temporary files on Ctrl+C or TERM.
- Improved restore_previous_repos() with manifest-based backup verification (.backed_up_* markers) to prevent destructive repository file deletion.
- Added mktemp usage for secure temporary deb file downloads in nvidia.sh, heroic.sh, and tools.sh to eliminate TOCTOU vulnerabilities in /tmp.
- Fixed Bluetooth USB dongle misclassification as WiFi devices by excluding "bluetooth" strings from USB_WIFI_DEVS detection in firmware.sh.
- Properly utilized the need array for selective package installation in internet.sh instead of hardcoding full package list.
- Corrected fwupdmgr duplicate execution and grep false positives in system.sh with strict pattern matching for available updates.
- update docs and added quickstart guide
2026-09-14 20:31:48 -05:00

495 lines
19 KiB
Bash

#!/usr/bin/env bash
# ── Global arrays ──
PCI_NET_DEVS=()
USB_WIFI_DEVS=()
PCI_BT_DEVS=()
USB_BT_DEVS=()
_DETECTED_FW_PKGS=()
_FW_PLAN_HW_LINES=()
_FW_PLAN_PKG_LINES=()
# ── Network device detection (PCI + USB) ──
_detect_all_network_devices() {
! is_installed pciutils && _install_pkg pciutils
! is_installed usbutils && _install_pkg usbutils
PCI_NET_DEVS=()
while IFS= read -r line; do
PCI_NET_DEVS+=("$line")
done < <(echo "$LSPCI_OUTPUT" | grep -iE 'network controller|ethernet controller' || true)
USB_WIFI_DEVS=()
while IFS= read -r line; do
# Exclude Bluetooth dongles: many report e.g. "Bluetooth wireless
# interface" and would otherwise be classified as WiFi and mapped
# to firmware-iwlwifi.
if echo "$line" | grep -qiE 'wireless|wifi|802\.11|wlan' &&
! echo "$line" | grep -qi 'bluetooth'; then
USB_WIFI_DEVS+=("$line")
fi
done < <(lsusb 2>/dev/null || true)
PCI_BT_DEVS=()
while IFS= read -r line; do
PCI_BT_DEVS+=("$line")
done < <(echo "$LSPCI_OUTPUT" | grep -i 'Bluetooth controller' || true)
USB_BT_DEVS=()
while IFS= read -r line; do
# All Bluetooth dongles belong here (the WiFi filter above now
# excludes anything containing "bluetooth").
if echo "$line" | grep -qi 'bluetooth'; then
USB_BT_DEVS+=("$line")
fi
done < <(lsusb 2>/dev/null || true)
_FW_PLAN_HW_LINES=()
for dev in "${PCI_NET_DEVS[@]}"; do
local desc dev_type
desc=$(echo "$dev" | sed -E 's/^[^ ]+ [^:]+: //; s/ \[[0-9a-fA-F]{4}:[0-9a-fA-F]{4}\]//; s/ \(rev.*\)//')
if echo "$dev" | grep -qiE 'network controller|wireless|wi-fi|wlan|802\.11'; then
dev_type="WiFi PCI"
else
dev_type="Ethernet PCI"
fi
_FW_PLAN_HW_LINES+=(" \xe2\x97\x8f ${desc} (${dev_type})")
done
for dev in "${USB_WIFI_DEVS[@]}"; do
local desc
desc=$(echo "$dev" | sed 's/^.*ID //')
_FW_PLAN_HW_LINES+=(" \xe2\x97\x8f ${desc} (USB)")
done
for dev in "${PCI_BT_DEVS[@]}"; do
local desc
desc=$(echo "$dev" | sed -E 's/^[^ ]+ [^:]+: //; s/ \[[0-9a-fA-F]{4}:[0-9a-fA-F]{4}\]//; s/ \(rev.*\)//')
_FW_PLAN_HW_LINES+=(" \xe2\x97\x8f ${desc} (Bluetooth PCI)")
done
for dev in "${USB_BT_DEVS[@]}"; do
local desc
desc=$(echo "$dev" | sed 's/^.*ID //')
_FW_PLAN_HW_LINES+=(" \xe2\x97\x8f ${desc} (Bluetooth USB)")
done
}
# ── Firmware package mapping ──
_detect_firmware_needs() {
local -A pkg_info
_DETECTED_FW_PKGS=()
_FW_PLAN_PKG_LINES=()
local dev_list
dev_list=("${PCI_NET_DEVS[@]}" "${USB_WIFI_DEVS[@]}")
for dev in "${dev_list[@]}"; do
local raw_desc vendor_lc pkg
raw_desc=$(echo "$dev" | sed -E 's/^[^ ]+ [^:]+: //; s/ \[[0-9a-fA-F]{4}:[0-9a-fA-F]{4}\]//; s/ \(rev.*\)//')
vendor_lc=$(echo "$dev" | sed -n 's/^.*]: //p' | awk '{print $1}' | tr '[:upper:]' '[:lower:]')
[[ "$vendor_lc" != *intel* && "$vendor_lc" != *realtek* && "$vendor_lc" != *atheros* && "$vendor_lc" != *qualcomm* && "$vendor_lc" != *mediatek* ]] && continue
case "$vendor_lc" in
*intel*)
if echo "$dev" | grep -qiE 'wireless|wi-fi|wlan|802\.11'; then
pkg="firmware-iwlwifi"
else
pkg="firmware-intel-misc"
fi
;;
*realtek*) pkg="firmware-realtek" ;;
*atheros* | *qualcomm*) pkg="firmware-atheros" ;;
*mediatek*) pkg="firmware-mediatek" ;;
esac
local short_dev
short_dev=$(echo "$raw_desc" | sed 's/ *\[[^]]*\]//g; s/ */ /g')
if [ -z "${pkg_info[$pkg]-}" ]; then
pkg_info[$pkg]="$short_dev"
else
pkg_info[$pkg]+=", $short_dev"
fi
done
for pkg in "${!pkg_info[@]}"; do
_DETECTED_FW_PKGS+=("$pkg")
_FW_PLAN_PKG_LINES+=(" [+] ${pkg} \xe2\x86\x90 ${pkg_info[$pkg]}")
done
mapfile -t _DETECTED_FW_PKGS < <(printf '%s\n' "${_DETECTED_FW_PKGS[@]}" | sort -u)
}
# ── Build plan string ──
_build_firmware_plan() {
local plan=""
plan+="This section installs the essential non-free firmware stack\n"
plan+="for Debian (including CPU microcode, GPU, network, and core\n"
plan+="drivers). The script has scanned your hardware to prepare\n"
plan+="the setup:\n\n"
plan+="Detected controllers:\n"
if [ ${#_FW_PLAN_HW_LINES[@]} -eq 0 ]; then
plan+=" (none detected)\n"
else
for line in "${_FW_PLAN_HW_LINES[@]}"; do
plan+="${line}\n"
done
fi
plan+="\nPlanned firmware packages:\n"
local fw_line
if is_installed firmware-linux-nonfree; then
local cur_ver
cur_ver=$(_get_installed_version "firmware-linux-nonfree")
fw_line=" [+] firmware-linux-nonfree ${cur_ver} (already installed)"
else
fw_line=" [+] firmware-linux-nonfree (base meta-package)"
fi
plan+="${fw_line}\n"
for line in "${_FW_PLAN_PKG_LINES[@]}"; do
plan+="${line}\n"
done
local has_bt=false
[ ${#PCI_BT_DEVS[@]} -gt 0 ] && has_bt=true
[ ${#USB_BT_DEVS[@]} -gt 0 ] && has_bt=true
if ! $has_bt; then
for dev in "${USB_WIFI_DEVS[@]}"; do
if echo "$dev" | grep -qi 'bluetooth'; then
has_bt=true
break
fi
done
fi
plan+="\nBluetooth:\n"
if $has_bt; then
if is_installed bluez; then
plan+=" [+] bluez (already installed)\n"
else
plan+=" [+] bluez + bluez-tools + bluez-obexd (base stack)\n"
fi
case "${DESKTOP_ENV:-other}" in
kde)
plan+=" [+] bluedevil (KDE applet)\n"
if [ "${AUDIO_SERVER:-}" = "pipewire" ]; then
plan+=" → pipewire-pulse + wireplumber (if missing)\n"
fi
;;
gnome) plan+=" (already in gnome-control-center)\n" ;;
*) plan+=" [+] blueman (GTK Bluetooth manager)\n" ;;
esac
plan+=" → Bluetooth service will be enabled\n"
else
plan+=" (no Bluetooth hardware detected)\n"
fi
plan+="\nInstallation order:\n"
plan+=" 1. Base firmware (firmware-linux-nonfree)\n"
plan+=" 2. Network firmware (realtek, iwlwifi, ...)\n"
plan+=" 3. Broadcom / Bluetooth firmware\n"
echo -e "$plan"
}
# ── Install detected firmware packages ──
_install_detected_firmware() {
local to_install=()
for pkg in "${_DETECTED_FW_PKGS[@]}"; do
if is_installed "$pkg"; then
echo " --> $pkg already installed."
continue
fi
local ver
ver=$(_get_pkg_version "$pkg")
if [ -z "$ver" ] || [ "$ver" = "(none)" ]; then
echo " --> $pkg not available in repositories, skipping."
continue
fi
to_install+=("$pkg")
done
if [ ${#to_install[@]} -gt 0 ]; then
_run_cmd "Firmware" "sudo DEBIAN_FRONTEND=noninteractive apt install -y ${to_install[*]}" \
"Installing network firmware packages..." || true
fi
}
# ── Wireless handler (Broadcom single-path wl) ──
_handle_wireless() {
local installed_any=false
local wl_build_failed=false
if [ ${#PCI_NET_DEVS[@]} -eq 0 ] && [ ${#USB_WIFI_DEVS[@]} -eq 0 ]; then
_detect_all_network_devices
fi
for dev in "${PCI_NET_DEVS[@]}"; do
local bcm_id dev_id
bcm_id=$(echo "$dev" | grep -oP '14e4:[0-9a-fA-F]+' || true)
[ -z "$bcm_id" ] && continue
dev_id=$(echo "$bcm_id" | cut -d: -f2 | tr '[:upper:]' '[:lower:]')
# --- Dependencies verification ---
if ! is_installed "linux-headers-amd64" || ! is_installed "dkms"; then
if ! apt-cache show linux-headers-amd64 dkms >/dev/null 2>&1; then
_msg "Broadcom Error" "linux-headers-amd64 or dkms are not available in your repositories. Cannot compile Broadcom driver.\n\nEnsure repositories are enabled and run:\n sudo apt install linux-headers-amd64 dkms"
_pause
continue
fi
fi
# --- Confirmation ---
if ! _confirm "Broadcom WiFi" "Detected Broadcom wireless device.\n\nInstall broadcom-sta-dkms, dkms, and wireless-tools?"; then
continue
fi
# --- Step-by-step installation ---
_run_cmd "Broadcom Deps" "sudo DEBIAN_FRONTEND=noninteractive apt install -y dkms wireless-tools linux-headers-amd64" || true
_run_cmd "Broadcom Driver" "sudo DEBIAN_FRONTEND=noninteractive apt install -y broadcom-sta-dkms" || true
# --- Persist blacklist of conflicting modules ---
local blacklist_conf="/etc/modprobe.d/blacklist-broadcom.conf"
local blacklist_content="blacklist b43\nblacklist b43legacy\nblacklist brcmsmac\nblacklist bcma\nblacklist ssb"
echo -e "$blacklist_content" | sudo tee "$blacklist_conf" >/dev/null || true
# --- Update initramfs and load module ---
_run_cmd "Initramfs" "sudo update-initramfs -u" || true
_run_cmd "Modprobe" "sudo modprobe -r b43 b43legacy b44 bcma brcmsmac brcmfmac ssb wl 2>/dev/null || true" "Removing conflicting modules" || true
_run_cmd "Modprobe" "sudo modprobe wl" || true
# --- Combo BT (unchanged) ---
local has_broadcom_bt=false
local btdev
for btdev in "${PCI_BT_DEVS[@]}"; do
if echo "$btdev" | grep -qi 'broadcom'; then
has_broadcom_bt=true
break
fi
done
if $has_broadcom_bt; then
echo -e "${YELLOW}[+] Broadcom WiFi+BT combo card detected.${NC}"
sudo mkdir -p /etc/modprobe.d
printf 'softdep wl post: btusb\n' | sudo tee /etc/modprobe.d/broadcom-combo.conf >/dev/null || true
echo -e "${YELLOW} A reboot may be required for Bluetooth support.${NC}"
fi
# --- Post-DKMS verification (Fix 5, unchanged) ---
if ! ls /lib/modules/$(uname -r)/updates/dkms/wl.ko* 2>/dev/null | grep -q .; then
_msg "Broadcom DKMS Build Failed" "The wl module was not built by DKMS.\n\nPossible causes:\n- Missing build tools (build-essential, dkms)\n- Kernel update without headers\n- Incompatible kernel version\n\nTry: sudo dpkg-reconfigure broadcom-sta-dkms"
if _confirm "Broadcom" "Rebuild the Broadcom driver now?"; then
_run_cmd "Broadcom" "sudo dpkg-reconfigure broadcom-sta-dkms" || true
if ls /lib/modules/$(uname -r)/updates/dkms/wl.ko* 2>/dev/null | grep -q .; then
:
else
local dmesg_out
dmesg_out=$(sudo dmesg | tail -20 2>/dev/null || echo "(dmesg unavailable)")
_msg "Broadcom DKMS Still Failed" "dpkg-reconfigure did not produce wl.ko either.\n\nLast kernel messages:\n${dmesg_out}\n\nYou may need to check build logs or report a bug against broadcom-sta-dkms."
_pause
wl_build_failed=true
continue
fi
else
wl_build_failed=true
continue
fi
fi
_msg "Network Warning" "The script is about to unload current WiFi kernel modules to load the Broadcom driver.\n\nIf you are connected via SSH over WiFi, YOUR CONNECTION WILL DROP. Please reconnect after a few seconds."
sudo modprobe -r b43 b43legacy b44 bcma brcmsmac brcmfmac ssb wl 2>/dev/null || true
sudo modprobe wl 2>/dev/null || true
# --- Verificación de carga ---
if lsmod | grep -q '^wl '; then
echo -e "${GREEN}[+] Broadcom WiFi activated (wl module loaded).${NC}"
_pause
installed_any=true
else
echo -e "${YELLOW}[+] Broadcom driver installed but wl module did not load.${NC}"
echo -e "${YELLOW} A system reboot is required.${NC}"
_pause
installed_any=true
fi
done
# --- USB Broadcom (unchanged) ---
local usb_dev
for usb_dev in "${USB_WIFI_DEVS[@]}"; do
if echo "$usb_dev" | grep -qi '0a5c'; then
_msg "USB Broadcom" "USB Broadcom device detected (0a5c).\n\nLinux does not have native drivers for most USB Broadcom WiFi chips.\nndiswrapper may be needed as a last resort."
_pause
fi
done
# --- Mensaje final (unchanged) ---
if ! $installed_any && ! $wl_build_failed; then
echo "No special WiFi firmware needed -- base firmware-linux-nonfree covers this system."
_pause
fi
}
# ── Ensure non-free repository is enabled ──
# Token-exact check for the "non-free" component. "non-free-firmware"
# contains the substring but is a different component, so word-boundary
# matching (\b) would produce false positives.
_has_nonfree_component() {
local file="$1"
grep -qE '^[^#]*[[:space:]]non-free([[:space:]]|$)' "$file" 2>/dev/null
}
_ensure_nonfree_repo() {
local nonfree_found=false
if [ -f /etc/apt/sources.list ] && _has_nonfree_component /etc/apt/sources.list; then
nonfree_found=true
fi
if ! $nonfree_found && [ -d /etc/apt/sources.list.d ]; then
for f in /etc/apt/sources.list.d/*.sources /etc/apt/sources.list.d/*.list; do
[ -f "$f" ] || continue
if _has_nonfree_component "$f"; then
nonfree_found=true
break
fi
done
fi
if $nonfree_found; then
return 0
fi
if ! _confirm "non-free Repository" "Component 'non-free' (and 'non-free-firmware') is required for WiFi/Bluetooth/GPU firmware.\n\nAdd them to your APT repositories?"; then
return 1
fi
# No active sources at all → bootstrap a complete configuration
if ! has_active_deb_sources; then
backup_current_repos
if ! bootstrap_repositories "main contrib non-free non-free-firmware"; then
return 1
fi
else
if [ -f /etc/apt/sources.list ]; then
sudo cp /etc/apt/sources.list "/etc/apt/sources.list.backup.$(date +%Y%m%d_%H%M%S)"
# Add each missing component after the space-delimited "main"
# component; a bare s/main/ would corrupt mirror URLs that
# contain "main" (e.g. https://main.example.com).
sudo sed -i -E '/^deb / { /(^|[[:space:]])non-free([[:space:]]|$)/! s/ main([[:space:]]|$)/ main non-free\1/ }' /etc/apt/sources.list
# non-free-firmware does not exist on Bullseye
if [ "$DEBIAN_VERSION" != "11" ]; then
sudo sed -i -E '/^deb / { /(^|[[:space:]])non-free-firmware([[:space:]]|$)/! s/ main([[:space:]]|$)/ main non-free-firmware\1/ }' /etc/apt/sources.list
fi
fi
if [ -d /etc/apt/sources.list.d ]; then
for f in /etc/apt/sources.list.d/*.sources; do
[ -f "$f" ] || continue
sudo cp "$f" "${f}.backup.$(date +%Y%m%d_%H%M%S)"
sudo sed -i -E '/^Components:/ { /(^|[[:space:]])non-free([[:space:]]|$)/! s/$/ non-free/ }' "$f"
if [ "$DEBIAN_VERSION" != "11" ]; then
sudo sed -i -E '/^Components:/ { /(^|[[:space:]])non-free-firmware([[:space:]]|$)/! s/$/ non-free-firmware/ }' "$f"
fi
done
fi
fi
# Verify the component was actually added before reporting success
local nonfree_ok=false
[ -f /etc/apt/sources.list ] && _has_nonfree_component /etc/apt/sources.list && nonfree_ok=true
if ! $nonfree_ok && [ -d /etc/apt/sources.list.d ]; then
for f in /etc/apt/sources.list.d/*.sources /etc/apt/sources.list.d/*.list; do
[ -f "$f" ] || continue
if _has_nonfree_component "$f"; then
nonfree_ok=true
break
fi
done
fi
if ! $nonfree_ok; then
echo -e "${RED}Failed to enable non-free repository. Check your APT sources.${NC}"
return 1
fi
_ensure_apt_updated
echo -e "${GREEN}non-free repository enabled.${NC}"
return 0
}
# ── Main entry point ──
install_firmware() {
echo -e "${YELLOW}Base firmware check...${NC}"
if ! _ensure_nonfree_repo; then
_msg "Error" "No 'non-free' repositories were enabled and the user declined to add them.\nPlease enable non-free manually or accept the prompt in the Firmware option." 10 65
return 1
fi
# 1. Detect
_detect_all_network_devices
_detect_firmware_needs
# 2. Plan
local plan
plan=$(_build_firmware_plan)
_msg "Firmware, Wireless & Bluetooth Setup" "$plan" 22 72
# 3. Confirm
if ! _confirm "Firmware" "Apply the network & firmware plan?"; then
echo "Firmware installation skipped."
return
fi
# 4. Install base firmware meta-package (unchanged logic)
local fw_pkg="firmware-linux-nonfree"
local fw_bpo
fw_bpo=$(_get_backports_version "$fw_pkg")
local fw_stable
fw_stable=$(_get_pkg_version "$fw_pkg")
if is_installed "$fw_pkg"; then
if [ -n "$fw_bpo" ]; then
local current_ver
current_ver=$(_get_installed_version "$fw_pkg")
if _confirm "Firmware" "firmware-linux-nonfree ${current_ver} already installed.\n\nUpgrade to backports version ${fw_bpo}?\n\nBackports often includes newer hardware support."; then
_run_cmd "Firmware" "sudo apt install -y -t ${DEBIAN_CODENAME}-backports $fw_pkg" "Upgrading firmware..." || true
fi
else
echo "$fw_pkg already installed."
fi
else
local msg="firmware-linux-nonfree provides hardware drivers for:\n"
msg+=" WiFi, Bluetooth, GPU, audio, webcams, and more.\n\n"
if [ -n "$fw_bpo" ]; then
msg+=" ● Stable: ${fw_stable}\n"
msg+=" Ultra tested, but may lack support for\n"
msg+=" very recent hardware.\n\n"
msg+=" ● Backports: ${fw_bpo} (Recommended)\n"
msg+=" Updated firmware for modern hardware from\n"
msg+=" 2025/2026: recent GPUs, processors, WiFi.\n\n"
msg+="Choose version:"
if _confirm_custom "Firmware" "$msg" "Backports" "Stable"; then
_run_cmd "Firmware" "sudo apt install -y -t ${DEBIAN_CODENAME}-backports $fw_pkg" "Installing firmware from backports..." || true
else
_run_cmd "Firmware" "sudo apt install -y $fw_pkg" "Installing firmware from stable..." || true
fi
else
msg+=" Version: ${fw_stable}\n\n"
msg+="Install it?"
if _confirm "Firmware" "$msg"; then
_run_cmd "Firmware" "sudo apt install -y $fw_pkg" "Installing firmware..." || true
fi
fi
echo -e "${GREEN}Base firmware installed.${NC}"
fi
# 5. Install specific network firmware packages
_install_detected_firmware
# 6. Broadcom wireless handler
_handle_wireless
# 7. Bluetooth stack
_install_bluetooth_stack
# 8. Summary
echo -e "${GREEN}Network & firmware setup complete.${NC}"
_pause
}