📚 [Godoc](https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock)
| 🌍 [landlock.io](https://landlock.io/)

# Go Landlock library

The Go-Landlock library restricts the current processes' ability to
use files, using Linux 5.13's Landlock feature.

## TL;DR: Example

In a Go program, after starting up and doing program initialization work, run:

```
err := landlock.V6.BestEffort().RestrictPaths(
    landlock.RODirs("/usr", "/bin"),
    landlock.RWDirs("/tmp"),
)
```

After this invocation, your program can only access the specified paths.

Landlock is a Linux kernel feature and can restrict the following types of access:

* Filesystem access
* Some network operations
* Some IPC operations (not implemented yet in Go: [#35](https://github.com/landlock-lsm/go-landlock/issues/35))

More details and examples in the [Go-Landlock
documentation](https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock).

## Goals

Goals of Go-Landlock are:

* Make unprivileged sandboxing easy to use and effective.
* Keep Go-Landlock's implementation at an easily auditable size.

## Technical implementation

Some implementation notes that should simplify auditing.

### Applying Landlock to all Goroutines

The Landlock kernel API enabled Landlock for the current OS thread,
but the mapping between Goroutines and OS threads is not 1:1, and
there are few guarantees about it.

Because the mapping between OS threads and Goroutines is not
guaranteed anyway, the Go-Landlock API always enables the given
Landlock for the entire process.

This is done using the `psx` library, which is a helper library for
the `libcap` library for working with Linux capabilities. `psx`
exposes an API that does a system call with the given arguments on
*every OS thread* in a running Go program.

For pure Go programs, `psx` does the same as the
[`syscall.AllThreadsSyscall`
function](https://pkg.go.dev/syscall#AllThreadsSyscall) in the Go
runtime (and that case is straightforward to understand).

For programs linked with `cgo`, there can be more OS threads than just
the ones that were started by the Go runtime. To cover these, `psx`
intercepts calls to the pthread library to infer the list of all
threads, and then uses a trick with Unix signals to execute the given
system call on all of them. (This is unfortunately common practice for
system calls that only apply to the current thread -- glibc uses the
same approach for some system calls. To dig this up in the glibc
source, see `sysdeps/nptl/setxid.h` and its users.)

A deeper discussion of `psx` can be found at:
https://sites.google.com/site/fullycapable/who-ordered-libpsx
