Landrun: Sandbox any Linux process using Landlock, no root or containers
131 comments
·March 22, 2025Zoup
rmccue
I’d recommend adding your first (and maybe second) paragraphs directly to your readme - this is a much clearer description if you don’t know what landlock is already!
linsomniac
I didn't have much luck with one of the readme examples:
# rm -f /tmp/foo; ./landrun-linux-amd64 --log-level debug --ro /usr/bin --ro /lib --ro /lib64 --rw /tmp touch /tmp/foo
[landrun] 2025/03/22 10:28:02 Sandbox config: {ReadOnlyPaths:[/usr/bin /lib /lib64] ReadWritePaths:[/tmp] AllowExec:false BindTCPPorts:[] ConnectTCPPorts:[] BestEffort:true}
[landrun:debug] 2025/03/22 10:28:02 Adding read-only path: /usr/bin
[landrun:debug] 2025/03/22 10:28:02 Adding read-only path: /lib
[landrun:debug] 2025/03/22 10:28:02 Adding read-only path: /lib64
[landrun:debug] 2025/03/22 10:28:02 Adding read-write path: /tmp
[landrun:debug] 2025/03/22 10:28:02 Applying Landlock restrictions
[landrun] 2025/03/22 10:28:02 Landlock restrictions applied successfully
[landrun] 2025/03/22 10:28:02 Executing: [touch /tmp/foo]
touch: cannot touch '/tmp/foo': Permission denied
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.Zoup
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.
mikedelfino
Could you please help me understand why exec is required for this touch example? Is it necessary to actually launch the touch binary? Or touch itself exec()s something else?
bastiao
Would be possible/make sense to use landlock on OCI/containers land?
codethief
Syd[0] uses landlock (among many other mechanisms) to containerize applications and provides an OCI-compatible interface.
ranger_danger
This is the minimum options I needed to get it to work:
landrun --log-level debug --exec --ro /usr/bin --ro /usr/lib --rw /tmp touch /tmp/foo
Personally I don't like that --exec would allow binaries in /tmp to be executed as well...
qwertox
But
`landrun --ro /usr/bin --ro /lib --ro /lib64 --rw /path/to/dir touch /path/to/dir/newfile`
vs
`landrun --ro /usr/bin --ro /lib --ro /lib64 --exec /usr/bin/bash`
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`).
nine_k
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.
Filligree
I’ll try it, but just off the bat, how does this compare to bubblewrap?
codedokode
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.
mid-kid
Emulating /proc isn't super interesting when you can simply enter a new process namespace.
bitbang
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.
amarshall
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.
1oooqooq
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.
camkego
I also would like to understand the differences relative to bubblewrap
BoingBoomTschak
Same question. One thing I really dislike in Bubblewrap is that I must share the whole net user namespace even if all I want to do is use UNIX domain sockets.
Since I only see net options specifying ports, does this handle this use case?
bastiao
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.
mdaniel
If you want a file format, I'd lobby for one of the existing ones rather than some random yaml one
- sandbox-exec's scheme one https://github.com/BrianSwift/macOSSandboxBuild/blob/main/co...
- AppArmor https://wiki.apparmor.net/ (although I'm cognizant that tries to address way more than just filesystem access)
- Java's permission one https://docs.oracle.com/javase/8/docs/technotes/guides/secur...
Likely tens more
bastiao
I agree that re-use file format could a good option. BTW the used landlock go library has sort of example https://github.com/landlock-lsm/go-landlock/blob/main/exampl...
l0kod
We are working on a JSON/TOML format for Landlock, with the related library, and bindings for several languages: https://github.com/landlock-lsm/landlockconfig
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.
Foxboron
Still early but Mickaël Salaün, the author of landlock, is working on this.
https://github.com/landlock-lsm/landlockconfig
I'm going to write up some Go bindings for this when it becomes relevant.
gnoack
(Author of go-Landlock here)
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 :)
yjftsjthsd-h
That could be a separate wrapper, like bubblejail is for bubblewrap. Landjail?
__turbobrew__
> but nobody uses it because the API is ... hard!
OpenBSD really got it right with pledge and unveil.
gnoack
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.
See the example at the top of the Readme at https://github.com/landlock-lsm/go-landlock
(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.
__turbobrew__
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.
bjconlan
This is where I need to shout out to everyone's favorite developer Justine for keeping Linux cool:
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).
mulle_nat
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.
charcircuit
I disagree. Android's model of starting with a strong sandbox and having apps request permission to acces things outside of it has been much more successful in getting apps to be sandboxed.
Defaults are important.
zzo38computer
I think that isn't good enough either (but at least they tried).
My operating system design is: programs start with nothing other than the ability to perform deterministic computation and to send/receive messages with the capabilities it receives in the initial message. It is not allowed to know what these capabilities refer to; they may be proxies set up by the user, network resources, or something else, and is not necessarily what it asked for. All I/O including the ability to determine the current date/time or how much time has passed, requires the use of capabilities. (Due to this, a program with no capabilities left can be terminated automatically by the operating system (unless a debugger is attached; it is also necessary that the program cannot notice the debugger attached to it), since it is no longer capable of any I/O.)
rainworld
// If we have no rules, just return
if len(rules) == 0 {
log.Info("No sandbox rules to apply")
return nil
}
Really cool and well-written project, but I disagree with this choice: No rules should mean no rules (everything denied).I would have suggested support for more fine-grained file/directory permissions—good to see that’s already planned.
Zoup
Yeah I agree with that, just release a new version that does that.
rainworld
Does Linux 6.8 in fact ship ABI v5? At least it’s not guaranteed (Ubuntu 24.04, 6.8.0-55-generic). This post suggests 6.10: https://lore.kernel.org/landlock/20240716.yui4Iezai8ae@digik...
trikko
Are (abstract) unix sockets supported?
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.
dsp_person
aren't abstract sockets un-jailable unless using network namespaces?
or in the other direction, to truly prevent e.g. xorg socket from being accessed by a bubblejailed application, it should exclude --share-net, regardless if you bind the actual path to the socket (since abstract permeates beyond that)
trikko
Well, so should it work?
You're telling me there's another reason, then... Can't guess which one.
Hmmm...
null
JohnTheSealion
How does Landrun compare to Firejail?
borplk
Weird question, but would this work inside docker as "extra protection"?
aucisson_masque
Would that make feasible (in the long term) to have macOS permission manager like « do you want terminal to access documents folder ? » on Linux ?
As a very average user, that’s the kind of thing I miss on windows and Linux.
Because I installed Google chrome, it doesn’t mean I want it to be able to scan every single file I have on my computer yet there is no way to prevent it and I feel it’s a big security and privacy issue that no one speak about !
mikedelfino
You might find Flatpak interesting if you're not already familiar with it. Properly packaged applications start with limited file system access—for example, when you browse file:/// in Firefox, it can't see all your files. However, using the "Open File" menu acts as a file system portal, granting access to selected files on demand. While this isn't exactly how macOS handles permissions, it does prevent the unrestricted system access you're concerned about.
qwertox
My biggest problem with Linux is that there are no per-process firewall settings. I think one can get around this by using AppArmor or using an user per app and assigning rules to a user.
I've used Linux for over a decade now, but there are still many things I haven't learned, so maybe I'm missing something in this regard.
The GitHub page says
- TCP network access control (binding and connecting)
and
- Support for UDP and other network protocol restrictions (when supported by Linux kernel)
so maybe this can be used to firewall processes in an easy way (assuming that it is easy to set up landrun)?
its-kostya
Why not use linux network namespaces to run your processes in different network stack? nftables rules are per network namespaces so you can get all sorts of sophisticated and achieve essentially per process firewalling. The pattern is to create a network namespace, create a veth pair and move one end of the pair into the namespace. Then you could set up rules to route traffic from default namespace to the process namespace via veth device.
Systemd has `NetworkNamespacePath` directive which can spin up services in new namespaces as well. See `man 5 systemd.exec`
mikedelfino
I'm not sure about the other commenter's intentions, but on desktop, I wish every program started in a restricted network namespace. Instead of blocking all incoming and outgoing connections by default, it would request user permission interactively and adjust access accordingly.
ranger_danger
opensnitch does this
ranger_danger
My biggest issue with using namespaces is that it bypasses the main host firewall entirely.
fulafel
Attaching a separate firewall rules to every process would be a bit heavyweight. What we do have is network namespaces that let you have networking rules (incl firewall) per a group of processes.
1oooqooq
that's what all firewall apps on Android (bastardized Linux) does.
well, they already have a user namespace per app which they can match on the firewall rule, but a per "main" program pid net namespace would be pretty much the same. i guess this can be a cool patch to this plus a one weekend qt+rust gui to manage the firewall (or a patch to firewalld gui)... only if i ever had a weekend.
nolist_policy
> My biggest problem with Linux is that there are no per-process firewall settings.
There is, with cgroups: https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.t...
NewJazz
Is there an example of this that uses cgroup2?
tobias2014
You can use firejail for network isolation, it can run applications in a new network namespace [1]. I'm using this to run applications over tor to make sure that nothing leaks.
[1] https://firejail.wordpress.com/documentation-2/basic-usage/#... "A network namespace is a new, independent TCP/IP stack attached to the sandbox. The stack has its own routing table, firewall and set of interfaces."
throwfaraway398
I saw there's an option to match on a cgroup among nft meta expressions (but I've never tried it). It could be enough if you just want to add per-process firewall rules, but not configure an additional namespace with it's associated interfaces, routing/nating.
kanbankaren
Yes. You could match packets based on username or even SELinux labels.
You could also set a special mark on a packet for each container and then filter based on that. The Internet is surprsingly very thin on nft resources. I spent a few weeks learning how to write them. Definitely, not for the average consumer.
GS523523
[dead]
Zoup
Thank you all for your support, I really didn't expect this to take off like this! given that project is roughly two days old (:D) it's still fair to expect some issues all around, please report them on GH if you found one.
khrbtxyz
I don't quite understand what --exec does. If I leave out --exec from example 3, is it supposed to prevent bash from executing other programs?
$ landrun --log-level debug --ro /usr/bin,/lib,/lib64 /usr/bin/bash --norc
[landrun] 2025/03/22 17:16:29 Sandbox config: {ReadOnlyPaths:[/usr/bin /lib /lib64] ReadWritePaths:[] AllowExec:false BindTCPPorts:[] ConnectTCPPorts:[] BestEffort:true}
[landrun:debug] 2025/03/22 17:16:29 Adding read-only path: /usr/bin
[landrun:debug] 2025/03/22 17:16:29 Adding read-only path: /lib
[landrun:debug] 2025/03/22 17:16:29 Adding read-only path: /lib64
[landrun:debug] 2025/03/22 17:16:29 Applying Landlock restrictions
[landrun] 2025/03/22 17:16:29 Landlock restrictions applied successfully
[landrun] 2025/03/22 17:16:29 Executing: [/usr/bin/bash --norc]
bash-5.2$
bash-5.2$ /usr/bin/uname -r
6.13.7-200.fc41.aarch64
Zoup
yeah it wasn't the best call, have a look at v0.1.4, I think it's better now!
johnisgood
I will just leave this here: https://man.archlinux.org/man/firejail.1
And someone also said, but Firejail supports Landlock, too: https://github.com/netblue30/firejail/pull/6078.
dpc_01234
Seems like a Nix could take a good advantage of Landlock, as it already (kind of) knows all the paths processes need access to.
btdmaster
Very cool project! I was curious if this was possible with util-linux (provider of the unshare command that provides namespace management, the underlying feature behind containers), and it is indeed possible:
setpriv --landlock-access 'fs:remove-file,remove-dir,write-file,make-reg' touch /tmp/foo # Permission denied
setpriv --landlock-access 'fs:remove-file,remove-dir,write-file,make-reg' --landlock-rule "path-beneath:make-reg:/tmp" touch /tmp/foo # Allowed
Very verbose unlike unshare and really deals with internal details, so I'd find it hard to use setpriv in practice.
null
jbverschoor
Imo, (almost) every directory should be treated as a new sandbox
thiht
How does the Landlock API compare to mount/network namespaces, as used in Docker containers? As I understand it, namespaces are for isolation, and Landlock would be more like access permissions, is that correct?
Could it be possible for the system to use the Landlock api to catch unauthorized net/fs access by an app and display a popup to ask for authorization, like macOS does?
gnoack
(Landlock reviewer here)
Namespaces can also be used for sandboxing, but they have a series of problems. Most importantly, they require more substantial changes to your program that wants to sandbox itself, and the program has to jump through a series of hoops to get everything into the right state. It is possible, but the resulting program environment is in the end more unusual and the mechanisms for enabling unprivileged namespaces are making it difficult to use it for smaller use cases. (It involves re-execution of the program that wants to sandbox itself, whereas with Landlock, a small program can just install a Landlock policy during an early startup phase and continue with that.)
Controlling the rules through a separate process is not currently possible, but it was proposed earlier this month on the kernel mailing lists:
https://lore.kernel.org/all/cover.1741047969.git.m@maowtm.or...
bjackman
I think in the upstream kernel LSMs are also still the only way to prevent a process from creating child namespaces where it has privileges?
E.g. if you can cat CAP_NET_ADMIN even within a restricted namespace, you have access to huge amounts of horrbly broken kernel code. It's easy (for people who know how to exploit kernel bugs) to escalate privileges from there.
Distros have their own fixes for this issue so namespaces definitely aren't useless in practice for sandboxing. But the basic mechanism just doesn't that well suited to it.
anybody8824
The user.max_user_namespaces sysctl itself is namespace aware and is used by bubblewrap's --disable-userns option.
But a prctl like NO_NEW_PRIVS would be better, since it could avoid an intermediary namespace that is needed for the namespace-aware sysctl.
thiht
Great answer, thanks!
l0kod
Namespaces (used by containers) are very powerful but they are also a door to a large attack surface: https://lwn.net/Articles/673597/
Landlock is (only) an access control system, but it's designed to let any process use it, including potentially untrusted ones, which makes it suitable for any apps. It's close and complementary to seccomp.
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).
Demo + usage examples in the README.
Would love feedback from the HN crowd!