syscallset

package module
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Nov 29, 2024 License: BSD-3-Clause Imports: 5 Imported by: 2

README

syscallset-go

Go Reference CI REUSE status

syscallset-go is an easy to use Go library allowing any Go program to restrict its own capabilities on Linux through seccomp-bpf. This makes it possible, for example, to prevent starting other malicious programs or establishing network connections, which drastically reduces the attack surface, also of third libraries.

Since secomp-bpf must be given an exact list of syscalls, which are even architecture-dependent, the creation and maintenance of an allow list is extremely tedious. An easier way is shown by OpenBSD with its pledge command, which expects groups instead of single syscalls. Back in the Linux world, systemd allows grouped allowing or disallowing of syscalls via SystemCallFilter.

This library brings systemd's SystemCallFilters to Go, allowing both systemd's platform-independent syscall sets as well as specific syscalls. Internally, a given allow list filter is converted to a seccomp-bpf profile, which is applied using the go-seccomp-bpf library. All code is Go, no cgo required.

syscallset-go, the Go Library

The only relevant function is LimitTo(syscallFilter string) error, expecting a filter string which will be applied. This filter will be always an allow list of syscall sets and/or single syscalls. However, it is possible to restrict a previously used syscall set by subtracting syscalls.

The syntax follows systemd's SystemCallFilter, with some small differences. To avoid duplicate documentation, please refer to the library's documentation.

The following example would be a simple Go program, restricted to only using @basic-io syscalls. It cannot open network connections, files or even list directories.

package main

import (
  "fmt"

  syscallset "github.com/oxzi/syscallset-go"
)

func main() {
  if err := syscallset.LimitTo("@basic-io"); err != nil {
    panic(err)
  }

  fmt.Println("hello restricted world")
}

For more information about the available syscall sets, please refer to

To debug which syscalls are missing, exchange LimitTo with LimitAndLog. This function will not terminate for non allowed syscalls, but log them to the audit log. One can read this log with auditd -f.

jail, Proof-of-Concept Jail

The simple jail program within cmd/jail allows starting another program with an applied syscallset filter.

$ go build ./cmd/jail
$ ./jail '@system-service ~@network-io ~@privileged' cowsay 'a somewhat more secure cow'
 ____________________________
< a somewhat more secure cow >
 ----------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

In this example, the cowsay program is allowed all syscalls within systemd's @system-service set except those within @network-io and @privileged. Thus, cowsay will not be able to, e.g., upload your SSH private key or adjust your computer's clock.

Please only take this tool as an example and do not use it for something serious. A better tool for exactly this job is already out there, it's called Firejail.

Updating syscalls.go

To update the syscalls.go file within this repository, one needs systemd running on the machine. Then, just use the generator tool.

$ go run generator/gen.go generator/go.tmpl > syscalls.go
$ go run generator/gen.go generator/go-apidoc.tmpl > syscallset.go

As systemd's userland applications are sufficient, one can use Docker to update the list to a recent version:

user@host $ docker pull archlinux:latest
user@host $ docker run -it --rm -v "$PWD":/app archlinux
root@container # pacman -Syu go
root@container # cd /app
root@container # go run generator/gen.go generator/go.tmpl > syscalls.go
root@container # go run generator/gen.go generator/go-apidoc.tmpl > syscallset.go
root@container # ^D

Security Implications

The whole point of this library is to increase security by reducing privileges. However, this code was not audited and might blow up in your face. So please do with caution and feel free to report bugs or even structural errors.

Documentation

Overview

Package syscallset is an easy to use Go library allowing any Go program to restrict its own capabilities on Linux through seccomp-bpf and predefined syscall sets from systemd.

To self-limit a Go application, use this package's LimitTo or LimitAndLog functions.

The following syscall groups from systemd are available:

  • aio: Asynchronous IO
  • basic-io: Basic IO
  • chown: Change ownership of files and directories
  • clock: Change the system time
  • cpu-emulation: System calls for CPU emulation functionality
  • debug: Debugging, performance monitoring and tracing functionality
  • default: System calls that are always permitted
  • file-system: File system operations
  • io-event: Event loop system calls
  • ipc: SysV IPC, POSIX Message Queues or other IPC
  • keyring: Kernel keyring access
  • known: All known syscalls declared in the kernel
  • memlock: Memory locking control
  • module: Loading and unloading of kernel modules
  • mount: Mounting and unmounting of file systems
  • network-io: Network or Unix socket IO, should not be needed if not network facing
  • obsolete: Unusual, obsolete or unimplemented system calls
  • pkey: System calls used for memory protection keys
  • privileged: All system calls which need super-user capabilities
  • process: Process control, execution, namespacing operations
  • raw-io: Raw I/O port access
  • reboot: Reboot and reboot preparation/kexec
  • resources: Alter resource settings
  • sandbox: Sandbox functionality
  • setuid: Operations for changing user/group credentials
  • signal: Process signal handling
  • swap: Enable/disable swap devices
  • sync: Synchronize files and memory to storage
  • system-service: General system service operations
  • timer: Schedule operations by time

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsSupported

func IsSupported() bool

IsSupported returns true if filtering syscalls through seccomp-bpf is possible on this platform.

func LimitAndLog

func LimitAndLog(syscallFilter string) error

LimitAndLog acts like LimitTo; however, non allowed syscalls are being logged instead of resulting in aborting the process. This might be useful for testing the application.

func LimitTo

func LimitTo(syscallFilter string) error

LimitTo a subset of the available Linux syscalls using a systemd system call filter string.

A filter string might contain both syscall sets, prefixed by an at sign (@), as well as single syscalls by their name. The list of syscall sets is either available in this package's main documentation or can be fetched from systemd's exec documentation:

https://www.freedesktop.org/software/systemd/man/systemd.exec.html#System%20Call%20Filtering

The filter acts as an allow list. Thus, every other syscall results in the termination of the process and its children. One can remove single syscalls or smaller sets again by prefixing them with a tilde (~). As the set of allowed syscalls is created by parsing the words from left to right, one should start with building the allow list and reducing it afterwards.

A small subset of syscalls (@default) is always allowed. Thus, when calling with an empty string, a very strict filter is applied, not even allowing using stdin or stdout.

A simple example with systemd's wide @system-service might be:

@system-service

Allowing some IO and file system access might be achieved through:

@basic-io @file-system @io-event

To restrict a wider set might be used like the following:

@system-service ~@process ~@setuid

Types

This section is empty.

Jump to

Keyboard shortcuts

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