3 个不稳定版本

使用旧的 Rust 2015

0.2.1 2022年10月2日
0.2.0 2019年4月10日
0.1.0 2018年6月21日

#1023网络编程


tarssh 中使用

Unlicense

19KB
318

rusty-sandbox unlicense

rusty-sandbox 显然是一个 Rust 的沙盒库,它不是 gaol

它基于一个简单的模型,在沙盒中可以进行以下操作

  • 任何正常计算(非 I/O)
  • 现有 文件描述符的 I/O 操作(即进入沙盒之前打开的文件和套接字)
  • 现有 套接字上接受连接(这将创建新的文件描述符)
  • 通过 Sandbox/SandboxContext API 在预先选择的目录下打开文件(这将创建新的文件描述符)

所有其他创建新文件描述符的方式都将失败!以及其他与外部世界可能危险交互的方式,如 sysctls、进程信号(kill)等。(平台相关)

底层技术

rusty-sandbox 强烈倾向于不需要任何持久和/或用户可见记录的简单沙盒功能(例如,类似于 gaol 在 Linux 上的 chroot 目录和绑定挂载)。

  • FreeBSD:最好的沙盒之一是 Capsicum,这是真正启发这个库设计的。
  • OpenBSD:pledge,遗憾的是仍然没有路径白名单功能(在选定目录下打开文件不起作用),等待 6.4 才能实现该功能
  • Apple OS X:Apple 希望废弃的 Seatbelt/sandboxd,我认为它可能更倾向于仅限 App Store 的内容?
  • Linux:待办。这将涉及 seccomp-bpf。不幸的是,在 capsicum-linux 上提出的 openat O_BENEATH 行为尚未被接受到 Linux 内核中!

用法

您可以沙盒当前进程

extern crate rusty_sandbox;
use std::fs;
use std::io::Read;
use rusty_sandbox::Sandbox;

fn main() {
    let mut file = fs::File::open("README.md").unwrap();
    Sandbox::new().sandbox_this_process().expect("Couldn't enter sandbox");
    let mut buf = Vec::new();
    file.read_to_end(&mut buf).unwrap();
    println!("Read file: {}", String::from_utf8_lossy(&buf));
    fs::File::open("README.md").expect("But can't open!");
    // on FreeBSD:
    // thread '<main>' panicked at 'But can't open!: Error { repr: Os { code: 94, message: "Not permitted in capability mode" } }', src/libcore/result.rs:760
}

以下是一个关于被分叉进程和允许的目录支持的示例。这个愚蠢的沙盒进程读取文件的第一个行

extern crate rusty_sandbox;
use std::io::{Write, BufRead, BufReader};
use rusty_sandbox::Sandbox;

fn main() {
    let mut process = Sandbox::new()
        .add_directory("repo", ".")
        .sandboxed_fork(|ctx, socket| {
            // This closure runs in a forked sandboxed process!
            let reader = BufReader::new(socket.try_clone().unwrap());
            for line in reader.lines() {
                let line = line.unwrap();
                if line == "" {
                    return;
                }
                // yes, this is an OpenOptions API!
                let file = ctx.directory("repo").unwrap()
                    .open_options().open(line).unwrap();
                socket.write_all(
                    BufReader::new(file).lines().next().unwrap().unwrap().as_bytes()
                ).unwrap();
                socket.write_all(b"\n").unwrap();
            }
        }).expect("Could not start the sandboxed process");
    process.socket.write_all(b"README.md\n").unwrap();
    let reader = BufReader::new(process.socket.try_clone().unwrap());
    println!("Line from the sandboxed process: {}", reader.lines().next().unwrap().unwrap());
    process.socket.write_all(b"\n").unwrap(); // The "stop" message
    process.wait().expect("Sandboxed process finished unsuccessfully");
}

(对于真实的服务,请使用类似 urpc 的工具!)

当然,在沙盒当前进程时,也可以使用目录功能

extern crate rusty_sandbox;
use std::io::Read;
use rusty_sandbox::Sandbox;

fn main() {
    let ctx = Sandbox::new()
        .add_directory("repo", ".")
        .sandbox_this_process()
        .unwrap();
    let mut file = ctx.directory("repo").unwrap()
        .open_options().open("README.md").unwrap();
    let mut buf = Vec::new();
    file.read_to_end(&mut buf).unwrap();
    println!("Read file: {}", String::from_utf8_lossy(&buf));
}

有趣的事实:这个库的早期原型使用了一个共享内存区域来进行进程间的通信,例如 sandblast配置解析器的沙箱。然而,在高于C语言级别的任何语言中,这都不实用,因为你不能简单地告诉语言的库在某个区域进行分配。

贡献

请随时提交pull请求!

通过参与此项目,您同意遵守贡献者行为准则

贡献者名单可在GitHub上找到。.

许可证

这是一款免费且无约束的软件,已发布到公共领域。
更多信息,请参阅UNLICENSE文件或unlicense.org

依赖项

~92KB