[HN Gopher] Landrun: Sandbox any Linux process using Landlock, n...
       ___________________________________________________________________
        
       Landrun: Sandbox any Linux process using Landlock, no root or
       containers
        
       Author : Zoup
       Score  : 211 points
       Date   : 2025-03-22 13:56 UTC (9 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | Zoup wrote:
       | 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!
        
         | Filligree wrote:
         | I'll try it, but just off the bat, how does this compare to
         | bubblewrap?
        
           | camkego wrote:
           | I also would like to understand the differences relative to
           | bubblewrap
        
           | bitbang wrote:
           | 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 wrote:
             | 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 wrote:
             | 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.
        
           | codedokode wrote:
           | 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.
        
         | bastiao wrote:
         | 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.
        
           | yjftsjthsd-h wrote:
           | That could be a separate wrapper, like bubblejail is for
           | bubblewrap. Landjail?
        
           | mdaniel wrote:
           | 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/mac
           | OSSandboxBuild/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 wrote:
             | 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...
        
           | Foxboron wrote:
           | Still early but Mickael Salaun, 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 wrote:
             | (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 :)
        
               | ARob109 wrote:
               | 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.
               | 
               | Akin to systemd SystemCallFilter directive for no-code
               | application of seccomp filters to the sandboxed process h
               | ttps://www.freedesktop.org/software/systemd/man/latest/sy
               | st...
        
           | l0kod wrote:
           | 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.
        
         | linsomniac wrote:
         | 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.
        
           | ranger_danger wrote:
           | 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...
        
             | nine_k wrote:
             | 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.
        
               | ranger_danger wrote:
               | > I'd create an ephemeral tmpfs disk for each landlocked
               | invocation
               | 
               | And now you've just invented firejail.
        
               | nine_k wrote:
               | UX-wise, yes. Internally firejail and landrun use
               | different isolation APIs.
        
               | ranger_danger wrote:
               | Firejail supports Landlock though:
               | https://github.com/netblue30/firejail/pull/6078
        
             | qwertox wrote:
             | 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`).
        
               | ranger_danger wrote:
               | 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.
        
           | bastiao wrote:
           | Would be possible/make sense to use landlock on
           | OCI/containers land?
        
             | codethief wrote:
             | Syd[0] uses landlock (among many other mechanisms) to
             | containerize applications and provides an OCI-compatible
             | interface.
             | 
             | [0]: https://gitlab.exherbo.org/sydbox/sydbox
        
               | ranger_danger wrote:
               | 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.
        
               | bastiao wrote:
               | True! I had the same feeling.
        
         | rainworld wrote:
         | // 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.
        
         | __turbobrew__ wrote:
         | > but nobody uses it because the API is ... hard!
         | 
         | OpenBSD really got it right with pledge and unveil.
        
           | gnoack wrote:
           | 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__ wrote:
             | 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.
        
               | l0kod wrote:
               | 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.
        
               | __turbobrew__ wrote:
               | 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.
        
           | mulle_nat wrote:
           | 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.
        
         | BlimpSpike wrote:
         | Similarly to the bubblewrap comment, I'd also like to know how
         | it compares to nsjail.
         | 
         | I think nsjail uses mount namespaces (CLONE_NEWNS) instead of
         | landlock for filesystem sandboxing, but what would the
         | practical differences be?
        
         | trikko wrote:
         | 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.
        
       | ximm wrote:
       | This looks nice, but I fail to see any use cases that cannot be
       | handled with bwrap and mount namespaces.
        
         | amarshall wrote:
         | Some systems or admins may not trust unprivileged namespacing
         | (thus disabling and its use requiring root), while Landlock may
         | be enabled (and is specifically designed to be used by
         | unprivileged processes).
        
         | 1oooqooq wrote:
         | namespace, specially user and net, are terrible to setup and
         | use.
         | 
         | I'm not sure this is better, but assuming it is by the author
         | into.
        
       | aw4y wrote:
       | nice! it would be cool (since it's in Go) how to use it like a
       | library, sandboxing some exec directly from your code.
        
         | NewJazz wrote:
         | https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landl...
        
         | gnoack wrote:
         | (Author of that library here)
         | 
         | It is a library, as already linked in the other comment:
         | https://github.com/landlock-lsm/go-landlock
         | 
         | The landrun tool is built on the same library. We also provide
         | an official library for Rust, and obviously you can do it from
         | C as well.
         | 
         | I also collected some libraries for other languages at
         | https://wiki.gnoack.org/SoftwareUsingLandlock (but I can not
         | vouch for their quality in detail)
        
       | teabee89 wrote:
       | Nice work! Too bad it's GPL v2 :(
        
         | yjftsjthsd-h wrote:
         | When would that matter?
        
         | allset_ wrote:
         | The underlying library that does most of the work is MIT.
         | 
         | https://github.com/landlock-lsm/go-landlock
        
       | jbverschoor wrote:
       | Imo, (almost) every directory should be treated as a new sandbox
        
         | IshKebab wrote:
         | Pretty much how Plan 9 works IIRC. I think Fuchsia might have a
         | similar idea.
        
       | zekrioca wrote:
       | How does one do resource control with Landrun, e.g., CPU, memory,
       | I/O..?
        
         | IshKebab wrote:
         | You can't. It's only for filesystem and TCP sandboxing.
        
           | gnoack wrote:
           | Exactly, for resource limits you can use setrlimit(2) or
           | cgroups if needed.
        
         | turrini wrote:
         | Not directly, but I think you can run it with systemd:
         | 
         | systemd-run --user --scope -p
         | MemoryMax=1G,IOReadIOPSMax=8000,CPUQuota=20%,<...> landrun ...
        
       | thiht wrote:
       | 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 wrote:
         | (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...
        
           | thiht wrote:
           | Great answer, thanks!
        
         | l0kod wrote:
         | 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.
        
       | dpc_01234 wrote:
       | Seems like a Nix could take a good advantage of Landlock, as it
       | already (kind of) knows all the paths processes need access to.
        
       | qwertox wrote:
       | 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)?
        
         | tobias2014 wrote:
         | 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 wrote:
           | 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 wrote:
             | 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.
        
         | nolist_policy wrote:
         | > 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...
        
         | its-kostya wrote:
         | 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`
        
       | nickandbro wrote:
       | This is great, I run a hobby project, vimgolf.ai, to get my
       | friends to learn vim and had to do a lot with firejail to sandbox
       | the neovim instances correctly. This looks be a lot easier to
       | setup
        
       | riobard wrote:
       | Is it just me or Linux seems to have too many non-orthogonal ways
       | to restrict processes? Like why Landlock does TCP filtering based
       | on port only? What about non-TCP traffic and maybe IP based
       | restrictions is more useful? How does it interact with Netfilter?
       | Puzzling.
        
         | l0kod wrote:
         | It takes time to develop theses features, but Landlock is
         | gaining new network filtering features. We are working in a way
         | to control socket creation according to their protocols, and
         | also a way to filter UDP (which makes sense to developers and
         | users).
         | 
         | From the point of view of an app developer, it might not make
         | sense to filters peers but services (ports) instead, and
         | filtering peers without their names would not be ideal (the
         | kernel doesn't know about DNS, only IPs). Anyway, this feature
         | might come one day if someone want to work on it, but we follow
         | well-tested incremental development.
         | 
         | Netfiler is a privileged network feature that allows to do
         | almost anything with the network, which makes it unsuitable for
         | (app/unprivileged) sandboxing.
        
           | gnoack wrote:
           | +1
           | 
           | A rough description of upcoming network restriction features
           | in Landlock and how they map to the BSD socket API is in the
           | talk at https://youtu.be/K2onopkMhuM?start=2025 starting
           | around 33:45
           | 
           | I really hope we can get back to these features soon :) I
           | think these would be very useful.
        
       | btdmaster wrote:
       | 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.
        
       ___________________________________________________________________
       (page generated 2025-03-22 23:00 UTC)