landlock

package
v0.0.0-...-479ddab Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2024 License: MIT Imports: 6 Imported by: 14

Documentation

Overview

Package landlock restricts a Go program's ability to use files and networking.

Restricting file access

The following invocation will restrict all goroutines so that they can only read from /usr, /bin and /tmp, and only write to /tmp:

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

This will restrict file access using Landlock V5, if available. If unavailable, it will attempt using earlier Landlock versions than the one requested. If no Landlock version is available, it will still succeed, without restricting file accesses.

Restricting networking

The following invocation will restrict all goroutines so that they can only bind to TCP port 8080 and only connect to TCP port 53:

err := landlock.V5.BestEffort().RestrictNet(
    landlock.BindTCP(8080),
    landlock.ConnectTCP(53),
)

This functionality is available since Landlock V5.

Restricting file access and networking at once

The following invocation restricts both file and network access at once. The effect is the same as calling Config.RestrictPaths and Config.RestrictNet one after another, but it happens in one step.

err := landlock.V5.BestEffort().Restrict(
    landlock.RODirs("/usr", "/bin"),
    landlock.RWDirs("/tmp"),
    landlock.BindTCP(8080),
    landlock.ConnectTCP(53),
)

More possible invocations

landlock.V5.RestrictPaths(...) (without the call to Config.BestEffort) enforces the given rules using the capabilities of Landlock V5, but returns an error if that functionality is not available on the system that the program is running on.

Landlock ABI versioning

The Landlock ABI is versioned, so that callers can probe for the availability of different Landlock features.

When using the Go Landlock package, callers need to identify at which ABI level they want to use Landlock and call one of the restriction methods (e.g. Config.RestrictPaths) on the corresponding ABI constant.

When new Landlock versions become available in landlock, users will manually need to upgrade their usages to higher Landlock versions, as there is a risk that new Landlock versions will break operations that their programs rely on.

Graceful degradation on older kernels

Programs that get run on different kernel versions will want to use the Config.BestEffort method to gracefully degrade to using the best available Landlock version on the current kernel.

In this case, the Go Landlock library will enforce as much as possible, but it will ensure that all the requested access rights are permitted after Landlock enforcement.

Current limitations

Landlock can not currently restrict all file system operations. The operations that can and can not be restricted yet are listed in the Kernel Documentation about Access Rights.

Enabling Landlock implicitly turns off the following file system features:

  • File reparenting: renaming or linking a file to a different parent directory is denied, unless it is explicitly enabled on both directories with the "Refer" access modifier, and the new target directory does not grant the file additional rights through its Landlock access rules.
  • Filesystem topology modification: arbitrary mounts are always denied.

These are Landlock limitations that will be resolved in future versions. See the Kernel Documentation about Current Limitations for more details.

Multithreading Limitations

This warning only applies to programs using cgo and linking C libraries that start OS threads through means other than pthread_create() before landlock is called:

When using cgo, the landlock package relies on libpsx in order to apply the rules across all OS threads, (rather than just the ones managed by the Go runtime). psx achieves this by wrapping the C-level phtread_create() API which is very commonly used on Unix to start threads. However, C libraries calling clone(2) through other means before landlock is called might still create threads that won't have Landlock protections.

Index

Constants

This section is empty.

Variables

View Source
var (
	// Landlock V1 support (basic file operations).
	V1 = abiInfos[1].asConfig()
	// Landlock V2 support (V1 + file reparenting between different directories)
	V2 = abiInfos[2].asConfig()
	// Landlock V3 support (V2 + file truncation)
	V3 = abiInfos[3].asConfig()
	// Landlock V4 support (V3 + networking)
	V4 = abiInfos[4].asConfig()
	// Landlock V5 support (V4 + ioctl on device files)
	V5 = abiInfos[5].asConfig()
)

These are Landlock configurations for the currently supported Landlock ABI versions, configured to restrict the highest possible set of operations possible for each version.

The higher the ABI version, the more operations Landlock will be able to restrict.

Functions

This section is empty.

Types

type AccessFSSet

type AccessFSSet uint64

AccessFSSet is a set of Landlockable file system access operations.

func (AccessFSSet) String

func (a AccessFSSet) String() string

type AccessNetSet

type AccessNetSet uint64

AccessNetSet is a set of Landlockable network access rights.

func (AccessNetSet) String

func (a AccessNetSet) String() string

type Config

type Config struct {
	// contains filtered or unexported fields
}

The Landlock configuration describes the desired set of landlockable operations to be restricted and the constraints on it (e.g. best effort mode).

func MustConfig

func MustConfig(args ...interface{}) Config

MustConfig is like NewConfig but panics on error.

func NewConfig

func NewConfig(args ...interface{}) (*Config, error)

NewConfig creates a new Landlock configuration with the given parameters.

Passing an AccessFSSet will set that as the set of file system operations to restrict when enabling Landlock. The AccessFSSet needs to stay within the bounds of what go-landlock supports. (If you are getting an error, you might need to upgrade to a newer version of go-landlock.)

func (Config) BestEffort

func (c Config) BestEffort() Config

BestEffort returns a config that will opportunistically enforce the strongest rules it can, up to the given ABI version, working with the level of Landlock support available in the running kernel.

Warning: A best-effort call to RestrictPaths() will succeed without error even when Landlock is not available at all on the current kernel.

func (Config) Restrict

func (c Config) Restrict(rules ...Rule) error

Restrict restricts all types of access which is restrictable with the Config.

Using Landlock V4, this is equivalent to calling both [RestrictPaths] and [RestrictNet] with the subset of arguments that apply to it.

In future Landlock versions, this function might restrict additional kinds of operations outside of file system access and networking, provided that the Config specifies these.

func (Config) RestrictNet

func (c Config) RestrictNet(rules ...Rule) error

RestrictNet restricts network access in goroutines.

Using Landlock V4, this function will disallow the use of bind(2) and connect(2) for TCP ports, unless those TCP ports are specifically permitted using these rules:

  • ConnectTCP permits connect(2) operations to a given TCP port.
  • BindTCP permits bind(2) operations on a given TCP port.

These network access rights are documented in more depth in the Kernel Documentation about Network flags.

func (Config) RestrictPaths

func (c Config) RestrictPaths(rules ...Rule) error

RestrictPaths restricts all goroutines to only "see" the files provided as inputs. After this call successfully returns, the goroutines will only be able to use files in the ways as they were specified in advance in the call to RestrictPaths.

Example: The following invocation will restrict all goroutines so that it can only read from /usr, /bin and /tmp, and only write to /tmp:

err := landlock.V3.RestrictPaths(
    landlock.RODirs("/usr", "/bin"),
    landlock.RWDirs("/tmp"),
)
if err != nil {
    log.Fatalf("landlock.V3.RestrictPaths(): %v", err)
}

RestrictPaths returns an error if any of the given paths does not denote an actual directory or file, or if Landlock can't be enforced using the desired ABI version constraints.

RestrictPaths also sets the "no new privileges" flag for all OS threads managed by the Go runtime.

Restrictable access rights

The notions of what "reading" and "writing" mean are limited by what the selected Landlock version supports.

Calling RestrictPaths with a given Landlock ABI version will inhibit all future calls to the access rights supported by this ABI version, unless the accessed path is in a file hierarchy that is specifically allow-listed for a specific set of access rights.

The overall set of operations that RestrictPaths can restrict are:

For reading:

  • Executing a file (V1+)
  • Opening a file with read access (V1+)
  • Opening a directory or listing its content (V1+)

For writing:

  • Opening a file with write access (V1+)
  • Truncating file contents (V3+)

For directory manipulation:

  • Removing an empty directory or renaming one (V1+)
  • Removing (or renaming) a file (V1+)
  • Creating (or renaming or linking) a character device (V1+)
  • Creating (or renaming) a directory (V1+)
  • Creating (or renaming or linking) a regular file (V1+)
  • Creating (or renaming or linking) a UNIX domain socket (V1+)
  • Creating (or renaming or linking) a named pipe (V1+)
  • Creating (or renaming or linking) a block device (V1+)
  • Creating (or renaming or linking) a symbolic link (V1+)
  • Renaming or linking a file between directories (V2+)

Future versions of Landlock will be able to inhibit more operations. Quoting the Landlock documentation:

It is currently not possible to restrict some file-related
actions accessible through these syscall families: chdir(2),
stat(2), flock(2), chmod(2), chown(2), setxattr(2), utime(2),
ioctl(2), fcntl(2), access(2). Future Landlock evolutions will
enable to restrict them.

The access rights are documented in more depth in the Kernel Documentation about Access Rights.

Helper functions for selecting access rights

These helper functions help selecting common subsets of access rights:

  • RODirs selects access rights in the group "for reading". In V1, this means reading files, listing directories and executing files.
  • RWDirs selects access rights in the group "for reading", "for writing" and "for directory manipulation". This grants the full set of access rights which are available within the configuration.
  • ROFiles is like RODirs, but does not select directory-specific access rights. In V1, this means reading and executing files.
  • RWFiles is like RWDirs, but does not select directory-specific access rights. In V1, this means reading, writing and executing files.

The PathAccess rule lets callers define custom subsets of these access rights. AccessFSSets permitted using PathAccess must be a subset of the AccessFSSet that the Config restricts.

func (Config) String

func (c Config) String() string

String builds a human-readable representation of the Config.

type FSRule

type FSRule struct {
	// contains filtered or unexported fields
}

FSRule is a Rule which permits access to file system paths.

func PathAccess

func PathAccess(accessFS AccessFSSet, paths ...string) FSRule

PathAccess is a Rule which grants the access rights specified by accessFS to the file hierarchies under the given paths.

When accessFS is larger than what is permitted by the Landlock version in use, only the applicable subset of accessFS will be used.

Most users should use the functions RODirs, RWDirs, ROFiles and RWFiles instead, which provide canned rules for commonly used values of accessFS.

Filesystem access rights are represented using bits in a uint64. The individual access rights and their meaning are defined in the landlock/syscall package and explained further in the Kernel Documentation about Access Rights.

accessFS must be a subset of the permissions that the Config restricts.

func RODirs

func RODirs(paths ...string) FSRule

RODirs is a Rule which grants common read-only access to files and directories and permits executing files.

func ROFiles

func ROFiles(paths ...string) FSRule

ROFiles is a Rule which grants common read access to individual files, but not to directories, for the file hierarchies under the given paths.

func RWDirs

func RWDirs(paths ...string) FSRule

RWDirs is a Rule which grants full (read and write) access to files and directories under the given paths.

Noteworthy operations which are *not* covered by RWDirs:

  • RWDirs does *not* grant the right to *reparent or link* files across different directories. If this access right is required, use FSRule.WithRefer.

  • RWDirs does *not* grant the right to *use IOCTL* on device files. If this access right is required, use FSRule.WithIoctlDev.

func RWFiles

func RWFiles(paths ...string) FSRule

RWFiles is a Rule which grants common read and write access to files under the given paths, but it does not permit access to directories.

Noteworthy operations which are *not* covered by RWFiles:

  • RWFiles does *not* grant the right to *use IOCTL* on device files. If this access right is required, use FSRule.WithIoctlDev.

func (FSRule) IgnoreIfMissing

func (r FSRule) IgnoreIfMissing() FSRule

IgnoreIfMissing gracefully ignores missing paths.

Under normal circumstances, referring to a non-existing path in a rule would lead to a runtime error. When the rule uses the IgnoreIfMissing modifier, these runtime errors are ignored. This can be useful e.g. for optional configuration paths, which are only ever read by a program.

func (FSRule) String

func (r FSRule) String() string

func (FSRule) WithIoctlDev

func (r FSRule) WithIoctlDev() FSRule

WithIoctlDev adds the "ioctl dev" access right to a FSRule.

It is uncommon to need this access right, so it is not part of RWFiles or RWDirs.

func (FSRule) WithRefer

func (r FSRule) WithRefer() FSRule

WithRefer adds the "refer" access right to a FSRule.

Notably, asking for the "refer" access right does not work on kernels below 5.19. In best effort mode, this will fall back to not using Landlock enforcement at all on these kernel versions. If you want to use Landlock on these kernels, do not use the "refer" access right.

type NetRule

type NetRule struct {
	// contains filtered or unexported fields
}

func BindTCP

func BindTCP(port uint16) NetRule

BindTCP is a Rule which grants the right to bind a socket to a given TCP port.

In Go, the bind(2) operation is usually run as part of net.Listen().

func ConnectTCP

func ConnectTCP(port uint16) NetRule

ConnectTCP is a Rule which grants the right to connect a socket to a given TCP port.

In Go, the connect(2) operation is usually run as part of net.Dial().

func (NetRule) String

func (n NetRule) String() string

type PathOpt deprecated

type PathOpt = Rule

PathOpt is a deprecated alias for Rule.

Deprecated: This alias is only kept around for backwards compatibility and will disappear with the next major release.

type Rule

type Rule interface {
	// contains filtered or unexported methods
}

Rule represents one or more Landlock rules which can be added to a Landlock ruleset.

Directories

Path Synopsis
Package lltest has helpers for Landlock-enabled tests.
Package lltest has helpers for Landlock-enabled tests.
Package syscall provides a low-level interface to the Linux Landlock sandboxing feature.
Package syscall provides a low-level interface to the Linux Landlock sandboxing feature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL