while this looks cool, this is also getting out of hand. we need an operating system that doesn't require all this machinery on top in order to achieve basic encapsulation.
As far as I can tell from 30 seconds of research, this thing just bundles standard Linux syscalls in one package. "This machinery" is just typical Google overengineering, it's not doing anything except acting as middleware.
P.S. Yeah, I wish we had a better userspace Linux namespace toolkit instead of Docker.
i think namespaces are the wrong abstraction. it's a good solution given what exists (posix/linux), but way more hacky than something new with encapsulation of machine code by source being a first class design principle.
the whole idea that you have to fork process tables, user tables, network tables and filesystems to achieve encapsulation between applications is a product of the old unix security model not being sufficient for what people are actually using these systems for today.
so the popularity of containers (namespaces) and the entire ecosystem of tools like this (dating all the way back to chroots and bsd jails) basically says to me that maybe a fresh approach to security features in an operating system would lead to less complexity than what has needed to be built on top of good ol' unix.
yeah i suppose you're right, point still stands. having to chop up all the kernel tables to run little mini systems just to deploy software correctly, along with choosing from a whole host of bolt on capabilities systems and sandboxing technologies makes it seem like the services provided by base unix for modern computing are looking a bit long in the tooth.
Not sure how to do that from OS perspective without introducing some kind of module concept (either through shared object or some other ways).
The SAPI solution seems pretty straightforward to me. Jail the particular library into a sandboxed process and IPC with it transparently. Compatibility will be tricky (especially for libraries that is more complicated). But the solution itself is straightforward and I can see it work.
yup. we need an operating system and hardware that sandboxes all code and state that runs on it by source, yet still has fast interfaces between units and avoids overt complexity by bolting facilities for this on top.
Check out ELFbac: (http://elfbac.org/)
It extracts "programmer intent" from relations in the ELF format to create memory protection boundaries.
It is not exactly sandboxing, but limits what a compromised program module can do.
Exactly. As far as I can tell all modern OSes are built on the assumption that users of a machine need protection from each other, rather than that each user needs protection from the third party code that they run.
> user needs protection from the third party code that they run
Unfortunately the above then often crosses the line over into "protecting the user from actually accomplishing useful stuff". The file sandboxing approaches I've seen so for e.g. commonly ignore the existence of file formats that don't consist of a single, atomic file.
I think you might want to take a look at https://fuchsia.dev/ - although I haven't worked with it myself so far, the stated goals might be somewhat in line with what you're proposing here.
They couldn't have made the client stub interface more baroque if they tried. It sounded like something that could mimic something approaching the original library interface automatically, pretty disappointed it's basically just another RPC stubs generator
If you can stomach the perf tradeoffs, compiling to WASM is much easier than this
> They couldn't have made the client stub interface more baroque if they tried.
I've never used this API but the cross process synchronization stuff seems like a difficult nut to crack. I'm curious which bits you think are unnecessarily baroque.
> If you can stomach the perf tradeoffs, compiling to WASM is much easier than this
I'm not super familiar with WASM, but it's unclear to me how compiling to that target addresses the problems that are addressed by this system? Does WASM have built-in security policies and sandboxing? Is it easy to call into a WASM-compiled library from your native C/C++ program? How?
Those are not sandbox escapes, those are missing intra-program defences which make it easier for a e.g. buffer overflow to be used for program manipulation. That still doesn't allow you to escape the sandbox in itself.
They don't let you perform sandbox escapes but that doesn't necessarily matter if all of the important data is inside the sandbox, and it has enough capabilities to meaningfully exfiltrate. seccomp has this problem in spades; most apps
that "use seccomp" make practically every syscall under the sun available to make the policy apply cleanly. This is just an example not to be taken as totally illustrative. But very few people design their programs around seccomp or another sandbox mechanism, I find.
This doesn't apply obviously to cases where you design around having a sandbox, and at that point, I think the differences between something like WASM and SAPI or whatever are a lot murkier and more technical.
One thing about WASM that I feel is worth mentioning, which isn't technical so much as social, is that there's a lot of appeal/interest around simply "lift-and-shift" existing native code onto webassembly runtimes. That's good because that existing code is useful, but those apps aren't often designed with such sandbox architectures in mind. They often are designed (or at least consider) having binary-level mitigations applied, though. So I think this natural overlap in the set of use cases people have is what might give people pause. This is similar to the seccomp problem; retrofitting is a very big appeal even though it has some conceptual issues. This isn't some kind of indictment but if you're going to do an honest evaluation of these approaches I feel this background is worth keeping in mind.
I think if you designed an app with a sandbox architecture by default the best sandbox is the one you trust, WASM vs whatever be damned.
> The Sandboxed API project (SAPI) aims to make sandboxing of C/C++ libraries less burdensome: after initial setup of security policies and generation of library interfaces, an almost-identical stub API is generated (using a template-based programming variable hierarchy system), transparently forwarding calls using a custom RPC layer to the real library running inside a sandboxed environment.
Are you claiming that this documentation is misleading?
So it adds extra state, that needs to be initialized, adds extra failure points than needed to be handled in the code (sandbox initialization can fail, the RPC layer can fail itself), need to wrap some data structures so they can be passed through (you can't just pass pointers as-is).
I wonder how callbacks can be passed, but maybe that's actually less problematic than data pointers.
To be honest it seems like writing a capnproto rpc around the functionality you want to sandbox, and running it as a low privilege microservice, would be better than SAPI.
capnproto supports passing callacks/interfaces back via its capabilities mechanism.
but you'd have to manually define such an rpc wrapper IDL, right?
IIUC the interesting trick behind SAPI is that it generates the wrapper for you based on parsing the library public API. Perhaps I misunderstood something.
Hi, one of the project's co-authors here (SAPI that is).
The aim of SAPI is a bit different than whole-process sandboxing. It's about retaining the original running speed (and lack of sandboxing constraints) of the main project part, while making sure that only some parts are isolated (sandboxed), and the programming interfaces to the sandboxed parts still look familiar.
I'm not that well-versed into how WASM works when it tries to integrate with the rest of OS. But I'd assume it's some form of whole-process sandboxing, where practically all code is WASMized, and only some kind of loaders and trusted stubs are written in native assemblers (something has to invoke syscalls in the end).
Not the same software, but "almost" the same underlying tech is used (e.g. SAPI/Sandbox2 used ptrace for process tracking and debugging, and to my knowledge Chrome Linux sandboxes don't).
> Any plans to create more sandboxes like this for other platforms like Windows and Mac?
Linux is so far a priority, but it might be technically possible to make the actual software isolation layer modularized, so it would support various underlying tech (various OSes, or even different tech under a single OS).
Most of the problems in creating services by wrapping libraries in RPCs, in my experience, come from most libraries not supporting asynchrony, timeouts etc.
The zlib example is a bit baffling to be honest. If zlib goes in to an infinite 100% CPU loop, perhaps due to a zip bomb, you're still screwed as far as I can tell
A full RPC abstraction also gives you the opportunity to change out the backend implementation that this doesn't.
> If zlib goes in to an infinite 100% CPU loop, perhaps due to a zip bomb, you're still screwed as far as I can tell
You can set CPU and wall time limits and the sandbox will be killed if it runs for longer.
> A full RPC abstraction also gives you the opportunity to change out the backend implementation that this doesn't.
Absolutely, but the RPC mechanism in SAPI is an implementation detail and ideally not something you should have to care about. You can of course just use the Sandbox2 part of Sandboxed API and implement an RPC layer yourself.
When I initially read the description, I thought this could provide a drop-in runtime-linked shared library stub, but looking deeper in the docs and examples it appears there is at least some setup code required on the client side?
Can this log the RPC calls around the target C library? Or potentially even replay calls in isolation? The latter could be expensive for non-trivial programs (require saving all synchronized memory state?), but might be more viable with binary diffs of the shared state if the client side doesn't modify the synchronized memory too much.
42 comments
[ 2.0 ms ] story [ 109 ms ] thread"Linux kernel with support for UTS, IPC, user, PID and network namespaces"
P.S. Yeah, I wish we had a better userspace Linux namespace toolkit instead of Docker.
I just want to run my apps with a separate TCP port namespace :)
so the popularity of containers (namespaces) and the entire ecosystem of tools like this (dating all the way back to chroots and bsd jails) basically says to me that maybe a fresh approach to security features in an operating system would lead to less complexity than what has needed to be built on top of good ol' unix.
(And I don't think they were ever intended as a security feature.)
The SAPI solution seems pretty straightforward to me. Jail the particular library into a sandboxed process and IPC with it transparently. Compatibility will be tricky (especially for libraries that is more complicated). But the solution itself is straightforward and I can see it work.
Unfortunately the above then often crosses the line over into "protecting the user from actually accomplishing useful stuff". The file sandboxing approaches I've seen so for e.g. commonly ignore the existence of file formats that don't consist of a single, atomic file.
I think you might want to take a look at https://fuchsia.dev/ - although I haven't worked with it myself so far, the stated goals might be somewhat in line with what you're proposing here.
If you can stomach the perf tradeoffs, compiling to WASM is much easier than this
I've never used this API but the cross process synchronization stuff seems like a difficult nut to crack. I'm curious which bits you think are unnecessarily baroque.
> If you can stomach the perf tradeoffs, compiling to WASM is much easier than this
I'm not super familiar with WASM, but it's unclear to me how compiling to that target addresses the problems that are addressed by this system? Does WASM have built-in security policies and sandboxing? Is it easy to call into a WASM-compiled library from your native C/C++ program? How?
Yes, WebAssembly is sandboxed. https://webassembly.org/docs/security/
This WASM? https://www.theregister.com/2021/11/04/webassembly_stack_can...
The castle walls stand, yet everything burns thanks being able to turn a candle into the table.
This doesn't apply obviously to cases where you design around having a sandbox, and at that point, I think the differences between something like WASM and SAPI or whatever are a lot murkier and more technical.
One thing about WASM that I feel is worth mentioning, which isn't technical so much as social, is that there's a lot of appeal/interest around simply "lift-and-shift" existing native code onto webassembly runtimes. That's good because that existing code is useful, but those apps aren't often designed with such sandbox architectures in mind. They often are designed (or at least consider) having binary-level mitigations applied, though. So I think this natural overlap in the set of use cases people have is what might give people pause. This is similar to the seccomp problem; retrofitting is a very big appeal even though it has some conceptual issues. This isn't some kind of indictment but if you're going to do an honest evaluation of these approaches I feel this background is worth keeping in mind.
I think if you designed an app with a sandbox architecture by default the best sandbox is the one you trust, WASM vs whatever be damned.
The doc claims that it's "almost identical"
> The Sandboxed API project (SAPI) aims to make sandboxing of C/C++ libraries less burdensome: after initial setup of security policies and generation of library interfaces, an almost-identical stub API is generated (using a template-based programming variable hierarchy system), transparently forwarding calls using a custom RPC layer to the real library running inside a sandboxed environment.
Are you claiming that this documentation is misleading?
https://github.com/google/sandboxed-api/blob/main/sandboxed_...
So it adds extra state, that needs to be initialized, adds extra failure points than needed to be handled in the code (sandbox initialization can fail, the RPC layer can fail itself), need to wrap some data structures so they can be passed through (you can't just pass pointers as-is).
I wonder how callbacks can be passed, but maybe that's actually less problematic than data pointers.
capnproto supports passing callacks/interfaces back via its capabilities mechanism.
IIUC the interesting trick behind SAPI is that it generates the wrapper for you based on parsing the library public API. Perhaps I misunderstood something.
The aim of SAPI is a bit different than whole-process sandboxing. It's about retaining the original running speed (and lack of sandboxing constraints) of the main project part, while making sure that only some parts are isolated (sandboxed), and the programming interfaces to the sandboxed parts still look familiar.
I'm not that well-versed into how WASM works when it tries to integrate with the rest of OS. But I'd assume it's some form of whole-process sandboxing, where practically all code is WASMized, and only some kind of loaders and trusted stubs are written in native assemblers (something has to invoke syscalls in the end).
In this case one can use Sandbox2, which is part of SAPI, though not very prominently exposed - https://github.com/google/sandboxed-api/tree/main/sandboxed_.... It's a full-featured Linux sandbox in its own rights, with C++ API. Examples might be englightning: https://github.com/google/sandboxed-api/tree/main/sandboxed_...
Any plans to create more sandboxes like this for other platforms like Windows and Mac?
Not the same software, but "almost" the same underlying tech is used (e.g. SAPI/Sandbox2 used ptrace for process tracking and debugging, and to my knowledge Chrome Linux sandboxes don't).
> Any plans to create more sandboxes like this for other platforms like Windows and Mac?
Linux is so far a priority, but it might be technically possible to make the actual software isolation layer modularized, so it would support various underlying tech (various OSes, or even different tech under a single OS).
The zlib example is a bit baffling to be honest. If zlib goes in to an infinite 100% CPU loop, perhaps due to a zip bomb, you're still screwed as far as I can tell
A full RPC abstraction also gives you the opportunity to change out the backend implementation that this doesn't.
You can set CPU and wall time limits and the sandbox will be killed if it runs for longer.
> A full RPC abstraction also gives you the opportunity to change out the backend implementation that this doesn't.
Absolutely, but the RPC mechanism in SAPI is an implementation detail and ideally not something you should have to care about. You can of course just use the Sandbox2 part of Sandboxed API and implement an RPC layer yourself.
Can this log the RPC calls around the target C library? Or potentially even replay calls in isolation? The latter could be expensive for non-trivial programs (require saving all synchronized memory state?), but might be more viable with binary diffs of the shared state if the client side doesn't modify the synchronized memory too much.