ebkalderon / bastille

Process sandboxing library written in Rust
Apache License 2.0
7 stars 0 forks source link

noob/direction/scope questions #7

Open abathur opened 4 years ago

abathur commented 4 years ago

Stumbled on this last night while surveying nix files that use osxfuse. I don't have any first-hand rust experience, but I fumbled around until I figured out how to build and get the bash example working.

Cool stuff :)

  1. Do you plan on fully packaging this for Nix?

As part of a larger project focused on resolving external dependencies in shell scripts (with a focus on Nix/nixpkgs), I'm taking a little time to evaluate the feasibility of ~fuzzing scripts to search for external dependencies that haven't been resolved. I'm not sure what if any role this will play in the long-term project--it'll depend on how effective it is. If it's good enough, it'll probably be part of a validation/hardening mode that a user can run for a while.

I've got a decent bash implementation of this concept that I have made fairly safe, but there's still a risk of redirects in the file spewing unanticipated output into weird places and overwriting or appending something. So I've been looking for a good cross-platform sandbox that doesn't require me going too far down a rabbit-hole for a proof-of-concept. From what I've seen so far, bastille fits the bill. I've been using the Nix build sandbox for now to fill this need for now, but non-NixOS users don't have sandboxed builds by default, so it isn't a good "release" solution.

I'm also looking for the ability to log/track paths that the sandboxed script tries to read (and maybe write). It doesn't look like bastille or sandboxfs do this out-of-the-box.

  1. Do you see any sort of filesystem logging/eventing/callback/hook system as in-scope for bastille?
  2. If not, I'm still curious what you think about how feasible it is to compose this feature in/on?
ebkalderon commented 4 years ago

Hey there, @abathur! Thanks for the kind words and questions. ❤️ I'm pleasantly surprised anyone is looking at this repo at all.

Your project sounds really interesting, since dynamic detection of unsatisfied dependencies for programs using a sandbox and syscall tracing is something that I've been curious about for a while as well. I'd be interested to follow your own progress too, if you don't mind!

With that said, I would like to disclaim that this project is a personal experiment and learning exercise to create a cross-platform sandboxing abstraction which works on Linux and macOS first, and maybe support OpenBSD, FreeBSD and their related derivatives down the line. I think if you check the partially complete FEATURES.md table, you will see that feature-parity between even the first two platforms is all over the place. Linux appears to be the best supported platform for your use case by far, and it is the only platform that I know of capable of full container-like isolation without explicitly requiring dangerous levels of root and setuid access. macOS seems particularly terrible in this regard, considering that it lacks filesystem, network, PID, and user namespacing; doesn't have tmpfs; doesn't have bind mounting (though there exists an OSXFuse implementation which reportedly doesn't behave well on newer releases of macOS); and the best it can do for filesystem-level isolation is chroot + sandboxfs, which is quite awful for security-critical applications.

The main purpose of Bastille, at this stage, is to research the overall sandboxing landscape, determine what features each platform offers, and evaluate the possibility of creating a common abstraction between them. The projected outcome currently seems grim, but I'm still looking into it. I would like to make these caveats very clear before you choose to adopt Bastille for use in your own project.

With that out of the way, in response to your questions:

  1. Given that bastille is not a standalone binary, but rather a developer-facing Rust library intended for spawning tailor-made sandbox environments, I imagine it would be tricky to package up for Nix on its own. However, besides using nix-shell for local development and testing of Bastille, I was already considering shipping an example Rust binary called bastille-sandbox which would provide a convenient command-line interface for sandboxing arbitrary executables with Bastille. I would love to package this binary for Nix! 😄 Though it would depend on the aforementioned caveats being resolved, of course.
  2. Sure, it could definitely fall in scope if there exists sufficient cross-platform support. I'd love to add logging and syscall introspection features in Bastille! Though some questions still remain regarding what subset of features we can realistically support across platforms and how to best abstract over them.
  3. I believe you would be fully at the mercy of your respective OS's level of support. Syscall hooking is inherently a platform-specific operation, so if your desired kernel doesn't provide userspace programs with a satisfactory API for doing this, you might very well be SOL.
abathur commented 4 years ago

Thanks for the quick response. The perspective on your goals is helpful.

My main project is focused on using a parser to do as much of it statically as possible, but I think it's still worth exploring fuzzier approaches to the problem. If nothing else, it'll still help me validate the static approach, focus my effort on the most-valuable improvements, and understand if/when it outstrips what a dynamic approach can deliver.

I can use the static approach to object to many dynamic statements that seem like they may be commands, but I also have to strike a balance between making the user/packager verify a great many innocuous dynamic statements manually, and allowing some dependencies in dynamic statements to go unnoticed. I don't have specifics worked out in my head, but I am curious if I can combine the two--let the static approach strictly object to the dynamic statements, and then use the dynamic approach to help the user triage statements that do indeed appear capable of executing external dependencies.

  1. Yes--I don't I know exactly what I mean here. I'm not terribly familiar with Rust or the Nix packaging ecosystem for it. I did notice that most of what was already packaged was very full-program-oriented, but I did notice that Nix also has some helpers for building crates (I think it sidesteps cargo), so I assumed this was possible, but it may well not be, or I may just be misunderstanding what exists and how it works.

  2. Makes sense. I'll keep an eye on the project.

    I haven't really looked at syscall introspection as such yet. I started down this path when someone opened an issue against my project linking a recent paper that documents how they used a FUSE to discover executables a script was trying to execute. I'd be re-using their code here, but it's Linux-specific. I was initially optimistic, since I knew OSXFUSE existed, that I'd be able to find some straight-forward cross-platform abstractions (even if constrained; I think my needs are narrower than many use cases). I guess, regardless of how I think of it, sitting in the event stream from an active FUSE is syscall introspection.

    I'd prefer to do it at the FUSE level (instead of just observing syscalls), because the extra leverage for the task of fuzzing may be useful. Thanks for refocusing me, though--FUSE probably isn't all that critical to getting most of what I'm looking for. On this score, are you aware of any cross-platform abstractions over syscall tracing? (I think my core need is just seeing stat calls)

  3. I think the gap here is that I didn't really catch on first read that FUSE isn't a general feature, here, but just an implementation-detail of your approach on macOS. I was imagining being able to abstract over it from that perspective, but after reading better in the light of day, it doesn't look like it squares with what you're doing. :)