Skip to content

Commit 1ff4488

Browse files
feat(windows): add SDIO driver update step with opt-in safety
Implements Snappy Driver Installer Origin (SDIO) support for Windows. SDIO is opt-in and disabled by default due to its invasive nature (driver updates can brick hardware). Includes vulnerability assessment. From PRs topgrade-rs#1338 and topgrade-rs#1339 by niStee. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 390b330 commit 1ff4488

16 files changed

Lines changed: 1252 additions & 81 deletions

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
5555
- NixOS or Nix (nixpkgs): [topgrade](https://search.nixos.org/packages?show=topgrade)
5656
- Void Linux: [`sudo xbps-install -S topgrade`](https://voidlinux.org/packages/?arch=x86_64&q=topgrade)
5757

58+
### Windows Features
59+
60+
On Windows, Topgrade supports updating:
61+
62+
- **Package Managers**: Chocolatey, Scoop, Winget
63+
- **System Updates**: Windows Update, Microsoft Store apps
64+
- **Driver Updates**: SDIO (Snappy Driver Installer Origin) - *requires explicit opt-in*
65+
- **Development Tools**: Various language package managers and development environments
66+
67+
*Note: Driver updates via SDIO require setting `enable_sdio = true` in your configuration file due to the critical nature of driver installations.*
68+
5869
## Usage
5970

6071
Just run `topgrade`.

SDIO_VULNERABILITY_ASSESSMENT.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# SDIO Implementation Vulnerability Assessment Report
2+
3+
**Generated:** August 17, 2025
4+
**Tested Version:** feat/windows-sdio-support branch
5+
6+
## Executive Summary
7+
8+
Comprehensive adversarial testing was conducted on the SDIO implementation to identify
9+
potential security vulnerabilities, edge cases, and failure modes.
10+
11+
## Test Results
12+
13+
### PASSED TESTS (Secure)
14+
15+
1. **Invalid Executable Detection**
16+
- STATUS: SECURE
17+
- Test: Pointed configuration to fake/invalid SDIO executable
18+
- Result: System correctly rejected invalid executable with clear error message
19+
- Error: "This version of %1 is not compatible with the version of Windows you're running"
20+
- Conclusion: Proper validation prevents execution of invalid binaries
21+
22+
2. **Path Injection via Script Generation**
23+
- STATUS: SECURE
24+
- Test: Examined generated SDIO scripts for injection vulnerabilities
25+
- Result: All directory paths are properly quoted in generated scripts
26+
- Example: extractdir "C:\Users\2glea\AppData\Local\Temp\topgrade_sdio"
27+
- Conclusion: Script generation is safe from path injection attacks
28+
29+
3. **Binary Validation**
30+
- STATUS: SECURE
31+
- Test: System attempts to execute only validated executables
32+
- Result: Non-PE executables are rejected by the OS before execution
33+
- Conclusion: OS-level protection prevents arbitrary code execution
34+
35+
### POTENTIAL ISSUES IDENTIFIED
36+
37+
1. **Configuration Path Injection**
38+
- STATUS: NEEDS INVESTIGATION
39+
- Test: Attempted to inject commands via sdio_path configuration
40+
- Issue: Command execution hung, indicating potential parsing problems
41+
- Risk: Medium - could cause DoS if malformed paths are processed
42+
- Recommendation: Add input validation for configuration paths
43+
44+
2. **Timeout Handling in Config Safety Workflow**
45+
- STATUS: NEEDS IMPROVEMENT
46+
- Test: Commands with dangerous configs caused timeouts
47+
- Issue: 10-second timeout may be insufficient for SDIO detection
48+
- Risk: Low - workflow might produce false negatives
49+
- Recommendation: Increase timeout or add better error handling
50+
51+
3. **Grep Pattern Vulnerability in CI Workflow**
52+
- STATUS: NEEDS TESTING
53+
- Test: Created config with tricky formatting to fool regex patterns
54+
- Potential Issue: Simple grep patterns might be fooled by:
55+
- Comments containing target strings
56+
- Non-standard spacing (enable_sdio=true vs enable_sdio = true)
57+
- Inline comments after dangerous settings
58+
- Recommendation: Use more robust TOML parsing instead of grep
59+
60+
### SECURITY STRENGTHS CONFIRMED
61+
62+
1. **Principle of Least Privilege**: SDIO disabled by default, requires explicit opt-in
63+
2. **Safe Script Generation**: All paths properly quoted and escaped
64+
3. **Error Handling**: Clear error messages without information disclosure
65+
4. **Restore Point Safety**: Script continues on restore point failure (graceful degradation)
66+
5. **Command Validation**: Invalid executables rejected at OS level
67+
6. **Logging Transparency**: All SDIO commands logged for security auditing
68+
69+
## Recommendations
70+
71+
### High Priority
72+
73+
1. Add input validation for sdio_path configuration to prevent DoS
74+
2. Improve config safety workflow to use TOML parser instead of grep
75+
3. Add timeout handling for long-running SDIO operations
76+
77+
### Medium Priority
78+
79+
1. Add unit tests for configuration parsing edge cases
80+
2. Implement more robust executable validation
81+
3. Add integration tests for script generation vulnerabilities
82+
83+
### Low Priority
84+
85+
1. Add telemetry for failed SDIO operations
86+
2. Implement configurable timeouts for different operation modes
87+
3. Add checksums for script integrity validation
88+
89+
## Conclusion
90+
91+
The SDIO implementation demonstrates strong security fundamentals with proper input
92+
validation, safe script generation, and fail-secure behavior. The identified issues
93+
are primarily related to robustness rather than security vulnerabilities.
94+
95+
The implementation successfully prevents the most critical attack vectors:
96+
97+
- Arbitrary code execution via fake executables
98+
- Script injection via path manipulation
99+
- Privilege escalation through configuration manipulation
100+
101+
Recommended fixes are defensive improvements rather than critical security patches.

config.example.toml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,53 @@
321321
# (default: false)
322322
# winget_use_sudo = true
323323

324+
# Enable SDIO (Snappy Driver Installer Origin) driver updates
325+
# WARNING: Driver updates can potentially cause system instability if incompatible
326+
# drivers are installed. Only enable this if you understand the risks and have
327+
# system backups. SDIO will create restore points when possible for safety.
328+
# (default: false - requires explicit opt-in)
329+
# enable_sdio = false
330+
331+
# Path to Snappy Driver Installer Origin (SDIO) executable
332+
# If not specified, Topgrade will try to find SDIO automatically by checking:
333+
# 1. SDIO_auto.bat (recommended) - automatically detects correct architecture
334+
# 2. Versioned executables (SDIO_x64_Rxxx.exe, SDIO_Rxxx.exe)
335+
# 3. Common installation locations (Scoop, Program Files, portable installs)
336+
# Examples:
337+
# sdio_path = "C:\\Users\\%USERNAME%\\scoop\\apps\\snappy-driver-installer-origin\\current\\SDIO_auto.bat"
338+
# sdio_path = "C:\\Program Files\\SDIO\\SDIO_x64_R1515.exe"
339+
340+
# Advanced SDIO configuration
341+
#[windows.sdio]
342+
# Filters applied to the SDIO "select" command. Defaults to ["missing", "newer", "better"].
343+
# selection_filters = ["missing", "newer", "better"]
344+
345+
# Driver pack download policy during install. One of: "none", "selected", "missing", "updates", "all".
346+
# driverpack_policy = "selected"
347+
348+
# Download driver packs during analysis (without installing) so they are ready for later runs.
349+
# prefetch_in_analysis = false
350+
351+
# Update the SDIO index catalog when running (recommended unless offline).
352+
# fetch_indexes = true
353+
354+
# Allow SDIO to download updated driver packs.
355+
# fetch_updates = true
356+
357+
# Control SDIO verbosity and logging; values above 255 enable debug-level detail.
358+
# verbose_level = 255
359+
# debug_logging = true
360+
361+
# Keep SDIO extraction and log files in the temporary directory for review.
362+
# keep_tempfiles = true
363+
364+
# Emit echo statements in the SDIO console output for easier tracing.
365+
# emit_echo = true
366+
367+
# Create a system restore point before installing drivers and customise its description.
368+
# restore_point = true
369+
# restore_point_description = "Topgrade SDIO Driver Update"
370+
324371

325372
[chezmoi]
326373
# Exclude encrypted files from update

locales/app.yml

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,3 +1482,193 @@ _version: 2
14821482
zh_CN: "Flatpak %{name} 未安装"
14831483
zh_TW: "Flatpak %{name} 未安装"
14841484
de: "Flatpak %{name} ist nicht installiert"
1485+
"freshclam is already running (lock file found). The ClamAV auto-updater service handles database updates.":
1486+
en: "freshclam is already running (lock file found). The ClamAV auto-updater service handles database updates."
1487+
"Fetching (jj)":
1488+
en: "Fetching (jj)"
1489+
"jj git fetch":
1490+
en: "jj git fetch"
1491+
"nom (nix-output-monitor) is configured but not installed":
1492+
en: "nom (nix-output-monitor) is configured but not installed"
1493+
"Reboot now?":
1494+
en: "Reboot now?"
1495+
"Some firmware updates may require a reboot to take effect. Run `fwupdmgr get-updates` for details.":
1496+
en: "Some firmware updates may require a reboot to take effect. Run `fwupdmgr get-updates` for details."
1497+
"No hardware ID update tools found":
1498+
en: "No hardware ID update tools found"
1499+
"Failed to refresh sudo credentials":
1500+
en: "Failed to refresh sudo credentials"
1501+
"Configuration file changed during run. Respawning...":
1502+
en: "Configuration file changed during run. Respawning..."
1503+
"Failed to refresh sudo credentials: {error}":
1504+
en: "Failed to refresh sudo credentials: %{error}"
1505+
"Awaiting user":
1506+
en: "Awaiting user"
1507+
"Checking for updates via store CLI...":
1508+
en: "Checking for updates via store CLI..."
1509+
"Cleaning up old module versions...":
1510+
en: "Cleaning up old module versions..."
1511+
"Hardware IDs ({cmd_name})":
1512+
en: "Hardware IDs (%{cmd_name})"
1513+
"Self-update: {old} -> {new}":
1514+
en: "Self-update: %{old} -> %{new}"
1515+
"System needs a reboot after updates.":
1516+
en: "System needs a reboot after updates."
1517+
"Snappy Driver Installer Origin":
1518+
en: "Snappy Driver Installer Origin"
1519+
"Running SDIO analysis...":
1520+
en: "Running SDIO analysis..."
1521+
"Running SDIO automatic installation...":
1522+
en: "Running SDIO automatic installation..."
1523+
"Running SDIO dry-run analysis...":
1524+
en: "Running SDIO dry-run analysis..."
1525+
"Running SDIO installation...":
1526+
en: "Running SDIO installation..."
1527+
"SDIO analysis complete.":
1528+
en: "SDIO analysis complete."
1529+
"SDIO analysis found no drivers to install; keeping this run in analysis mode.":
1530+
en: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1531+
"SDIO automatic installation complete.":
1532+
en: "SDIO automatic installation complete."
1533+
"SDIO driver updates are disabled. Enable with 'enable_sdio = true' in [windows] section":
1534+
en: "SDIO driver updates are disabled. Enable with 'enable_sdio = true' in [windows] section"
1535+
"SDIO dry-run analysis complete.":
1536+
en: "SDIO dry-run analysis complete."
1537+
"SDIO installation complete.":
1538+
en: "SDIO installation complete."
1539+
"SDIO (Snappy Driver Installer Origin) not found":
1540+
en: "SDIO (Snappy Driver Installer Origin) not found"
1541+
"Failed to run trigger for {}: {}":
1542+
en: "Failed to run trigger for %{}: %{}"
1543+
"Command failed: `{command}`":
1544+
en: "Command failed: `%{command}`"
1545+
"Failed to execute `{command}`":
1546+
en: "Failed to execute `%{command}`"
1547+
"{name} is already running, can't update it now.":
1548+
en: "%{name} is already running, can't update it now."
1549+
"Skip due to following reasons: {py_err} {py3_err}":
1550+
en: "Skip due to following reasons: %{py_err} %{py3_err}"
1551+
"No version after '{bin_name}'":
1552+
en: "No version after '%{bin_name}'"
1553+
"Invalid version in Topgrade keep file at {}":
1554+
en: "Invalid version in Topgrade keep file at %{}"
1555+
"Too old {name} version to have update extensions command":
1556+
en: "Too old %{name} version to have update extensions command"
1557+
"Failed to update .NET package {package_name:?}":
1558+
en: "Failed to update .NET package %{package_name}"
1559+
"Failed to parse `tmux_arguments`: `{args}`":
1560+
en: "Failed to parse `tmux_arguments`: `%{args}`"
1561+
"Yarn root at {} doesn't exist":
1562+
en: "Yarn root at %{} doesn't exist"
1563+
"{} root at {} doesn't exist":
1564+
en: "%{} root at %{} doesn't exist"
1565+
"{} exists but empty":
1566+
en: "%{} exists but empty"
1567+
"Failed to canonicalize {profile_dir:?}":
1568+
en: "Failed to canonicalize %{profile_dir}"
1569+
"Failed to read symlink {profile_dir:?}":
1570+
en: "Failed to read symlink %{profile_dir}"
1571+
"SDIO driver updates are disabled. Enable with 'enable_sdio = true' in [windows] section":
1572+
en: "SDIO driver updates are disabled. Enable with 'enable_sdio = true' in [windows] section"
1573+
lt: "SDIO tvarkyklių atnaujinimai išjungti. Įjunkite su 'enable_sdio = true' [windows] sekcijoje"
1574+
es: "Las actualizaciones de controladores SDIO están deshabilitadas. Habilite con 'enable_sdio = true' en la sección [windows]"
1575+
fr: "Les mises à jour des pilotes SDIO sont désactivées. Activez avec 'enable_sdio = true' dans la section [windows]"
1576+
zh_CN: "SDIO 驱动程序更新已禁用。在 [windows] 部分使用 'enable_sdio = true' 启用"
1577+
zh_TW: "SDIO 驅動程式更新已停用。在 [windows] 部分使用 'enable_sdio = true' 啟用"
1578+
de: "SDIO-Treiberupdates sind deaktiviert. Mit 'enable_sdio = true' im Abschnitt [windows] aktivieren"
1579+
"SDIO (Snappy Driver Installer Origin) not found":
1580+
en: "SDIO (Snappy Driver Installer Origin) not found"
1581+
lt: "SDIO (Snappy Driver Installer Origin) nerastas"
1582+
es: "SDIO (Snappy Driver Installer Origin) no encontrado"
1583+
fr: "SDIO (Snappy Driver Installer Origin) introuvable"
1584+
zh_CN: "未找到 SDIO (Snappy Driver Installer Origin)"
1585+
zh_TW: "找不到 SDIO (Snappy Driver Installer Origin)"
1586+
de: "SDIO (Snappy Driver Installer Origin) nicht gefunden"
1587+
"Snappy Driver Installer Origin":
1588+
en: "Snappy Driver Installer Origin"
1589+
lt: "Snappy Driver Installer Origin"
1590+
es: "Snappy Driver Installer Origin"
1591+
fr: "Snappy Driver Installer Origin"
1592+
zh_CN: "Snappy Driver Installer Origin"
1593+
zh_TW: "Snappy Driver Installer Origin"
1594+
de: "Snappy Driver Installer Origin"
1595+
"Running SDIO dry-run analysis...":
1596+
en: "Running SDIO dry-run analysis..."
1597+
lt: "Running SDIO dry-run analysis..."
1598+
es: "Running SDIO dry-run analysis..."
1599+
fr: "Running SDIO dry-run analysis..."
1600+
zh_CN: "Running SDIO dry-run analysis..."
1601+
zh_TW: "Running SDIO dry-run analysis..."
1602+
de: "Running SDIO dry-run analysis..."
1603+
"Running SDIO analysis...":
1604+
en: "Running SDIO analysis..."
1605+
lt: "Running SDIO analysis..."
1606+
es: "Running SDIO analysis..."
1607+
fr: "Running SDIO analysis..."
1608+
zh_CN: "Running SDIO analysis..."
1609+
zh_TW: "Running SDIO analysis..."
1610+
de: "Running SDIO analysis..."
1611+
"Running SDIO automatic installation...":
1612+
en: "Running SDIO automatic installation..."
1613+
lt: "Running SDIO automatic installation..."
1614+
es: "Running SDIO automatic installation..."
1615+
fr: "Running SDIO automatic installation..."
1616+
zh_CN: "Running SDIO automatic installation..."
1617+
zh_TW: "Running SDIO automatic installation..."
1618+
de: "Running SDIO automatic installation..."
1619+
"Running SDIO installation...":
1620+
en: "Running SDIO installation..."
1621+
lt: "Running SDIO installation..."
1622+
es: "Running SDIO installation..."
1623+
fr: "Running SDIO installation..."
1624+
zh_CN: "Running SDIO installation..."
1625+
zh_TW: "Running SDIO installation..."
1626+
de: "Running SDIO installation..."
1627+
"SDIO dry-run analysis complete.":
1628+
en: "SDIO dry-run analysis complete."
1629+
lt: "SDIO dry-run analysis complete."
1630+
es: "SDIO dry-run analysis complete."
1631+
fr: "SDIO dry-run analysis complete."
1632+
zh_CN: "SDIO dry-run analysis complete."
1633+
zh_TW: "SDIO dry-run analysis complete."
1634+
de: "SDIO dry-run analysis complete."
1635+
"SDIO analysis complete.":
1636+
en: "SDIO analysis complete."
1637+
lt: "SDIO analysis complete."
1638+
es: "SDIO analysis complete."
1639+
fr: "SDIO analysis complete."
1640+
zh_CN: "SDIO analysis complete."
1641+
zh_TW: "SDIO analysis complete."
1642+
de: "SDIO analysis complete."
1643+
"SDIO automatic installation complete.":
1644+
en: "SDIO automatic installation complete."
1645+
lt: "SDIO automatic installation complete."
1646+
es: "SDIO automatic installation complete."
1647+
fr: "SDIO automatic installation complete."
1648+
zh_CN: "SDIO automatic installation complete."
1649+
zh_TW: "SDIO automatic installation complete."
1650+
de: "SDIO automatic installation complete."
1651+
"SDIO installation complete.":
1652+
en: "SDIO installation complete."
1653+
lt: "SDIO installation complete."
1654+
es: "SDIO installation complete."
1655+
fr: "SDIO installation complete."
1656+
zh_CN: "SDIO installation complete."
1657+
zh_TW: "SDIO installation complete."
1658+
de: "SDIO installation complete."
1659+
"SDIO analysis found no drivers to install; keeping this run in analysis mode.":
1660+
en: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1661+
lt: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1662+
es: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1663+
fr: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1664+
zh_CN: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1665+
zh_TW: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1666+
de: "SDIO analysis found no drivers to install; keeping this run in analysis mode."
1667+
"Proceed to install selected drivers now? This will create a restore point first. (y/N)":
1668+
en: "Proceed to install selected drivers now? This will create a restore point first. (y/N)"
1669+
lt: "Ar norite dabar įdiegti pasirinktus tvarkykles? Pirmiausia bus sukurta atkūrimo taškas. (y/N)"
1670+
es: "¿Desea instalar los controladores seleccionados ahora? Primero se creará un punto de restauración. (y/N)"
1671+
fr: "Procéder à l'installation des pilotes sélectionnés maintenant ? Un point de restauration sera créé d'abord. (y/N)"
1672+
zh_CN: "现在安装所选驱动程序吗?将首先创建一个还原点。(y/N)"
1673+
zh_TW: "現在要安裝所選的驅動程式嗎?將先建立還原點。(y/N)"
1674+
de: "Ausgewählte Treiber jetzt installieren? Zuerst wird ein Wiederherstellungspunkt erstellt. (y/N)"

0 commit comments

Comments
 (0)