-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(sandbox): add -Zsandbox unstable flag #66
base: master
Are you sure you want to change the base?
Conversation
* `sandbox.runner`: Target platform sandboxed build scripts built for * `sandbox.target`: Runner that executes artifacts of build scripts Example config: ```toml [sandbox] target = "wasm32-wasip1" runner = [ "wasmtime", "--wasi", "inherit-env=y", "--dir", "/path/to/my/package", ] ```
Add support for `[sandbox]` to specify a target platform and a custom build script runner. To help the external runner finds and executes the executable produced by a build script, it is assumed that only one executable was produced.
e0889df
to
4ca4cd0
Compare
Hi, @weihanglo. I learned of this project from the the October project goals update. I wanted to make you aware of a related project
|
Hello @smoelius! |
👋 If you and/or Cargo folks are interested I'd be happy to chat in-depth about WASI/WebAssembly/etc things. I can also dump info here if that helps too! As a perhaps tl;dr; my overall read of the situation here (please correct me if I'm wrong) is that if WASI targets supported In any case though I'm also happy to attend a meeting if you or others would find that helpful too! |
If we just let a wasm script spawn processes that then run outside the sandbox, that seems pointless. So I don't see how the wasm-based approach here is supposed to work. |
Those spawn processes still run inside the sandbox I believe, just like other sockets and HTTP requests wasi proposals. The wasi runtime needs to provide an interface for granting/limiting what can be spawn. It is pretty hard to design a proper interface for that though. |
That requires a sandbox that can run actual binaries. If we have a sandbox that can run actual binaries (not just wasm code), we may as well build the build script the usual way and run it inside the sandbox. So at that point the use of wasm seems a bit pointless. |
As a WASI user, the way I'd imagine this working would be that all process spawning is denied by default, and there would be embedder-defined mechanisms for allow-listing spawning, e.g., specific external processes, possibly even with specific patterns of arguments. I don't have a lot of experience with writing interesting Rust build scripts, but I'd imagine this approach would cover the vast majority of Edit: to clarify, the advantage of this over, say, defining Cargo-specific Component Model interfaces, is that build scripts can still be written in Plain Old Rust, and as long as they're only calling out to a set of well-known external programs that are trusted-ish by Rust anyway, then they'll Just Work inside a Wasm sandbox. Any build scripts that try to do anything more exotic than that (e.g call Google's protoc) would fail. So then maybe we could have a mechanism for users to say "I'm okay with this crate's build script calling this external program" but deny by default in "paranoid mode". |
Personally I feel there's nuance that might be worth exploring here. Should arbitrary executables be allowed by default? Probably not. If the executables were themselves wasm, then probably so! As @jeffparsons mentions I'd also imagine a sort of allow-list style system which could also be in place. Alternatively if this isn't a security sandbox and is instead just a "hermetic build" style sandbox then it's perhaps totally ok to execute whatever so long as the build system can track the dependencies of the "whatever". Furthermore if the goal is to precompile build scripts to wasm then allowing arbitrary executables is totally fine. Basically if there is room to explore here (which I'd also completely understand if there isn't appetite for that or energy to explore) then I think it could be worth digging in to this more on the wasm side without immediately bouncing off on initial concerns |
IMO security is one of the main motivations for this -- being able to do check-builds of a project and open it in an IDE without having to worry about it exfiltrating secrets from my machine, or mutating any part of the filesystem outside the project folder. As someone who regularly tries to understand third-party libraries, which requires exploring their sourcecode, I would quite appreciate if that wouldn't require me to do manual sandboxing. :) (Note that in many cases I do not run these libraries nor their test suites, so I don't have to trust the generated code.) Sorry if this is going off-topic, I don't know what is the right place for the "general project discussion" here. |
What does this PR try to resolve?
This is an experiment for rust-lang/rust-project-goals#108.
An unstable
[sandbox]
config table is added behind the-Zsandbox
unstable flag:sandbox.runner
: Target platform sandboxed build scripts built forsandbox.target
: Runner that executes artifacts of build scriptsHere is an example
.cargo/config.toml
:Also an example
main.rs
:What did we achieve in this experiment?
As you can see, we can easily swap to any sandbox runner with a custom target.
We use
wasm32-wasip1
above as an example,as it is the one with smaller footprint, very cross-platform, and pretty popular in the Rust community.
However, it turns out that `wasm32-wasip1 doesn't support POSIX process spawning.
Use cases of process spawning in build scripts are essential, such as
pkg-config
to find system libraries.cargo metadata
to get crate metadata.git
.According to the design axioms,
Restrcting process spawning is the top one axiom.
We made that with
wasm32-wasip1
,but have no way to opt-out.
This contradicts to the "ensuring
-sys
crates be built" axiom.As a result, it is unlikely to use
wasm32-wasip1
as a default sandbox environment with this experiment.Other possibilities
Have talked to some other folks, there are some potential route we could take if we chose wasi as a default sandbox environment.
The offical
build-rs
crate to the rescueThe Cargo team recently adopted the
build-rs
crate.It is going to be the official crate providing API for writing build scripts.
We could take the advantage of it, telling everyone instead of using
std::process::Command
, use something likebuild_rs::Command
. So that Cargo could have a full control over how a build script spawning processes.While it sounds ideal, this doesn't help the current situation because
build-rs
in build scripts may increase build time; people may refuse to use.A Cargo-flavored wasi standard library
There was a discussion in the GSoC "sandboxed proc-macro with wasm" about shipping a custom verion of the standard library for sandboxed wasm. For Cargo's build script, we could potentially ship a
wasm32-wasi-cargo
target. The std in this custom target could intercept anyexec
call or process spawning. Then it calls back to the host process (which is Cargo in our case) to determine how to handle process execution. The host process could either reject, or run the external program and post back the result.This idea sounds pretty hacky and need more investigations of the communication mechanism between the host process and the wasm runtime. Perhaps via sockets, The WebAssembly Component Model, other host function call mechanism. There is also WASIX project which supprots
fork
/exec
though it is currently not a WASI standard not even a proposal.Continue with other more mature sandbox runtime choices
Since one of major design space is the user interafce of sandbox configuration,
we could leave off sandbox runtimes and explore more on the configuration side.
We could, for example, use docker or eBPF as a temporary default runtime, and explore how the configuration should look like.
We may want to take a look at the configuration of Cackle-rs as a starting point. By doing so, we wouldn't block on waiting for wasm runtime to being more mature.