Crates.io | extrasafe-multiarch |
lib.rs | extrasafe-multiarch |
version | 0.4.0 |
source | src |
created_at | 2023-08-16 18:40:19.053835 |
updated_at | 2024-03-17 12:50:09.778774 |
description | Make your code extrasafe by reducing what it can access. |
homepage | |
repository | https://github.com/AaronDewes/extrasafe |
max_upload_size | |
id | 946279 |
size | 281,129 |
"trust noone not even urself" - internet man
fn main() {
println!("disabling syscalls...");
extrasafe::SafetyContext::new()
.enable(
extrasafe::builtins::SystemIO::nothing()
.allow_stdout()
.allow_stderr()
).unwrap()
.apply_to_all_threads().unwrap();
// Opening files now fails!
let res = File::create("should_fail.txt");
assert!(res.is_err());
println!("but printing to stdout still works!");
eprintln!("and so does stderr!");
}
You've used safe and unsafe Rust: now your code can be extrasafe.
extrasafe is a wrapper around the Linux kernel's seccomp syscall-filtering functionality to prevent your program from calling syscalls you don't need, with support for the Landlock Linux Security Module. Seccomp is used by systemd, Chrome, application sandboxes like bubblewrap and firejail, and container runtimes. Seccomp by itself is not a complete sandboxing system.
The goal of extrasafe is to make it easy to add extra security to your own programs without having to rely on external configuration by the person running the software.
seccomp is very mildly complicated, so we provide simple defaults that make it hard to misuse: Deny-by-default with pre-selected sets of syscalls to enable.
Additionally, we support slightly advanced use-cases:
We also support using Landlock to allow specific, targeted access to the filesystem:
fn main() {
let tmp_dir = tempfile::tempdir().unwrap().into_path();
extrasafe::SafetyContext::new()
.enable(
extrasafe::builtins::SystemIO::nothing()
.allow_create_in_dir(&tmp_dir)
.allow_write_file(&tmp_dir)
).unwrap()
.apply_to_current_thread().unwrap();
// Opening arbitrary files now fails!
assert!(File::open("/etc/passwd")
.is_err());
// But the directory we allowed works
assert!(File::create(tmp_dir.join("my_output.txt"))
.is_ok());
// And other syscalls are still disallowed
assert!(std::net::UdpSocket::bind("127.0.0.1:0")
.is_err());
}
Check out the user guide here
Application developers who want to tightly control what their programs can and cannot do.
If you're developing a library, there are three things you can do:
extrasafe::RuleSet
that covers the functionality of your libraryinit
function that does any IO-related work ahead of time (e.g. reading config files, SSL certificates)You don't want to use extrasafe directly in your library because you don't know what other functionality your dependents will be using.
Currently extrasafe only supports x86_64
. If you'd like to help support other archs please open an issue.
You may be able to use extrasafe to help test certain edge-cases, like the network being unavailable or not being able to read files, but I think that use-case would be better served by a separate library. Email me if you're interested in this!
So you can be extra safe. Suppose your program has a dependency with an undiscovered RCE lurking somewhere: extrasafe allows you to partially hedge against that by disabling access to functionality and files you don't need.
unshare
.AF_NETLINK
, which can be filtered with seccompAF_NETLINK
sockets are disabled by default with extrasafe.Seccomp filters are a somewhat blunt tool.
open
calls, or indeed any syscall arguments that are pointers (but we now support Landlock!)Why not both? Keep reading.
systemd supports filtering child processes' syscalls with seccomp via the SystemCallFilter
attribute. See e.g. this blog post and the systemd documentation
Issues:
pledge
To those sysadmins or devops reading this and saying "but I don't want to trust that the developers wrote their seccomp filter correctly!" - great! Defense in depth is the goal, and you can and should continue to use AppArmor or your preferred choice of external security control system.
As mentioned above, you should continue to use Linux Security Modules like AppArmor and SELinux! Not every program will be using extrasafe.
In the same way, from the perspective of a developer, there's no guarantee that the person running your code is using them. When there's a bug in your open-source code running on thousands of machines outside of your control, it's much nicer to know that it's not easily exploitable and can be fixed at your leisure, rather than having to coordinate a massive patch-and-upgrade effort to secure the systems.
Using make as a simple command runner until just
is packaged for Ubuntu/Debian, or you can run the cargo commands directly.
make test
make lint
make coverage