Linux Landlock is a kernel-native security module that lets unprivileged processes sandbox themselves - but nobody uses it because the API is ... hard!
I built `landrun`, a small CLI tool in Go, to make it practical to sandbox any command with fine-grained filesystem and network access controls. No root. No containers. No SELinux/AppArmor configs.
It's lightweight, auditable, and wraps Landlock v5 features (file access + TCP restrictions).
Bubblewrap is very limited, for example it doesn't allow to grant access to /proc/self/exe without giving access to whole /proc subsystem. So I had to write an emulation of /proc in Python and mount it with FUSE to work around this. I wonder if this issue is fixed in landlock, firejail and others.
Also bubblewrap cannot ask for a decision in runtime: you must set up the rules beforehand.
If I understand it correctly, landlock is an API used by an app to sandbox itself. The app itself controls the sandboxing. Bubble wrap is user space tooling external to the app, so the app had no direct awareness or control of its sandboxing. The scenarios each is intended for are orthogonal to one another.
Landlock can be used to sandbox a launched sub process, as it is here, just as the Kernel APIs used by Bubblewrap could (and sometimes are!) used by programs to sandbox themselves.
not exactly correct. bubblewrap, firejail, and i not sure, but maybe even apparmour, all remove capabilities and create+join restricted fs/net namespaces, and then fork the actual thing you want to execute. so it's exactly the same concept, but those use the cap and cgroups.
Looks very interesting. I'm achieving something somewhat similar by running soeme processes under docker and mounting volumes ro, but could definitely see a usecase for adding landlock to more server processes.
yeah you are missing --exec there, which feels a bit useless that you have to mention it, but I prefer things explicit and use all LSM can provide, I can imagine cases where --exec isn't really required. like `cat`.
either case have a look at latest release, it's a bit cleaner.
thanks for the link, Sydbox seems like a super cool project, but there's something weird about it: too many links in the README. not on GitHub, and the project that's on GitHub with a similar name hasn't had a commit in 16 years, is it by the same person?
if they can polish up the public facing side of the project, it would instill more confidence.
I don't need a link to Wikipedia every time "PoC" is used. Or to an online man page every time strace(1) is mentioned.
I get it that a documentation can have more than one "entry point", and hyperlinking all occurrences solves that.
But I think assuming certain audience leads to a document that is more effective. You don't explain addition in university-level textbooks, to make it easier to children from primary school.
This product is simply not for people who hear of strace for the first time.
that looks really cool, but unfortunately without any obvious examples or even a link to documentation, I'm closing the tab and likely forgetting it exists... I would assume many others would feel the same way.
> Read the fine manuals of syd,
libsyd, gosyd, plsyd, pysyd, rbsyd, syd.el and watch the asciicasts Memory Sandboxing, PID Sandboxing, Network Sandboxing, and Sandboxing Emacs with syd.
I do agree, though, that the docs could be improved.
seems to indicate that `--exec` is only required if the command you're executing then uses an `exec`-call internally, which `bash` would need to be able to fork.
So `touch` should not need `--exec`, while `bash` should be able to run anything it can read (including that whitelisted `/tmp`).
The former does not work for me, I have to add --exec. I can only assume it's because touch is in /usr/bin and so it needs permission to execute it from there.
It seems that using --ro or --rw at all makes --exec also mandatory.
well yeah you'll need --exec when you want to run binaries (unlike... cat?)
I hope landlock adds support to bind --exec to actual directories, that'll be fun!
As a workaround you could create a tmpfs device like /tmp_noexec with noexec flag, and mount it instead of the normal /tmp. But landrun does not (yet?) allow changing the name in directory options :(
For added security, I'd create an ephemeral tmpfs disk for each landlocked invocation: obviously the program we're running has no business seeing what other processes may have put to /tmp.
I'm trying to run a self-contained webserver executable without any external dependency. It starts but daemon <-> workers communication doesn't seem working (it is done via unix socket)
It works fine with bubblewrap or inside a scratch docker container.
This seems pretty nice, as it using directly landlock API from the Linux Kernel (like pledge from OpenBSD). One feature I would like to have is like yaml description for some set of configuration rather that use all this arguments. So we could have preconfigured commands and just execute them. But I think it is just a matter of taste. I will try the tool. Thanks for it.
We are working to make it part of the OCI runtime specification too.
Using existing configuration format would not work because Landlock has its own unique properties: unprivileged, nested sandboxes, dedicated Linux syscalls, and a good compatibility story with opt-in and incremental features.
Awesome! I'm happy to hear that you and others are interested in the configuration language. We should probably coordinate that on the Landlock mailing list when the time comes, so that we don't duplicate that work. We are open to outside contributions :)
Would be cool to see integration of landlock with configuration file in a way that a service launched by systemd can apply the configuration to the executable.
Which also points to landlock-make[0] or vice-versa (the original project that made me aware of the kernel functionality (although didn't realize it also isolated network which is great).
OpenBSD did get it right, but they also have a more relaxed scheme for backwards compatibility across releases. Linux's strict ABI compatibility guarantees complicate matters slightly, but with the right supporting library it becomes tolerable.
(Full disclosure, I am the author of that library)
FWIW, I do hope that we can motivate people to use Landlock in the same way as people use pledge on OpenBSD, as a lightweight self-sandboxing mechanism that requires fewer architectural changes to your program and results in more constrained sandboxes than Linux namespaces and other mechanisms do.
As far as I know the ABI for pledge and unveil really haven’t changed since release? What is stopping linux from creating NEW security primitives which are easy to use? We have wireguard in the linux kernel as a recent addition. Wireguard shows that new simple primitives can be added to the kernel, it requires someone with “good taste” to do the implementation without sacrificing usability.
BSD systems ship a kernel and user space, which simplifies a lot of things. Linux is more flexible but it comes at a cost. Adding new security features can also be challenging for other reasons. Anyway, Landlock is one of these new security primitives, and it is gaining new features over time.
The Landlock interface must not change the underlying semantic of what is allowed or denied, otherwise it could break apps build for an older or a newer kernel. However, these apps should still use all the available security features. This is challenging.
Landlock provides a way to define fine-grained security policies. I would not say the kernel interface is complex (rather flexible), but what really matter are the user space library interfaces and how they can safely abstract complexity.
I know how linux and bsd work. I still have yet to find a satisfactory answer to why linux cannot create security primitives which are useful — like wireguard. I understand that landlock tries to abstract complexity, but why do we need to design complex user interfaces? Pledge and unveil are just simple syscalls, there is no magic secret sauce on BSDs which enable these syscalls. It is true that bsd userspace has been compiled to bake in plege and unviel syscalls, but that is totally separate from the usability of the interfaces.
For instance, with Pledge, the "dns" promise is implemented with hardcoded path in the kernel. Linux is complex because it is versatile and flexible. Controlling access to such features requires some complexity and the kernel might not be enough.
About interfaces, another example is that Unveil is configured with path names but Landlock uses file descriptors instead (more flexible).
Also, these OpenBSD primitives only apply to the current executed binary, there is no nested sandboxes because the goal is not to create this kind of secure environment but mainly to secure a trusted binary.
I have been using https://github.com/marty1885/landlock-unveil on Linux for about two years now on my stock Ubuntu kernel. I am not sure, why this hasn't become more popular. It's also rootless sandboxing (and it does `unveil` like OpenBSD I guess). I use it to confine builds of third party software with success.
reply