FFFF
Skip to content

Latest commit

 

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Simple sandboxer tool

sst (Simple sandboxer tool) is a small CLI tool that will run some other program while applying sandboxing, using Linux Landlock API. It requires no root privileges to run and it is trying to be "as little fuss" as possible; a single sst.c-file implementation that only demands a C compiler and some Linux kernel headers to compile.

Example:

# What this does:
#
# 1) No outgoing TCP connections
# 2) Incoming TCP connections only allowed on port 5000
# 3) No filesystem write access
#

$ sst ENABLE_NETWORK_SANDBOXING ENABLE_FILESYSTEM_SANDBOXING ALLOW_INCOMING_TCP_PORT:5000 PATH_BENEATH_EXEC:/ -- java -jar some-program.jar

See CHEATSHEET.md in this repository for a quick reference.

Compiling

If you have a Linux machine with development tools, then make hopefully suffices. It will compile sst to the current directory.

$ make
$ ./sst <options here>

sst.c is, on purpose, a single file with no dependencies other than Kernel headers, so you could also try:

$ gcc -Wall -O2 sst.c -o sst
$ ./sst <options here>

Usage

The command line tool is called sst (for "Simple Sandboxer Tool"). By default, it will not restrict anything.

$ sst <options...> -- <command> <arg1> <arg2> ... <argN>

Note: The -- is mandatory. You specify on the command line, before the --, how do you want to sandbox.

The ordering of the options before -- does not matter.

You can nest sst calls, e.g. one only does filesystem sandboxing, and another does networking sandboxing. The permissions can only be tightened; an sst cannot increase privileges under Landlock.

Examples

Open a shell that can't do (TCP) networking:

$ sst ENABLE_NETWORK_SANDBOXING -- bash
$ nc -v example.org 80
Warning: inverse host lookup failed for 104.18.3.24:
Warning: inverse host lookup failed for 104.18.2.24:
example.org [104.18.3.24] 80 (http) : Permission denied

(note: some programs may know HTTP3/QUIC which uses UDP instead, as mentioned elsewhere in this README.md. They would still work.).

Run a program with a read-only root and some directories with write permission:

$ sst ENABLE_FILESYSTEM_SANDBOXING PATH_BENEATH_EXEC:/ PATH_BENEATH_WRITE:/workspace/my_program -- my_program --option 123

Lazy template to use

This is often my starting point when I design a sandboxer for some program.

This stops networking and stops filesystem write access entirely. The root is set to PATH_BENEATH_EXEC which lets the opened bash shell to execute and run commands; but none of these commands can leave a mark on the filesystem.

$ sst ENABLE_FILESYSTEM_SANDBOXING ENABLE_NETWORK_SANDBOXING PATH_BENEATH_EXEC:/ -- bash

Remove ENABLE_NETWORK_SANDBOXING if you would like to allow Internet (or fine-tune that with the networing-related sandboxing options).

Add PATH_BENEATH_WRITE:<directory> as needed to allow selectively write access to some parts of the filesystem.

Sandboxing

You might be interested in CHEATSHEET.md in this repository for an uncluttered "cheat sheet" version of this information.

Forbidden operations generally result in an EPERM error given to the caller; refer to Landlock documentation for details.

Filesystem-related sandboxing

To use any options below, you must specify, somewhere, on the command line, before the -- separator, the trigger option word ENABLE_FILESYSTEM_SANDBOXING. This enables the use of the options below, and it also restricts all filesystem access except the ones specified.

  • FILE_READ:<filepath>: allow reading from a specific file. The file has to be an actual file, not a directory. Executing the file is not allowed.
  • FILE_EXEC:<filepath>: same as FILE_READ but adds execution privileges.
  • FILE_WRITE:<filepath>: same as FILE_READ but adds write privileges (not execution privileges).
  • FILE_EXEC_WRITE:<filepath>: combined FILE_EXEC and FILE_WRITE (you can also separately specify them).
  • FILE_WRITE_EXEC:<filepath>: alias for FILE_EXEC_WRITE.
  • PATH_BENEATH_READ:<dir>: allow reading (not executing) everything under <dir>. The path must refer to a directory.
  • PATH_BENEATH_EXEC:<dir>: same as PATH_BENEATH_READ but also gives execution privileges.
  • PATH_BENEATH_WRITE:<dir>: same as PATH_BENEATH_READ but also gives write privileges.
  • PATH_BENEATH_EXEC_WRITE:<dir>: combined PATH_BENEATH_EXEC and PATH_BENEATH_WRITE (you can also separately specify them).
  • PATH_BENEATH_WRITE_EXEC:<dir>: alias for PATH_BENEATH_EXEC_WRITE.

Networking-related sandboxing

To use any options below, you must specify, somewhere, on the command line, before the -- separator, the trigger option word ENABLE_NETWORK_SANDBOXING. This enables the other options, and it also restricts all TCP networking except the ones specified.

Note: this does not restrict other forms of network communications (e.g. UDP). QUIC for example is UDP, so this tool cannot block it. (try curl https://google.com/ while sandboxing networking; a modern enough curl will use UDP!).

As of writing of this: ABI 8 of Landlock API looks like UDP support is coming.

  • ALLOW_INCOMING_TCP_PORT:<port>: allow incoming connections to the given port. 0 can be specified, read bind() documentation on what does binding to port 0 mean exactly.
  • ALLOW_OUTGOING_TCP_PORT:<port>: allow outgoing connections to the given port.

Warts, issues, thoughts

Scope of Landlock and intended use

Landlock at least in its current form is not a foolproof sandboxing system; look for other technologies (e.g. bubblewrap, firejail on Linux; App Sandboxing on MacOS; and use actual firewalls to stop networking) if you are working with code you expect to be actively adversarial that makes an effort to work around the sandbox. I consider sst to be the "quick & lazy sandboxing method that I can just slap on things, bam done" route, and I escalate to more thorough methods depending on what am I dealing with.

Here are some use cases I've used this for so far:

  1. stop unwanted telemetry (my original motivation; in late 2025 I touched a JavaScript framework with a particularly facetious attitude about telemetry and got annoyed :-)
  2. sandbox my own applications. I especially do this with software that I have to deal with and that is exposed to the Internet; e.g. Minecraft servers, <insert your latest 21st century Web/JavaScript thingamajig framework>-based applications.

I consider this to be, at best, one layer of defense, and I think at the moment this only is effective because most software I target with this are not expecting to be sandboxed (i.e. software by unscrupulous tech companies filled with telemetry or some other user-hostile code), or they are not hostile programs to begin with.

Future improvements to sst might be about adding features to help with observability rather than sandboxing. Landlock itself has some amount of "audit features" but I have not studied them as of writing this section right now, or if it makes sense to put such features into sst specifically.

Filesystem sandboxing may be overly restrictive.

The sst filesystem restrictions restrict a lot of operations; the most permissive setting you can set (while also having filesystem sandboxing on at all) is this combo:

static const __u32 EXEC_WRITE_FILE_ACCESS_DIR =
    LANDLOCK_ACCESS_FS_EXECUTE |
    LANDLOCK_ACCESS_FS_READ_FILE |
    LANDLOCK_ACCESS_FS_READ_DIR |
    LANDLOCK_ACCESS_FS_WRITE_FILE |
    LANDLOCK_ACCESS_FS_REMOVE_FILE |
    LANDLOCK_ACCESS_FS_REMOVE_DIR |
    LANDLOCK_ACCESS_FS_MAKE_REG |
    LANDLOCK_ACCESS_FS_MAKE_DIR |
    LANDLOCK_ACCESS_FS_MAKE_SYM |
    LANDLOCK_ACCESS_FS_TRUNCATE |
    LANDLOCK_ACCESS_FS_IOCTL_DEV;

Landlock itself is a bit more fine-grained (and likely will be more so in the future); so this is a missing feature in sst.

The current set of options you can set reflect my own use of this tool, but I will expand and improve over time if I find a good design for it.

Non-TCP networking is not blocked at all (e.g. UDP, used in HTTP3/QUIC). I will likely add it as soon as my system gets updated enough to have it in the installed Kernel headers and I am able to test it conveniently. One of the use cases of this sandboxing is to stop unwanted telemetry, but if the telemetry uses UDP it kind of defeats the point of sandboxing.

I suck at naming

Networking uses the ALLOW verb, e.g. ALLOW_INCOMING_TCP_PORT.

Filesystem settings however use no such verbiage. Inconsistent.

Also my names are long and capitalized and they look like they are shouting.

I might at some point add better designed names as aliases; the current names are what they are because I accidentally got used to them.

License

GPL3 only.

About

Simple Sandboxer Tool (sst), based on Linux Landlock API. A single sst.c file, runs without fuss in an unprivileged environment.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0