[ANN] Landbox — Landlock "os/exec.Command()" replacement

78 views
Skip to first unread message

Nikita Loskutov

unread,
Mar 1, 2026, 2:09:33 AM (yesterday) Mar 1
to golang-nuts
Hello there!

I'm working on Landbox — Landlock "os/exec.Command()" replacement.

```go
package main

import "github.com/cnaize/landbox"

func main() {
    // allow only: ro="/usr", rw="/tmp"
    sandbox := landbox.NewSandbox([]string{"/usr"}, []string{"/tmp"}, nil)
    defer sandbox.Close()

    // deny everything else
    output, _ := sandbox.Command("ls", "/home").CombinedOutput()

    println(string(output))
    // Executing the sandboxed command...
    // ls: cannot open directory '/home': Permission denied
}
```

Github: https://github.com/cnaize/landbox

Any feedback is welcome!

Brian Candler

unread,
Mar 1, 2026, 4:05:39 AM (yesterday) Mar 1
to golang-nuts
As a starting point, it would be good if you explain what the use case is - what it does that's different to exec.Command, and how it does it?  (My first thought was: could it be cgroups or namespaces?)

There's no documentation, and the code is less than self-explanatory. Via some reverse-engineering I found:
* It sets some magic environment variables like LL_FS_RO, LL_FS_RW
* It reads in a binary blob "bin/sandboxer" (stored within the repo) and executes it in memory via a third-party library (github.com/liamg/memit)  - presumably to avoid needing to set the execute bit on the binary, or to bypass any "noexec" protections on the filesystem.
* Googling for those environment variables finds https://docs.kernel.org/admin-guide/LSM/landlock.html which shows use of a similar "sandboxer" binary

I repeat: the binary blob that it executes is stored inside the git repo. Do I run arbitrary binary blobs downloaded from the Internet?  Err, no thank you.  If this isn't a trojan horse, it certainly looks like it could be, and there's no way to tell if it is or it isn't.

So if you're going to do it this way, a key requirement for you is to establish a chain of trust to this binary. Either include the source code for "sandboxer", and the scripts required to build it from source; or sign the binary with some way to verify the signature back to a trusted source (which might be you, if you can persuade people that you are a trustworthy source). Or: don't include the binary at all, and give instructions for the user on how to build it themselves or download a binary from a trusted source (e.g. signed OS packages from well-known third-party sources).


If so, I wonder if it would be possible to implement what sandboxer.rs does directly in Go. Googling:

"golang landlock" => https://github.com/landlock-lsm/go-landlock
"golang linux security modules" => https://github.com/rogercoll/go-lsm

If it's for use in exec.Command then it may still require building a wrapper binary, but at least it could avoid the Rust toolchain.

Nikita Loskutov

unread,
Mar 1, 2026, 4:39:51 AM (yesterday) Mar 1
to Brian Candler, golang-nuts
Thanks for the critical feedback!

Let me clarify the architecture and the choice of the "binary blob":
1. Why a helper binary?
    Unlike go-landlock, which sandboxes the current process (making it irreversible for the entire application), Landbox is designed to isolate child processes only.
    To achieve this without complex CGO or re-executing the Go runtime (which is heavy), Landbox uses a minimalist (~50KB) static helper.
2. The binary helper has been built directly from the official Linux kernel samples (https://github.com/torvalds/linux/tree/v6.19/samples/landlock) using musl-gcc.
    If you wish, you can audit the source, rebuild it yourself, and replace the included binary file.
3. The memit library is used for both security and speed, allowing us to execute the binary helper directly from memory rather than writing it to the disk every time the sandbox runs.

If you have any further questions, let's talk. Thank you for your feedback!

Thanks,
Nikita Loskutov


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/MCzPu_IrEQs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/260264d8-e95a-4343-bb08-fb6a8c2919f0n%40googlegroups.com.

Brian Candler

unread,
Mar 1, 2026, 1:32:12 PM (17 hours ago) Mar 1
to golang-nuts
A minor thought: if you do want to run a binary like that, then instead of reading it from a separate file on disk, you can embed it directly into your Go program.

Available since: https://go.dev/doc/go1.16

Nikita Loskutov

unread,
Mar 1, 2026, 1:53:54 PM (17 hours ago) Mar 1
to Brian Candler, golang-nuts
Thanks for the suggestion, you are absolutely right, and that’s exactly how Landbox is architected.

I’m already using go:embed to keep the library zero-dependency. You can see the implementation here:
https://github.com/cnaize/landbox/blob/v0.2.0/helper.go#L9-L13

Thanks,
Nikita Loskutov


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/MCzPu_IrEQs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

Brian Candler

unread,
5:13 AM (1 hour ago) 5:13 AM
to golang-nuts
Ah yes, sorry I saw "ReadFile" but didn't look any more closely :-)
Reply all
Reply to author
Forward
0 new messages