`dmesg` shows the connections it blocks (I think this is maybe the audit feature). I used an example sandboxer.c as a base (https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux...) except I just set mine up to not touch file restricting, just networking so that it has that one whitelisted incoming port.
./network-sandboxer-tool 8000 some-program arg1 arg2 etc.
I like it because it just works as an unprivileged usermode program without setting anything up. A tiny C program. It works inside containers without having to set up any firewalls. Aside from having to compile a small C program, there is little fuss. I found the whole Landlock thing trying to find out alternatives to bubblewrap because I couldn't figure out how to do the same thing in bwrap conveniently.The "unprivileged" in "Landlock: unprivileged access control" for me was the selling point for this use case.
I don't consider this effective against actively adversarial programs though.
- https://github.com/containers/bubblewrap
- https://codeberg.org/dannyfritz/dotfiles/src/commit/38343008...
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?
> 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?
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?
Even the example code builds a somewhat questionable 'sandbox' that hits a problem discussed in those threads. Say we're ok with an app having r-w access to home except for a couple of places such as ~/.ssh. Now you could try to add a rule to exclude access to ~/.ssh, but the security object must exist when the policy is being established (the rules refer to directories by fds). As such, no .ssh directory, means not rules denying access. You start a sandboxed app thinking you've set up a tight sandbox, at some point ~/.ssh gets created, and now the untrusted app can read your ssh keys.
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.
My questions are:
- How does this help with malware? I want to craft an environment where any program trying to read f.ex. anything inside ~/.ssh is automatically denied. I don't want a malicious build script to exfiltrate all my sensitive data!
- It seems that this software is well-positioned for us to write application launchers with, is that true? If so, well, I like the idea but it seems too manual.
Maybe I'm looking at the wrong thing. I strongly prefer deny-by-default in an invisible manner i.e. my system to refuse most requests to access this or that. Not opting in to it. Bad actors will not graciously limit their own program with Landlock. They'll try to get anything before I can even blink my eyes.
I feel I'm missing crucially important context. Can somebody help?
https://man7.org/linux/man-pages/man7/landlock.7.html
But i suppose i am missing somehting then people would like...
What would you want an library to do here? abstract over it to make it easier? (relatively simple api already)
legit question, not trying to poke anyone here.. trying to find out what ppl expect from libraries which wrap around these syscalls or stdlib things.
I'd love to see a comparison of landlock to restricted containers.
I did not know of this and I am looking for simple ways to isolate processes for multiple reasons. I am building a coding agent, https://github.com/brainless/nocodo, that runs (headless) on a Linux instance. Generated code is immediately available for demo.
I am new to isolation and not looking for a container based approach. Isolation from a security standpoint but I do not know enough. This approach looks like a great start for me.
That's like relying on criminals to cuff themselves when they have committed a crime.
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))
}