I've been messing with sandboxing using "bwrap" for random itch.io games I download to play and it isn't trivial to get it working with least privileges. I have so far been unable to get "Microlandia" to run, but other Unity games are running just fine under "bwrap". I am excited to see more Landlock tools emerge that make this task easier.
What's the status of Landlock in container runtimes? A quick search makes it seem like CRIs are trying to define their own custom Landlock interface.
That will inevitably lag behind what the kernel supports, but more importantly I don't foresee many container image packagers, Helm recipe maintainers and other YAML wranglers getting into the business of maintaining a Landlock sandbox policy.
It makes sense for an application to use Landlock directly to sandbox some parser or other sensitive component. But if the CRI just blocks the syscalls by default, no infra person is going to take on the maintainance of their own sandbox policy for every app. The app will just see ENOSYS and not be sandboxed.
I might be missing the whole idea here, but I really don't see why we need some custom layer in the middle instead of having container runtimes let the security syscalls through?
The first and foremost interface of the kernel is the syscall interface aka the uapi. libc and other C libraries like liburing or libcap are downstream of that. Many syscalls still don't have wrappers in libc after years of use.
I read the article as saying that there's no official C library but unofficial ones do exist. Quote below, emphasis mine.
> A official c library doesn’t exist yet unfortunately, but there’s several out there you can try.
Also, it looks like there is more than zero support for C programs calling Landlock APIs. Even without a 3rd-party library you're not just calling syscall() with a magic number:
I don't understand what you mean. There's no "official" Rust, Haskell and Go APIs for this thing either. All libraries available seem to be just what some third party made available. There's also several C libraries, just none that have been officially endorsed by the Linux kernel team.
Go is famous for not needing libc and talking to the kernel. Rust and Haskell have communities that are very interested in safety and security, so they are earlier adopters.
For C, unofficial support apparently sufficed for now.
It's pretty subtle but it's referring to The C Library, libc.{a,so,dll,etc}. The library provided by your toolchain that supports the language.
Meaning glibc or musl or your favorite C library probably doesn't have this yet, but since the system calls are well defined you can use A C library (create your own header file using the _syscallN macro for example).
The lack of a C API should not stop any C developers from using it, hopefully. The wrapper libraries are relatively simple (i.e. https://codeberg.org/git-bruh/landbox) and both Rust and Go can expose a C FFI in case developers would rather link against a more "official" library instead.
There is no "liblandlock" or whatever, though there totally could be. The only reason Rust, Go, and Haskell have an easy-to-use API for this syscall is because someone bothered to implement a wrapper and publish it to the usual package managers. Whatever procedure distros use to add new libraries could just as easily be used to push a landlock library/header to use it in C.
Interesting they added new syscalls, instead of handling configuration via /sys like with SELinux and AppArmor. I suppose it must be because of the no privilege principle.
Can sysadmins disable access to Landlock syscalls via seccomp? Not that I can see why they'd want to, just wondering how this is layered.
I suppose the problem might be if the system has been set up at some earlier point in time to whitelist a set of syscalls for a process and, as Landlock is newer, its syscall numbers won't be included. A program that has been updated to use Landlock while a seccomp policy that predates Landlock is applied would presumably be terminated with SIGSYS due to this?
How can a program determine if Landlock is present without just trying the syscalls and seeing if they work?
You can restrict the landlock syscalls with seccomp.
I also don't think doing so is extraordinarily useful.
If you allow something in landlock, it's still subject to traditional DAC and other restrictions because its a stackable LSM. It can only restrict existing access, not allow new accesses.
I think it's a reasonable question. The answer is that not everything does indeed run in a VM or a container: lots of things (notably on developer machines) run directly in a host user context, where they have access to all kinds of global state that they don't really need (developer credentials, browser state, etc.).
But also: even within a container (which isn't itself a sandbox) or a VM, you still have concentric circles of trust and/or privilege. If you're installing arbitrary dependencies from the Internet, for example, you probably want a basic initial defense of preventing those dependencies from exfiltrating your secrets at build time.
> It provides a simple, developer-friendly way to add defense-in-depth to applications.
Defense in depth. Lock your valuables inside a safe,
inside of your locked house. Why lock them in a safe when your house is already locked? Because if someone breaks into your house, you want additional defense "just in case". So just in case I wrote some shitty code and my server got hacked, lock the valuables in a safe anyway so that thief can't steal the expensive silverware (prod credentials).
i have zero experience with linux system programming so i'm probably missing something, but what's the point of an application restricting itself at runtime? if the application were compromised in some way, wouldn't it simply un-restrict itself?
For sandboxes where the underlying software is assumed to be non-hostile (e.g. browser sandboxes), these kind of restrictions can be applied very early in a program's execution. If the program doesn't accept any untrusted input until after the restrictions are applied, it can still provide a strong defense against escalation in the event of a vulnerability.
LWN's article on unveil() is a good explanation - the restrictions are permanently applied to the process and its children until termination:
https://lwn.net/Articles/767137/
Since it can’t re-enable privileges during runtime, the compromise would have to modify its own code and restart; if you don’t allow the running process to access its own code, it couldn’t make any changes that would persist across a restart of the code.
codex-cli is a neat example of an open source Rust program that uses Landlock to run commands that an LLM comes up with when writing code (see [1]). The model is that a user trusts the agent program (codex-cli), but has much more limited trust of the commands the remote LLM asks codex-cli to run.
Comparing landlock to containers isn't really an apples to apples comparison. Containers use a bunch of linux security mechanisms together like chroot seccomp and user namespaces to accomplish their goals. Landlock is just another building block that devs can use.
Fun fact: because landlock is unprivleged, you can even use it inside containers; or to build an unprivileged container runtime :)
Also, it's very easy to write your own LandLock policy in the programming language of your choice and wrap whatever program you like rather than downloading stuff from Github. Here's another example in Go:
It allows running non/semi-trusted workloads with isolation. Pretty useful to onboard applications into a proper scheduler with all bells and whistles without having to containerise, but still with decent levels of isolation between them.
LandLock is a Minor LSM intended for software developers. They incorporate it into their source code to limit where the programs may read/write. Here's a simple Go example:
package main
import (
"flag"
"fmt"
"github.com/landlock-lsm/go-landlock/landlock"
"io/ioutil"
"log"
"os"
)
// simple program that demonstrates how landlock works in Go on Linux systems.
// Requires 5.13 or newer kernel and .config should look something like this:
// CONFIG_SECURITY_LANDLOCK=y
// CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo"
func main() {
var help = flag.Bool("help", false, "landlock-example -f /path/to/file.txt")
var file = flag.String("f", "", "the file path to read")
flag.Parse()
if *help || len(os.Args) == 1 {
flag.PrintDefaults()
return
}
// allow the program to read files in /home/user/tmp
err := landlock.V1.RestrictPaths(landlock.RODirs("/home/user/tmp"))
if err != nil {
log.Fatal(err)
}
// attempt to read a file
bytes, err := ioutil.ReadFile(*file)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(bytes))
}
I feel like I need to ask; did you write this comment and the code example yourself, or did you ask an AI to generate it? If it's AI, why didn't you disclose it? If it's the former, why the weird formatting etc instead of linking to one of the official examples at https://github.com/landlock-lsm/go-landlock/blob/main/exampl... ?
I don't understand why someone would wrap an untrusted application with their own code vs using something like Systemd's exec capabilities to do the same without having to have a binary wrapper. What benefits do you see over the systemd solution?
Systemd's exec capabilities are great, but don't allow the application developer to dynamically restrict access rights to resources. So you could restrict a text editor for instance to the file it was launched to edit, instead of a hardcoded directory.
I've been messing with sandboxing using "bwrap" for random itch.io games I download to play and it isn't trivial to get it working with least privileges. I have so far been unable to get "Microlandia" to run, but other Unity games are running just fine under "bwrap". I am excited to see more Landlock tools emerge that make this task easier.
- https://github.com/containers/bubblewrap
- https://codeberg.org/dannyfritz/dotfiles/src/commit/38343008...
- https://explodi.itch.io/microlandia
What's the status of Landlock in container runtimes? A quick search makes it seem like CRIs are trying to define their own custom Landlock interface.
That will inevitably lag behind what the kernel supports, but more importantly I don't foresee many container image packagers, Helm recipe maintainers and other YAML wranglers getting into the business of maintaining a Landlock sandbox policy.
It makes sense for an application to use Landlock directly to sandbox some parser or other sensitive component. But if the CRI just blocks the syscalls by default, no infra person is going to take on the maintainance of their own sandbox policy for every app. The app will just see ENOSYS and not be sandboxed.
I might be missing the whole idea here, but I really don't see why we need some custom layer in the middle instead of having container runtimes let the security syscalls through?
I am puzzled by this:
> A official c library doesn’t exist yet unfortunately, but there’s several out there you can try.
> Landlock is a Linux Security Module (LSM) available since Linux 5.13
Since when is not a C API the first and foremost interface for developers when it comes to Linux kernel stuff?
The first and foremost interface of the kernel is the syscall interface aka the uapi. libc and other C libraries like liburing or libcap are downstream of that. Many syscalls still don't have wrappers in libc after years of use.
Thanks for clarification! I meant more, why isn't there a C API first, but Rust, Haskell, and Go before that — that's kind of surprising or new to me.
I read the article as saying that there's no official C library but unofficial ones do exist. Quote below, emphasis mine.
> A official c library doesn’t exist yet unfortunately, but there’s several out there you can try.
Also, it looks like there is more than zero support for C programs calling Landlock APIs. Even without a 3rd-party library you're not just calling syscall() with a magic number:
https://docs.kernel.org/userspace-api/landlock.html
https://github.com/torvalds/linux/blob/6bda50f4/include/uapi...
https://github.com/torvalds/linux/blob/6bda50f4/include/linu...
I don't understand what you mean. There's no "official" Rust, Haskell and Go APIs for this thing either. All libraries available seem to be just what some third party made available. There's also several C libraries, just none that have been officially endorsed by the Linux kernel team.
Go is famous for not needing libc and talking to the kernel. Rust and Haskell have communities that are very interested in safety and security, so they are earlier adopters.
For C, unofficial support apparently sufficed for now.
It's pretty subtle but it's referring to The C Library, libc.{a,so,dll,etc}. The library provided by your toolchain that supports the language.
Meaning glibc or musl or your favorite C library probably doesn't have this yet, but since the system calls are well defined you can use A C library (create your own header file using the _syscallN macro for example).
The lack of a C API should not stop any C developers from using it, hopefully. The wrapper libraries are relatively simple (i.e. https://codeberg.org/git-bruh/landbox) and both Rust and Go can expose a C FFI in case developers would rather link against a more "official" library instead.
The Linux kernel has a relatively simple example on how to use the syscall even if you can't find a library to deal with it for you: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
There is no "liblandlock" or whatever, though there totally could be. The only reason Rust, Go, and Haskell have an easy-to-use API for this syscall is because someone bothered to implement a wrapper and publish it to the usual package managers. Whatever procedure distros use to add new libraries could just as easily be used to push a landlock library/header to use it in C.
There is a C API. man landlock_add_rule for example.
https://github.com/torvalds/linux/blob/master/include/uapi/l...
you can add simple one-line wrappers if you don't like using syscall() function.
I use this and have no problems with it: https://github.com/marty1885/landlock-unveil
Interesting they added new syscalls, instead of handling configuration via /sys like with SELinux and AppArmor. I suppose it must be because of the no privilege principle.
Can sysadmins disable access to Landlock syscalls via seccomp? Not that I can see why they'd want to, just wondering how this is layered.
I suppose the problem might be if the system has been set up at some earlier point in time to whitelist a set of syscalls for a process and, as Landlock is newer, its syscall numbers won't be included. A program that has been updated to use Landlock while a seccomp policy that predates Landlock is applied would presumably be terminated with SIGSYS due to this?
How can a program determine if Landlock is present without just trying the syscalls and seeing if they work?
You can restrict the landlock syscalls with seccomp.
I also don't think doing so is extraordinarily useful.
If you allow something in landlock, it's still subject to traditional DAC and other restrictions because its a stackable LSM. It can only restrict existing access, not allow new accesses.
As a noob in this space, why is this needed when every job already runs inside a VM or a container? Again, a noob so please bear with me
I think it's a reasonable question. The answer is that not everything does indeed run in a VM or a container: lots of things (notably on developer machines) run directly in a host user context, where they have access to all kinds of global state that they don't really need (developer credentials, browser state, etc.).
But also: even within a container (which isn't itself a sandbox) or a VM, you still have concentric circles of trust and/or privilege. If you're installing arbitrary dependencies from the Internet, for example, you probably want a basic initial defense of preventing those dependencies from exfiltrating your secrets at build time.
Containers are NOT security wrappers. They are convenience to avoid dependency hell from lazy people.
VM's can be security wrappers, but if you expose all of $HOME to a VM, then there really isn't much security happening, in terms of your data.
This lets developers of applications harden themselves, it doesn't require the end-user to do anything(like put it in a VM).
> It provides a simple, developer-friendly way to add defense-in-depth to applications.
Defense in depth. Lock your valuables inside a safe, inside of your locked house. Why lock them in a safe when your house is already locked? Because if someone breaks into your house, you want additional defense "just in case". So just in case I wrote some shitty code and my server got hacked, lock the valuables in a safe anyway so that thief can't steal the expensive silverware (prod credentials).
Aren’t there existing methods to do this using selinux or apparmor?
i have zero experience with linux system programming so i'm probably missing something, but what's the point of an application restricting itself at runtime? if the application were compromised in some way, wouldn't it simply un-restrict itself?
For sandboxes where the underlying software is assumed to be non-hostile (e.g. browser sandboxes), these kind of restrictions can be applied very early in a program's execution. If the program doesn't accept any untrusted input until after the restrictions are applied, it can still provide a strong defense against escalation in the event of a vulnerability.
LWN's article on unveil() is a good explanation - the restrictions are permanently applied to the process and its children until termination: https://lwn.net/Articles/767137/
The kernel enforces that once the policy gets added it can't be removed.
So the restrictions are permanent for the life of the program. Even root can't undo them.
Since it can’t re-enable privileges during runtime, the compromise would have to modify its own code and restart; if you don’t allow the running process to access its own code, it couldn’t make any changes that would persist across a restart of the code.
codex-cli is a neat example of an open source Rust program that uses Landlock to run commands that an LLM comes up with when writing code (see [1]). The model is that a user trusts the agent program (codex-cli), but has much more limited trust of the commands the remote LLM asks codex-cli to run.
[1] https://developers.openai.com/codex/security/
As the article states. You can not give extra permissions only limit further.
So like using seccomp with a whitelist (fairly easy to do) with per-object access rights.
I'd love to see a comparison of landlock to restricted containers.
Comparing landlock to containers isn't really an apples to apples comparison. Containers use a bunch of linux security mechanisms together like chroot seccomp and user namespaces to accomplish their goals. Landlock is just another building block that devs can use.
Fun fact: because landlock is unprivleged, you can even use it inside containers; or to build an unprivileged container runtime :)
So it works also by using some cli utility to run my software for example?
Yup. There are tools that use landlock to accomplish just that.
https://github.com/Zouuup/landrun
All you gotta do is apply a policy and do a fork() exec(). There is also support in firejail.
Firejail requires SUID, LandLock does not.
Also, it's very easy to write your own LandLock policy in the programming language of your choice and wrap whatever program you like rather than downloading stuff from Github. Here's another example in Go:
Yeah, see e.g. sydbox: https://gitlab.exherbo.org/sydbox/sydbox
For a cool practical example, check out Nomad's (flexible workload orchestrator) exec2 task driver: https://github.com/hashicorp/nomad-driver-exec2
It allows running non/semi-trusted workloads with isolation. Pretty useful to onboard applications into a proper scheduler with all bells and whistles without having to containerise, but still with decent levels of isolation between them.
What the Landlock LSM can add to the state of Linux security
Is this a statement or a question?
whoops it got added by the post creation form. I thought it would appear as a subtitle not a comment lol
LandLock is a Minor LSM intended for software developers. They incorporate it into their source code to limit where the programs may read/write. Here's a simple Go example:
I feel like I need to ask; did you write this comment and the code example yourself, or did you ask an AI to generate it? If it's AI, why didn't you disclose it? If it's the former, why the weird formatting etc instead of linking to one of the official examples at https://github.com/landlock-lsm/go-landlock/blob/main/exampl... ?
Yup. In the application code itself is where landlock shines at the moment.
It's becoming increasingly usable as a wrapper for untrusted applications as well.
I don't understand why someone would wrap an untrusted application with their own code vs using something like Systemd's exec capabilities to do the same without having to have a binary wrapper. What benefits do you see over the systemd solution?
Systemd's exec capabilities are great, but don't allow the application developer to dynamically restrict access rights to resources. So you could restrict a text editor for instance to the file it was launched to edit, instead of a hardcoded directory.