Skip to content

Latest commit

 

History

History
578 lines (483 loc) · 29.9 KB

File metadata and controls

578 lines (483 loc) · 29.9 KB

tokimo-package-sandbox

License: MIT

跨平台原生沙箱库 —— 在隔离环境中运行不受信任的命令。一套 API,三个平台,每个平台使用操作系统原生的隔离原语。

平台 隔离引擎 需要 root 备注
Linux (ch) Cloud Hypervisor 微型虚拟机 (KVM) + virtiofsd + smoltcp 用户态网络栈 不需要(用户需在 kvm 组中) /dev/kvm + /dev/vhost-vsock + cloud-hypervisor 二进制可用时优先选择
Linux (bwrap) bubblewrap(用户命名空间)+ smoltcp 用户态网络栈 不需要 CH 不可用时自动回退;~50 ms 启动,无虚拟机
macOS Apple Virtualization.framework → Linux 微型虚拟机 + smoltcp 用户态网络栈 不需要 ~2 s 冷启动
Windows Hyper-V HCS → Linux 微型虚拟机 + smoltcp 用户态网络栈(SYSTEM 服务) 一次性服务安装 ~600 ms

所有后端提供完全相同的 Sandbox 接口:configure → create → start → spawn shells → stop。同一个 init 二进制(tokimo-sandbox-init)在每个沙箱中以 PID 1(bwrap 中为 PID 2)运行,使用相同的线路协议,不区分传输层。网络完全统一:所有后端的 AllowAll 策略均使用同一套 smoltcp 用户态网络栈。

Linux 后端选择SANDBOX_BACKEND 环境变量):

取值 行为
(未设)/ auto 先探测 ch;不可用时优雅地回退到 bwrap
ch 强制使用 Cloud Hypervisor;不可用直接报错(不回退)。
bwrap 强制使用 bubblewrap;不可用报错。
disabled 拒绝构造任何后端。

Sandbox::active_backend() 返回运行时实际选中的具体后端,便于调用方 / CI 日志确认走的是哪条路径。

为什么做这个项目

现有的沙箱方案要么是平台专属的(bwrap、jail、WSL),要么需要守护进程和镜像(Docker、Podman)。没有一个开源库能让你用一套 Rust API 在 Linux、macOS 和 Windows 上沙箱化一条命令——还要有可用的网络、PTY 支持和动态宿主↔客机文件共享——而不需要 root、Docker 或预构建的容器镜像。

这个项目填补了这个空白。

架构

┌─────────────────────────────────────────────────────────────┐
│                      你的应用程序                             │
│                                                             │
│   let sb = Sandbox::connect().unwrap();                     │
│   sb.configure(params).unwrap();                            │
│   sb.start_vm().unwrap();                                   │
│   let shell = sb.shell_id().unwrap();                       │
│   sb.write_stdin(&shell, b"uname -a\n").unwrap();           │
│   sb.stop_vm().unwrap();                                    │
└────────────────────────┬────────────────────────────────────┘
                         │  各平台完全相同的 API
        ┌────────────────┼─────────────────────┬────────────────┐
        ▼                                      ▼                ▼
   LinuxBackend  ── Auto:ch → bwrap         MacosBackend   WindowsBackend
   (进程内;connect() 时决定)              (进程内)      (命名管道 RPC)
        │                                       │                │
        ├── ChBackend  ── cloud-hypervisor      ▼                ▼
        │   (KVM 微型虚拟机、virtiofsd、    arcbox-vz →     tokimo-sandbox-svc
        │    hybrid-vsock UDS)             VZVirtualMachine    (SYSTEM 服务)
        │                                       │                │
        └── BwrapBackend                        │                │
            (bubblewrap 用户命名空间)         │                │
                  │                             │                ▼
                  │                             │          Hyper-V HCS
                  └────────────┬────────────────┘                │
                               ▼                                 ▼
                      tokimo-sandbox-init                 Linux 微型虚拟机
                      (PID 1,共享二进制)              (HvSocket 传输)
                               │
                               ▼
                          Linux 客机

Linux —— 双后端,同一套 API

Linux 平台层会在 Sandbox::connect() 时探测 Cloud Hypervisor,并选择当前主机上能用且最强的后端。CH 优先(真实 KVM 隔离、完整内核边界、与 macOS/Windows 等价的安全姿态);bwrap 是回退(无虚拟机、启动最快、能在没有 /dev/kvm 的环境下工作,例如未开启虚拟化的嵌套 CI)。

两个后端除了隔离原语之外完全共享:同一个 tokimo-sandbox-init PID 1 二进制、同一套 FuseHost/tokimo-sandbox-fuse FUSE 基础设施、同一个 smoltcp 网络栈、同一份协议帧。仅传输层接线不同(SEQPACKET socketpair vs. hybrid-vsock UDS sidecar)。

Linux —— Cloud Hypervisor(ch 后端)

Sandbox::start_vm()
  │
  ├─ probe_ch() ✅  (/dev/kvm + /dev/vhost-vsock + cloud-hypervisor + virtiofsd)
  │
  ├─ 启动 cloud-hypervisor 子进程:
  │      --kernel  vmlinuz                  ← 与 crate 版本配对发布
  │      --initramfs initrd.img
  │      --cmdline "... tokimo.guest_listens=0 tokimo.init_port=2222 ..."
  │      --memory size=<MB>                 ← 来自 ConfigureParams
  │      --cpus boot=<N>
  │      --vsock cid=3,socket=<vsock_uds>   ← hybrid-vsock;每端口一个 UDS sidecar
  │      --fs tag=<mount_name>,socket=<virtiofsd.sock>  ← 每个共享一份
  │      [--net tap=...]                    ← 仅 AllowAll
  │
  ├─ 启动 virtiofsd 子进程(每个 ConfigureParams.mount 一个):
  │      --shared-dir <host_path>
  │      --socket-path <virtiofsd.sock>
  │      [--readonly] [--sandbox=none|chroot]
  │
  └─ 宿主侧 hybrid-vsock UDS sidecar (`<vsock_uds>_<port>`) 上的监听器:
        port 2222 → init 控制通道
        port 4444 → smoltcp 网络栈 RX/TX
        port 5555 → FuseHost(进程内 FUSE-over-vsock)
  • 无守护进程、无服务、不需要 root。 每个 Sandbox 拥有独立的 cloud-hypervisor + virtiofsd 进程组。
  • 与 macOS/Windows 同一套打包内核 + initrd + rootfsvm-kernel-* + vm-rootfs-* tag artifact)。
  • vsock 传输 使用 CH 的 hybrid-vsock —— 宿主以监听每端口 UDS(<vsock_uds>_<port>)的方式扮演 vsock,而不是用 /dev/vhost-vsock。四个通道(init、网络栈、FUSE、控制台)全部由客机发起(tokimo.guest_listens=0)。
  • 文件共享 ConfigureParams 中声明的挂载使用 virtiofsd(CH 的天然原语),不走 FUSE-over-vsock。运行时 add_mount 仍然通过同一份 FuseHost 走 FUSE-over-vsock。
  • 网络: AllowAll 与其他后端使用同一套 smoltcp 用户态网络栈。Blocked 直接省略网卡。
  • PTY: 主 fd 留在客机;init 通过协议事件(vsock)桥接 I/O。

Linux —— bubblewrap(bwrap 后端)

Sandbox::start_vm()
  │
  ├─ socketpair(AF_UNIX, SOCK_SEQPACKET)     ← init 控制通道
  ├─ socketpair(AF_UNIX, SOCK_STREAM)         ← 网络栈(仅 AllowAll)
  │
  └─ exec bwrap --unshare-user --unshare-pid --unshare-ipc --unshare-uts
                 --unshare-net                ← 始终:全新网络命名空间
                 --ro-bind <.vm/base/rootfs>/{usr,bin,sbin,lib,lib64}
                 --ro-bind <.vm/base/rootfs>/etc/{passwd,group}     ← 打包的用户表
                 --ro-bind /etc/{resolv.conf,hosts,ssl,...}   ← 仅宿主网络/CA
                 --cap-add CAP_SYS_ADMIN      ← fusermount3 需要
                 --cap-add CAP_NET_ADMIN      ← 用于 TAP 和 lo 启动
                 --cap-add CAP_NET_RAW        ← 客机 ping 需要
                 --cap-add CAP_MKNOD          ← 回退 TUN 节点创建
                 --dev-bind-try /dev/net/tun  ← 仅 AllowAll
                 -- /path/to/tokimo-sandbox-init bwrap
                        --control-fd=<ctrl>
                        --net-fd=<net>        ← 仅 AllowAll
                        --bringup-lo --mount-sysfs
                              │
                              └─ bwrap 内 PID 2(bwrap 是 PID 1)
                                 ├─ 控制:SEQPACKET,PTY 通过 SCM_RIGHTS 传递
                                 ├─ 网络:STREAM,TAP tk0 ↔ 宿主 smoltcp
                                 └─ FUSE:每个挂载一个 socketpair,宿主 FuseHost 服务
  • 无守护进程、无服务、不需要 root。 每个 Sandbox 拥有独立的 bwrap+init 组合。
  • 打包 rootfs。 /usr /bin /sbin /lib /lib64 /etc/passwd /etc/group 都来自 .vm/base/rootfs/(与 macOS、Windows 启动用的同一份 artifact),保证三平台 sandbox 内看到同一套工具版本。仅网络/DNS/CA 配置仍从宿主机绑定。
  • 网络: AllowAllBlocked 都使用 --unshare-net 创建全新网络命名空间。AllowAll 通过 TAP 设备(tk0)叠加 smoltcp 用户态网络栈,经 STREAM socketpair 桥接到宿主——与 macOS 和 Windows 架构完全一致。Blocked 只有 lo
  • 文件共享: 所有挂载使用 FUSE-over-socketpair —— 与 macOS 和 Windows 共同一套 FuseHost + tokimo-sandbox-fuse 基础设施。每个挂载获得一个 AF_UNIX SOCK_STREAM socketpair;宿主端由 FuseHost 服务,客机端通过 --transport unix-fd 传递给 tokimo-sandbox-fuse。启动时和运行时挂载使用相同机制。
  • PTY: 主 fd 通过 SCM_RIGHTS 传递到宿主,直接 I/O。

macOS — Virtualization.framework

Sandbox::start_vm()
  │
  └─ arcbox-vz → VZVirtualMachine
       ├─ VZLinuxBootLoader(vmlinuz, initrd.img)
       ├─ VZVirtioFileSystemDevice  tag="rootfs"       ← rootfs(只读)
       ├─ VZVirtioSocketDevice      port=2222          ← init 控制通道
       ├─ VZVirtioSocketDevice      port=4444          ← 用户态网络栈
       ├─ VZVirtioSocketDevice      port=5555          ← FUSE-over-vsock 宿主
       └─ VZNetworkDeviceConfiguration::nat()          ← 仅 AllowAll
            │
            └─ Linux 微型虚拟机(arm64)
                 tokimo-sandbox-init(PID 1)通过 virtio-vsock 通信
  • 无服务、不需要 root。 纯库调用;每个 Sandbox 启动自己的虚拟机。
  • 共享文件系统: 所有挂载使用 FUSE-over-vsock —— 宿主在 vsock 端口 5555 上运行进程内 FuseHost,每个挂载在客机中启动一个 tokimo-sandbox-fuse 子进程通过 vsock 连回。与 Linux 和 Windows 共同一套基础设施。
  • 网络: AllowAll 使用宿主侧 smoltcp 用户态网络栈(vsock 传输)。Blocked 从虚拟机配置中省略网络设备。
  • PTY: 主 fd 留在客机中;init 通过协议 Stdout/Write 事件桥接 I/O。

Windows — Hyper-V HCS

Sandbox(库) ──命名管道──▶ tokimo-sandbox-svc.exe(SYSTEM)
                                │
                                ├─ HCS 计算系统(Schema 2.5)
                                │    ├─ LinuxKernelDirect(vmlinuz, initrd)
                                │    ├─ SCSI:每会话 rootfs.vhdx
                                │    ├─ FUSE-over-vsock(用户挂载)
                                │    └─ HvSocket ServiceTable
                                │
                                ├─ AF_HYPERV 监听器(每会话 GUID)
                                │
                                └─ smoltcp 用户态网络栈
                                     │
                                     └─ NAT → 宿主网络
  • SYSTEM 服务代表非特权用户管理虚拟机。通过 sudo ... --install 或 MSIX 一次性安装。
  • 每会话隔离: 每个会话获得独立的 VHDX 克隆和 HvSocket 服务 GUID,支持并发会话。
  • 网络: AllowAll 使用与 macOS 相同的 smoltcp 用户态网络栈Blocked 在内核参数中设置 tokimo.net=blocked
  • PTY: 与 macOS 相同——主 fd 留在客机,I/O 通过协议桥接。

用户态网络栈

所有后端的 AllowAll 策略使用同一套 smoltcp L3/L4 代理src/net/netstack/)。一套统一的网络栈,一个拦截点,不区分平台或 Linux 后端。

Linux 客机内核
  │ 以太网帧
  │   Linux bwrap:通过 TAP tk0 → STREAM socketpair
  │   Linux ch:   通过 TAP tk0 → vsock UDS sidecar
  │   macOS:      通过 virtio-vsock
  │   Windows:    通过 HvSocket
  ▼
StreamDevice(smoltcp,宿主侧)
  │
  ├─ TCP:smoltcp socket → 宿主 TcpStream::connect() → 双向代理
  ├─ UDP:smoltcp socket → 宿主 UdpSocket → 手动构造以太网回复帧
  └─ ICMP:解析 EchoRequest → 平台特定 send_echo → 构造 EchoReply
  • 所有后端统一 —— Linux bwrap(TAP + socketpair)、Linux ch(TAP + vsock)、macOS(vsock)、Windows(HvSocket)
  • 双栈 IPv4/IPv6,支持扩展头遍历(HopByHop、Route、Opts、Frag)
  • 子网: 192.168.127.0/24(v4)、fd00:7f::/64(v6),MTU 1400
  • 3 线程: RX 读取(传输层 → smoltcp)、主轮询循环、TX 写入(smoltcp → 传输层)
  • 120 秒空闲超时(每流)

共享 init 二进制

tokimo-sandbox-init 是一个 Rust 二进制,在每个沙箱中以 PID 1(或 bwrap 中的 PID 2)运行。启动时自动检测传输层:

传输层 使用者 PTY 机制
SOCK_SEQPACKET(继承 fd) Linux bwrap SCM_RIGHTS fd 传递
SOCK_SEQPACKET(监听器) Linux 独立模式 SCM_RIGHTS fd 传递
VSOCK 流(客机连接) Linux ch(hybrid-vsock) 协议桥接(Stdout/Write 事件)
VSOCK 流(客机监听) macOS VZ 协议桥接(Stdout/Write 事件)
VSOCK 流(客机连接) Windows HCS 协议桥接(Stdout/Write 事件)

能力:PipesPty stdio 模式、ResizeSignalKillpgOpenShellMountFuse/UnmountFuse(FUSE-over-vsock/socketpair)。

快速开始

[dependencies]
tokimo-package-sandbox = "0.1"
use tokimo_package_sandbox::{Sandbox, ConfigureParams, NetworkPolicy};

let sb = Sandbox::connect().unwrap();
sb.configure(ConfigureParams {
    user_data_name: "demo".into(),
    memory_mb: 4096,
    cpu_count: 4,
    network: NetworkPolicy::AllowAll,
    ..Default::default()
}).unwrap();

sb.create_vm().unwrap();
sb.start_vm().unwrap();

let shell = sb.shell_id().unwrap();
sb.write_stdin(&shell, b"uname -a\n").unwrap();
// ... 通过 sb.subscribe() 读取事件 ...

sb.stop_vm().unwrap();

前置条件

平台 要求
Linux bwrap 后端:sudo apt install bubblewrapch 后端:需要 cloud-hypervisor + virtiofsd 二进制在 PATH 上(或位于 bin/cloud-hypervisor/current/bin/bin/virtiofsd/current/),/dev/kvm/dev/vhost-vsock 可访问(通常需要用户在 kvm 组中)。需要 <repo>/.vm/base/ 下的虚拟机产物。两种后端运行时都不需要 root。
macOS macOS 13+,Apple Silicon。需要 <repo>/.vm/base/ 下的虚拟机产物(见下方)。代码签名需要 com.apple.security.virtualization 权限。
Windows 启用"虚拟机平台"(Win 10 1903+)。一次性 sudo 安装服务。需要 <repo>/.vm/base/ 下的虚拟机产物。

虚拟机产物(所有平台)

三个后端共享同一套 Linux 内核 + initrd + Debian 13 rootfs。内核+initrd 与 rootfs 通过两个独立 tag 系统发布:vm-kernel-* 跟随 host crate 版本,vm-rootfs-* 很少重发。下载:

# Linux / WSL
scripts/linux/fetch-vm.sh                                              # 最新发布
scripts/linux/fetch-vm.sh -k vm-kernel-1.0.0 -r vm-rootfs-1.0.0       # 指定标签
# Windows
pwsh scripts/windows/fetch-vm.ps1                                                       # 最新发布
pwsh scripts/windows/fetch-vm.ps1 -KernelTag vm-kernel-1.0.0 -RootfsTag vm-rootfs-1.0.0

macOS 本地构建:

scripts/macos/build-vm-local.sh              # arm64(默认)

本地 rebake initrd(修改 init.sh 或 guest 二进制后)

发布的 initrd 由 CI (vm.ymlbuild.sh) 构建,是 kernel + modules

  • rootfs 的唯一权威来源。当你在迭代 init.sh 或三个 musl 业务二进制 (tokimo-sandbox-inittokimo-tun-pumptokimo-sandbox-fuse)时, 不需要重跑完整流水线,只需把它们换进发布版 initrd 的副本:
# Linux
scripts/linux/rebake-initrd.sh --install-to-vm

# macOS(exec 上面那个 — guest 二进制始终是 Linux musl)
scripts/macos/rebake-initrd.sh --install-to-vm
# Windows(pwsh → wsl bash 上面那个)
pwsh scripts/windows/rebake-initrd.ps1 -InstallToVm

三个入口接受同一组 flag:--skip-build--install-to-vm--arch amd64|arm64--base <path>。Rebake 永远不会动 /modules/ —— 内核模块从 CI 出来时 vermagic 已与 vmlinuz 严格匹配,脚本最后会对 刚生成的 initrd 跑 vermagic 自检确认。

macOS 代码签名

在本地 .cargo/config.toml 中注册签名 cargo runner:

[target.aarch64-apple-darwin]
runner = "scripts/macos/codesign-and-run.sh"

Windows 服务

# 开发 — 前台运行,无 SCM
sudo cargo run --bin tokimo-sandbox-svc -- --console

# 开发 — 持久化 SCM 服务(sudo)
sudo .\target\debug\tokimo-sandbox-svc.exe --install

# 生产 — MSIX
pwsh scripts/windows/build-msix.ps1

沙箱内有什么

所有平台运行相同的 Debian 13(Trixie)Linux rootfs

类别 内容
运行时 Node.js 24、Python 3.13、Lua 5.4
编辑器 vim、nano
办公/文档 pandoc、libreoffice(headless)、poppler、qpdf、tesseract-ocr
Python pypdf、pdfplumber、reportlab、pandas、openpyxl、markitdown、ipython、requests、rich、Pillow
Node.js pnpm、docx、pptxgenjs
媒体 ffmpeg
网络 curl、wget、dig、ping、rsync、git
其他 jq、zstd、bash-completion

API

沙箱生命周期

let sb = Sandbox::connect()?;
sb.configure(ConfigureParams { .. })?;
sb.create_vm()?;      // Windows:HCS 计算系统;Linux/macOS:无操作
sb.start_vm()?;       // Linux:启动 bwrap;macOS:启动虚拟机;Windows:启动 HCS
sb.stop_vm()?;        // 销毁

Shell 控制

let shell = sb.shell_id()?;                          // 默认 shell
let job = sb.spawn_shell(ShellOpts { pty: Some((24, 80)), .. })?;  // PTY shell
sb.write_stdin(&shell, b"echo hello\n")?;
sb.resize_shell(&job, 40, 120)?;
sb.signal_shell(&job, Signal::SIGTERM)?;
sb.close_shell(&job)?;
let shells = sb.list_shells()?;

事件

let rx = sb.subscribe();
for event in rx {
    match event {
        Event::Stdout { id, data } => { /* stdout 字节 */ }
        Event::Stderr { id, data } => { /* stderr 字节 */ }
        Event::Exit { id, exit_code, signal } => { /* 进程退出 */ }
        Event::GuestConnected => { /* 客机 init 就绪 */ }
        _ => {}
    }
}

动态文件共享

sb.add_mount(Mount {
    name: "workspace".into(),
    host_path: "/tmp/my-project".into(),
    guest_path: "/workspace".into(),
    read_only: false,
})?;
// ... 客机可以访问 /workspace ...
sb.remove_mount("workspace")?;

测试

34 个集成测试,通过公共 Sandbox API 测试真实客机。平台无关的源码;同一套测试在三个平台上运行。

# Linux —— bwrap 后端
sudo apt install bubblewrap
cargo build --bin tokimo-sandbox-init
SANDBOX_BACKEND=bwrap PATH="$PWD/target/debug:$PATH" \
    cargo test --test sandbox_integration -- --test-threads=1

# Linux —— ch 后端(KVM 微型虚拟机;需要 cloud-hypervisor + virtiofsd + /dev/kvm)
SANDBOX_BACKEND=ch PATH="$PWD/target/debug:$PATH" \
    cargo test --test sandbox_integration -- --test-threads=1

# macOS
cargo test --test sandbox_integration -- --test-threads=1

# Windows(sudo,服务运行中)
sudo cargo test --test sandbox_integration -- --nocapture

Linux(bwrap 用户命名空间速率限制;CH 启动序列化)和 macOS(VZ 调度队列串行化虚拟机启动)必须使用 --test-threads=1。Windows 支持并发。

覆盖范围:生命周期、Shell I/O、多 Shell 流 + 信号 + 枚举、PTY 大小/调整/ctrl-c/转义序列、FUSE 挂载添加/移除、网络 blocked/allow-all/ICMPv4/ICMPv6/IPv6 TCP、多会话并发。

单元测试:cargo test --lib(会话注册表、协议、服务内部)。

示例

# 沙箱内交互式 PTY shell
cargo run --example pty_shell

# smoltcp 网络栈独立演示(无虚拟机的 TCP + UDP 代理)
cargo run --example smoltcp_netstack

源码布局

src/
├── lib.rs                        Crate 根:7 个顶层模块,向后兼容 re-export shim
│
├── api/                          公共 Sandbox API
│   ├── mod.rs                    Sandbox 句柄(~30 个方法)、ConfigureParams、ShellOpts、
│   │                             Mount、NetworkPolicy、Event、HostExecCtx/Action/Callback、
│   │                             JobId、SessionSummary/Details、PortForwardSpec
│   ├── backend.rs                SandboxBackend trait — 每平台实现契约
│   ├── backend_kind.rs           SandboxBackendKind(Auto/Disabled/Bwrap/Ch)、ActiveBackend
│   ├── error.rs                  Error 枚举 + Result 别名 + bail! 宏
│   └── platform.rs               每平台 default_backend()
│
├── backends/                     平台特定后端实现
│   ├── mod.rs                    条件编译:linux、macos、shared、svc_protocol、windows
│   ├── shared.rs                 SharedBackend<B> — 进程级会话共享(Linux/macOS)
│   ├── svc_protocol.rs           Windows 宿主 ↔ 服务 JSON-RPC 协议
│   ├── linux/
│   │   ├── bwrap/                bubblewrap 后端(无虚拟机,仅命名空间)
│   │   │   ├── sandbox.rs        LinuxBackend: SandboxBackend
│   │   │   ├── init_client.rs    InitClient(SOCK_SEQPACKET)
│   │   │   └── init_transport.rs SEQPACKET 帧 + SCM_RIGHTS
│   │   └── ch/                   Cloud Hypervisor 微型虚拟机后端
│   │       ├── backend.rs        ChBackend: SandboxBackend
│   │       ├── vmm.rs            CH + virtiofsd 子进程生命周期
│   │       └── probe.rs          probe_ch() — KVM/vsock/二进制可用性检查
│   ├── macos/
│   │   ├── sandbox.rs            MacosBackend: SandboxBackend
│   │   ├── vm.rs                 VZ 虚拟机生命周期、BOOT_LOCK
│   │   └── vsock_init_client.rs  VsockInitClient(VSOCK 传输)
│   └── windows/
│       ├── sandbox.rs            WindowsBackend: SandboxBackend(命名管道 JSON-RPC)
│       ├── client.rs             命名管道客户端
│       ├── init_client.rs        透明管道隧道上的 init 客户端
│       ├── init_transport.rs     Windows init 传输层适配
│       ├── ov_pipe.rs            OVERLAPPED Read/Write 封装
│       ├── safe_path.rs          TOCTOU 安全的 canonicalize_safe
│       └── ntfs_mode.rs          NTFS mode-bit 辅助函数
│
├── init/                         宿主侧 init 客户端 + 协议(所有后端共享)
│   ├── client/
│   │   ├── mod.rs                InitClient<S: TransportSend> — 泛型宿主侧客户端
│   │   └── vsock.rs              VSOCK 传输实现
│   └── protocol/
│       ├── types.rs              Frame、Op、Reply、Event、StdioMode
│       └── wire.rs               帧编解码、SEQPACKET + 流传输辅助
│
├── vfs/                          VFS 子系统(FUSE-over-vsock/socketpair)
│   ├── backend.rs                VfsBackend trait 层次结构 + VfsFileInfo
│   ├── protocol/
│   │   ├── mod.rs                VFS 线路协议:Frame、Req(~35 个操作)、Res、Errno
│   │   ├── wire.rs               长度前缀 postcard 帧 + bulk-bypass 优化
│   │   └── handshake.rs          Hello/HelloAck 握手
│   ├── host/
│   │   ├── mod.rs                FuseHost:accept 循环、每挂载分发
│   │   ├── id_table.rs           Nodeid + fh 分配器(带引用计数)
│   │   └── ops/                  每操作处理器:dir、file、meta、mutate、xattr
│   └── impls/
│       ├── local.rs              LocalDirVfs — 宿主目录透传
│       ├── mem.rs                MemFsVfs — 内存文件系统(测试用)
│       ├── meta.rs               meta_to_info() 辅助函数
│       ├── sanitize.rs           路径清理
│       └── macos_xattr.rs        macOS xattr 处理
│
├── net/                          网络
│   ├── constants.rs              共享拓扑常量(IP、MAC、子网、MTU)
│   ├── ifreq.rs                  Linux ioctl 辅助函数
│   └── netstack/
│       ├── mod.rs                用户态 smoltcp L3/L4 代理(~1750 行)
│       ├── host_dns.rs           宿主 DNS 解析器检测
│       └── icmp/                 平台特定 ICMP echo 后端
│
├── host_exec/                    Host-Exec 桥接(客机命令 → 宿主回调)
│   ├── mod.rs                    HostExecBridge、BridgeStream trait、handle_one()
│   ├── linux_relay.rs            SCM_RIGHTS 中继读取线程
│   ├── macos_listener.rs         vsock accept 循环
│   ├── transport.rs              传输层抽象
│   └── protocol/
│       ├── mod.rs                线路协议:Frame 枚举、版本 1
│       └── wire.rs               Postcard 帧封装
│
├── util/                         工具函数
│   ├── affinity.rs               CPU 亲和性辅助
│   ├── fonts.rs                  宿主字体目录发现
│   ├── raw_io.rs                 底层 I/O 辅助(Unix)
│   ├── rootfs_init.rs            Rootfs 初始化
│   ├── session_registry.rs       SessionRegistry(Windows 服务)
│   ├── vm_dir.rs                 虚拟机目录管理
│   └── vsock_util.rs             VSOCK 连接辅助(Linux)
│
└── bin/
    ├── tokimo-sandbox-init/      客机 PID 1 二进制(三平台共用)
    │   ├── main.rs               传输层分发、挂载设置、chroot
    │   ├── server.rs             主请求循环(mio::Poll)
    │   ├── child.rs              子进程管理
    │   ├── pty.rs                PTY 分配
    │   └── pump.rs               TUN ↔ vsock 桥接
    │
    ├── tokimo-sandbox-fuse/      客机侧 FUSE 桥接二进制
    │   └── main.rs               内核 FUSE 操作 → VFS 线路请求
    │
    ├── tokimo-sandbox-svc/       Windows SYSTEM 服务
    │   └── imp/
    │       ├── mod.rs            SCM 生命周期、管道服务器、会话处理
    │       ├── hcs.rs            ComputeCore.dll 加载器
    │       ├── hvsock.rs         AF_HYPERV socket 辅助
    │       ├── vmconfig.rs       HCS Schema 2.5 JSON 构建器
    │       ├── vhdx_pool.rs      每会话 VHDX 租赁
    │       ├── netstack.rs       smoltcp 用户态网络栈
    │       └── svclog.rs         日志
    │
    ├── tokimo-tun-pump/          客机侧 TUN ↔ vsock 桥接
    └── tokimo-host-exec/         客机侧 host-exec 桩

网络策略

策略 行为
AllowAll(默认) 通过 smoltcp 用户态网络栈 提供完整网络访问(所有后端)。Linux bwrap:TAP + socketpair。Linux ch:TAP + vsock。macOS:vsock。Windows:HvSocket。
Blocked 无网络。Linux bwrap:仅有 lo 的新网络命名空间。Linux ch:CH 配置中无网卡。macOS:虚拟机配置中无网卡。Windows:内核参数 tokimo.net=blocked

与 Docker 的对比

tokimo-package-sandbox Docker
守护进程 无(库调用;Windows 上为 SYSTEM 服务) 需要 dockerd
启动速度 ~50 ms(Linux)/ ~2 s 冷启动(macOS/Windows 虚拟机) ~1-3 s
Root 不需要(Linux/macOS) 通常需要
镜像 无(内置 Debian rootfs) 需要
API Rust 原生,Sandbox 句柄 CLI / REST
网络 统一 smoltcp 用户态网络栈(所有平台) bridge + iptables NAT
用途 "运行这条不受信任的命令" "部署这个服务栈"

许可证

MIT。见 LICENSE