3 个不稳定版本
使用旧的 Rust 2015
0.2.1 | 2022年10月2日 |
---|---|
0.2.0 | 2019年4月10日 |
0.1.0 | 2018年6月21日 |
#1023 在 网络编程
在 tarssh 中使用
19KB
318 行
rusty-sandbox
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请求!
通过参与此项目,您同意遵守贡献者行为准则。
许可证
这是一款免费且无约束的软件,已发布到公共领域。
更多信息,请参阅UNLICENSE
文件或unlicense.org。
依赖项
~92KB