gomodjail imposes syscall restrictions on a specific set of Go modules, so as to mitigate their potential vulnerabilities and supply chain attack vectors.
In other words, gomodjail is a "container" (as in Docker containers) for Go modules.
gomodjail can be applied just in the following two steps:
Step 1: add gomodjail:confined
comment to go.mod
:
require (
example.com/module v1.0.0 // gomodjail:confined
)
Step2: run the program with gomodjail run --go-mod=go.mod
:
gomodjail run --go-mod=FILE -- PROG [ARGS]...
Runtime dependencies:
- Linux 4.8 or later
- x86_64 (aka "amd64") or aarch64 ("arm64")
Build dependencies:
make
sudo make install
Makefile variables:
PREFIX
: installation prefix (default:/usr/local
)
An example program is located in ./examples/victim
:
cd ./examples/victim
go build
./victim
Confirm the "malicious" vi screen:
*** ARBITRARY SHELL CODE EXECUTION ***
This 'vi' command was executed by the 'github.com/AkihiroSuda/gomodjail/examples/poisoned' module.
This example is harmless, of course, but suppose that this was a malicious code.
Type ':q!' to leave this screen.
Run the program again with gomodjail run --go-mod=go.mod
, and confirm that the execution of the "malicious" vi
command is blocked.
gomodjail run --go-mod=go.mod -- ./victim
level=WARN msg=***Blocked*** syscall=pidfd_open module=github.com/AkihiroSuda/gomodjail/examples/poisoned
examples/profiles
has several example profiles:
docker.mod
: fordocker
(notdockerd
)- ...
- Not applicable to a Go binary built by non-trustworthy thirdparty, as the symbol information might be faked.
- Not applicable to a Go binary built with
-ldflags="-s"
(disable symbol table) - Not applicable to a Go module that use:
- No isolation of file descriptors across modules. A confined module can still read/write an existing file descriptor, although it cannot open a new file descriptor.
- The target binary file must not be replaced during execution.
- May not work with a future version of Go.
- The
gomodjail:confined
policy is not well defined and still subject to change. - This is not a panacea; there can be other loopholes too.
See gomodjail run --help
$ gomodjail run --help
Run a Go program with confinement
Usage:
gomodjail run COMMAND...
Flags:
--go-mod gomodjail:confined go.mod file with comment lines like gomodjail:confined
-h, --help help for run
--no-policy Allow running without any policy (useful only for debugging)
--policy stringToString e.g., example.com/module=confined (default [])
Global Flags:
--debug debug mode [$DEBUG]
SECCOMP_RET_TRAP
is used for conditionally allowing trusted Go modules to execute the syscall.SECCOMP_RET_USER_NOTIF
is not used because it cannot access all the CPU registers, due to the lack ofstruct pt_regs
instruct seccomp_data
.- Stack unwinding is used for analyzing the call stack to determine the Go module.
- Automatically detect non-applicable modules (explained in Caveats).
- Support macOS, probably using
DYLD_INSERT_LIBRARIES
- Support embedding gomodjail in a target program
- Apply landlock in addition to seccomp. Depends on
SECCOMP_IOCTL_NOTIF_ADDFD
. - Modify the source code of the Go runtime, so as to remove necessity of using
seccomp
.