Security breach with Rust macros

I don't have much to add to this specific issue, expect that I think the reasoning of "Sandboxing X is pointless because we do the same with Y" is wrong. While we can come up with specific counter-examples (eg a CI that compiles builds but doesn't run them), they're a tangent from the main point (and most of them are contrived anyway).

I think we should reason in terms of "what is the minimum level of information this system needs to do X, and how do we provide that information and nothing else?". Restricting the build process to only the information it strictly needs doesn't just help with security; it helps with caching, build reproducibility, debugging, etc.

We've mentioned compiling macros to WebAssembly; doing so would help sandboxing, but this is true the other way around too: having defined sandboxing rules would help having a "compile macros to WebAssembly" pipeline, which could have reduce initial build times (which, at the very least, is useful for CI).

2 Likes

I agree that sandboxing as an option for the command line makes sense, although it isn't something we've done yet.

My basic point is just that this is an issue that we've encountered and made some particular choices which have seemed to work well so far.

Maybe "modern" (read: not) filesystems are the wrong abstraction, and a capability-based, ownership-based filesystem (think stacked borrows, not Windows) would be the way to go?

Many people would like to use Rust on existing filesystems, so this doesn't seem very related to the current topic.

9 Likes

The data structure used and the security model used for file systems are orthogonal concerns. I agree that capability based security is a better approach compared to ACLs. WASI is an example of such an approach.

ownership, stacked borrows, provenance together make a pretty nice capability based system, all it needs is to be enforced somewhere.

... altho unfortunately rust's filesystem APIs don't support such a model, we guess. it would have benefits beyond just security: it'd also help with unintended corruption like trying to backup a live DB by copying its files over, vs using filesystem-level snapshots.

Stacked Borrows and provenance are not designed as security mechanisms; I very much doubt you will get useful results trying to shoehorn them into one.

6 Likes

...but the final binaries may be running via something like Flatpak, with locked-down permissions, which then makes the ability to execute code at compile time a much more appealing target, proportionally.

Were I designing a system to retrofit onto Cargo, I'd probably start the brainstorming with something analogous to how wax grants $PWD by default when you use it to run WASI apps.

Something like "Cargo sandboxes compilation to the directory containing Cargo.toml by default, with either blacklisting (separate file) or forced read-only (Cargo.toml) on any files which could be used/abused to loosen the security back up again, assuming that "build artifacts will always be executed in another sandbox" paradigm.

That default would also help to catch dependencies on out-of-repository things before you git push.

1 Like

I use target as a symlink to an off-partition location (to keep build artifacts from across my machine in one place for easy exclusion in backups). I'd like that to continue working at least, so some considerations that other locations are suitable is fine. In order to allow this to work, I'm much more OK with a global cargo configuration for something like this than a per-repo one (though I suppose it wouldn't be impossible to keep a local patch, hopefully it is in a file that is never expected to be committed since this setup is my business and no one else's).

Fair enough. Maybe use .cargo/config and its fallback chain to achieve that, and force read-only access on any detected .cargo/config locations inside the whitelisted portion of the filesystem.

Also $CARGO_TARGET_DIR, which I have set to a shared location as a simple compilation sharing cache with less moving parts than sccache