Skip to content

Commit

Permalink
feat: Enable sandboxing on Linux
Browse files Browse the repository at this point in the history
Whitelist syscalls on Linux amd64 with seccomp. Other Linux
architectures have to be checked.
  • Loading branch information
macie committed Oct 28, 2023
1 parent fdce772 commit 60b50f9
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
matrix:
include:
- bin_name: opinions-openbsd_amd64-hardened
- bin_name: opinions-linux_amd64
- bin_name: opinions-linux_amd64-hardened
- bin_name: opinions-linux_arm
- bin_name: opinions-linux_arm64
- bin_name: opinions-freebsd_amd64
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ build: check test
VERSION="$${CURRENT_VER_TAG:-$$PSEUDOVERSION}"; \
# hardened \
GOOS=openbsd GOARCH=amd64 go build -C cmd/ -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-openbsd_amd64-hardened'; \
GOOS=linux GOARCH=amd64 go build -C cmd/ -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_amd64-hardened'; \
# without sandbox \
GOOS=linux GOARCH=amd64 go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_amd64'; \
GOOS=linux GOARCH=arm go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_arm'; \
GOOS=linux GOARCH=arm64 go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_arm64'; \
GOOS=freebsd GOARCH=amd64 go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-freebsd_amd64'; \
Expand Down
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ It directly calls search engines on underlying websites.
Application is developed with security-first approach:

- functionality is limited by design
- access to the OS is restricted by application-level sandboxing (currently OpenBSD only).
- access to the OS is restricted by application-level sandboxing (with [pledge](https://man.openbsd.org/pledge.2) and [seccomp](https://en.wikipedia.org/wiki/Seccomp)).

## Usage

Expand Down Expand Up @@ -54,14 +54,11 @@ may be different than expected.

## TODO

Add [sandboxing](https://learnbchs.org/pledge.html) for other OSes:

- Linux: [seccomp](https://en.wikipedia.org/wiki/Seccomp) (see:
<https://github.com/stephane-martin/skewer/blob/master/sys/scomp/seccomp.go> and
<https://blog.heroku.com/applying-seccomp-filters-on-go-binaries>)
- FreeBSD: [Capsicum](https://en.wikipedia.org/wiki/Capsicum_(Unix)) (see:
- add [sandboxing](https://learnbchs.org/pledge.html) for FreeBSD (with
[Capsicum](https://en.wikipedia.org/wiki/Capsicum_(Unix)) - see:
<https://reviews.freebsd.org/rS308432> and
<https://cgit.freebsd.org/src/tree/lib/libcapsicum/capsicum_helpers.h?id=d66f9c86fa3fd8d8f0a56ea96b03ca11f2fac1fb#n104>)
<https://cgit.freebsd.org/src/tree/lib/libcapsicum/capsicum_helpers.h?id=d66f9c86fa3fd8d8f0a56ea96b03ca11f2fac1fb#n104>))
- verify hardened version of linux arm and arm64.

## License

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.20

require (
github.com/andybalholm/cascadia v1.3.2
github.com/seccomp/libseccomp-golang v0.10.0
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
Expand Down
2 changes: 1 addition & 1 deletion security/sandbox.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Package security contains OS specific mitigation mechanisms.

//go:build !openbsd && !unsafe
//go:build !(linux && amd64) && !openbsd && !unsafe

package security

Expand Down
58 changes: 58 additions & 0 deletions security/sandbox_linux_amd64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//go:build linux && amd64 && !openbsd && !unsafe

package security

import (
seccomp "github.com/seccomp/libseccomp-golang"
)

// IsHardened reports whether security sandbox is enabled.
const IsHardened = true

// Sandbox restrict application access to necessary system calls needed by
// network connections and standard i/o.
func Sandbox() error {
// How to create minimal whitelist:
// 1. Create empty list of allowed syscalls
// 2. Set `seccomp.ActLog` as default filter action
// 3. Compile and run program
// 4. Use `dmesg` to find logged syscalls (started with _audit_)
// 5. Translate syscalls numbers to names and add them to allowed list
// 6. Go to point 3 and repeat until no new audit logs
// 7. Reset default filter action to `seccomp.ActKillProcess`
allowedSyscalls := []string{
// similar to stdio pledge
"clone3", "close", "epoll_create1", "epoll_ctl", "epoll_pwait",
"exit_group", "fcntl", "fstat", "futex", "getpid", "getrandom",
"getsockopt", "gettid", "mmap", "mprotect", "munmap", "nanosleep",
"pipe2", "read", "rseq", "rt_sigprocmask", "rt_sigreturn",
"sched_getaffinity", "sched_yield", "set_robust_list", "setsockopt",
"sigaltstack", "tgkill", "uname", "write",

// similar to inet pledge
"connect", "getpeername", "getsockname", "socket",

// similar to rpath pledge
"getdents64", "newfstatat", "openat", "readlinkat",
}

// By default goroutines don't play well with seccomp. Program will hang
// when underlying thread is terminated silently. We need to kill process -
// see: https://github.com/golang/go/issues/3405#issuecomment-750816828
whitelist, err := seccomp.NewFilter(seccomp.ActKillProcess)
if err != nil {
return err
}

for _, callName := range allowedSyscalls {
callId, err := seccomp.GetSyscallFromName(callName)
if err != nil {
return err
}

whitelist.AddRule(callId, seccomp.ActAllow)
}
whitelist.Load()

return nil
}
2 changes: 1 addition & 1 deletion security/sandbox_openbsd.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build openbsd && !unsafe
//go:build openbsd && !(linux && amd64) && !unsafe

package security

Expand Down

0 comments on commit 60b50f9

Please sign in to comment.