agent-Specialization/scripts/setup-wsl-sandbox.ps1

93 lines
5.0 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# setup-wsl-sandbox.ps1 — 创建 astrion WSL2+bwrap 专用沙箱发行版
#
# 用法PowerShell普通用户即可无需管理员
# powershell -ExecutionPolicy Bypass -File scripts\setup-wsl-sandbox.ps1
# 可选参数:
# -DistroName 发行版名称(默认 astrion-sandbox需与 HOST_SANDBOX_WSL_DISTRO 一致)
# -InstallDir 发行版 VHDX 安装目录(默认 ~\.astrion\wsl-sandbox
# -RootfsUrl Alpine minirootfs 下载地址(默认阿里云镜像)
# -ApkMirror apk 软件源镜像(默认阿里云)
#
# 设计依据wsl2-sandbox-poc-report.md
# - 必须是专用发行版并关闭 interop否则沙箱内可经 cmd.exe 逃逸到宿主机;
# - 固化公共 DNS规避 localhost 代理导致的 WSL NAT DNS 失效;
# - 内置国内 apk 镜像,避免官方源大包下载卡死。
param(
[string]$DistroName = "astrion-sandbox",
[string]$InstallDir = (Join-Path $env:USERPROFILE ".astrion\wsl-sandbox"),
[string]$RootfsUrl = "https://mirrors.aliyun.com/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.3-x86_64.tar.gz",
[string]$ApkMirror = "https://mirrors.aliyun.com/alpine/v3.21"
)
$ErrorActionPreference = "Stop"
$env:WSL_UTF8 = "1"
function Invoke-Wsl {
param([Parameter(ValueFromRemainingArguments=$true)][string[]]$Args)
$output = & wsl.exe @Args 2>&1 | Where-Object { $_ -notmatch "localhost 代理|localhost proxy" }
return @{ Code = $LASTEXITCODE; Output = ($output -join "`n") }
}
Write-Host "==> [1/6] 检查 WSL 环境"
$null = Invoke-Wsl --status
if ($LASTEXITCODE -ne 0) {
throw "WSL 不可用。请先启用 WSL2wsl --install --no-distribution 或安装 Docker Desktop 后重试)。"
}
Write-Host "==> [2/6] 检查发行版 '$DistroName' 是否已存在"
$probe = Invoke-Wsl -d $DistroName -e true
if ($probe.Code -eq 0) {
Write-Host " 发行版已存在跳过导入如需重建wsl --unregister $DistroName"
} else {
Write-Host "==> [3/6] 下载 Alpine rootfs"
$rootfs = Join-Path $env:TEMP "astrion-alpine-minirootfs.tar.gz"
if (-not (Test-Path $rootfs)) {
Invoke-WebRequest -Uri $RootfsUrl -OutFile $rootfs -UseBasicParsing
}
Write-Host " rootfs: $rootfs ($([math]::Round((Get-Item $rootfs).Length/1MB,1)) MB)"
Write-Host "==> [4/6] 导入为 WSL2 发行版"
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
$null = Invoke-Wsl --import $DistroName $InstallDir $rootfs --version 2
$check = Invoke-Wsl -d $DistroName -e true
if ($check.Code -ne 0) { throw "发行版导入失败: $($check.Output)" }
}
Write-Host "==> [5/6] 写入沙箱配置(关闭 interop / 固定 DNS / 国内镜像)"
# 关闭 Windows 互操作:防止沙箱内经 cmd.exe 逃逸宿主机PoC 已验证该逃逸路径)
$null = Invoke-Wsl -d $DistroName -- sh -c "printf '[network]\ngenerateResolvConf = false\n\n[interop]\nenabled = false\nappendWindowsPath = false\n' > /etc/wsl.conf"
$null = Invoke-Wsl -d $DistroName -- sh -c "rm -f /etc/resolv.conf && printf 'nameserver 223.5.5.5\nnameserver 119.29.29.29\n' > /etc/resolv.conf"
$null = Invoke-Wsl -d $DistroName -- sh -c "printf '$ApkMirror/main\n$ApkMirror/community\n' > /etc/apk/repositories"
# 使 wsl.conf 生效
$null = Invoke-Wsl --terminate $DistroName
Start-Sleep -Seconds 2
Write-Host "==> [6/6] 安装沙箱工具链bubblewrap / bash / python3 / git"
$apk = Invoke-Wsl -d $DistroName -- sh -c "apk update && apk add bubblewrap bash ncurses-libs python3 git"
if ($apk.Code -ne 0) { throw "apk 安装失败: $($apk.Output)" }
# 与 Windows 端 Git for Windows 默认的 core.autocrlf=true 对齐:
# Windows 检出的工作区文件是 CRLF沙箱 git 不开 autocrlf 会把全部文件误判为已修改
# (全量 +/-),且全量内容读取+xdiff 会让 git 命令慢到触发执行超时。
$null = Invoke-Wsl -d $DistroName -e git config --system core.autocrlf true
# 9P 挂载的 inode/ctime 语义与 Windows git 写入的索引不匹配,会导致沙箱 git 对全部
# 文件做内容重读(全树 status/diff >20s放宽 stat 校验后只需秒级。
$null = Invoke-Wsl -d $DistroName -e git config --system core.checkStat minimal
$null = Invoke-Wsl -d $DistroName -e git config --system core.trustctime false
# 验收
$verify = Invoke-Wsl -d $DistroName -- sh -c "bwrap --version && bash -c 'echo bash-ok' && python3 --version && git --version"
Write-Host $verify.Output
$escape = Invoke-Wsl -d $DistroName -- bwrap --die-with-parent --new-session --unshare-all --ro-bind / / --proc /proc --dev /dev -- bash -c "cmd.exe /c echo escape 2>&1 || echo interop-blocked"
if ($escape.Output -match "interop-blocked|not found") {
Write-Host " interop 逃逸封堵验证: OK"
} else {
Write-Warning " interop 可能未关闭,请检查 /etc/wsl.conf 后执行 wsl --terminate $DistroName"
}
Write-Host ""
Write-Host "完成。沙箱发行版 '$DistroName' 就绪。"
Write-Host "若使用了非默认名称,请设置环境变量 HOST_SANDBOX_WSL_DISTRO=$DistroName"