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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
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 ¶
RODirs is a Rule which grants common read-only access to files and directories and permits executing files.
func ROFiles ¶
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 ¶
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 ¶
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 ¶
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) WithIoctlDev ¶
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 ¶
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 ¶
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 ¶
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().
Source Files ¶
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. |