Skip to content

Commit 60b50f9

Browse files
committed
feat: Enable sandboxing on Linux
Whitelist syscalls on Linux amd64 with seccomp. Other Linux architectures have to be checked.
1 parent fdce772 commit 60b50f9

File tree

8 files changed

+70
-12
lines changed

8 files changed

+70
-12
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
matrix:
4949
include:
5050
- bin_name: opinions-openbsd_amd64-hardened
51-
- bin_name: opinions-linux_amd64
51+
- bin_name: opinions-linux_amd64-hardened
5252
- bin_name: opinions-linux_arm
5353
- bin_name: opinions-linux_arm64
5454
- bin_name: opinions-freebsd_amd64

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ build: check test
3434
VERSION="$${CURRENT_VER_TAG:-$$PSEUDOVERSION}"; \
3535
# hardened \
3636
GOOS=openbsd GOARCH=amd64 go build -C cmd/ -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-openbsd_amd64-hardened'; \
37+
GOOS=linux GOARCH=amd64 go build -C cmd/ -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_amd64-hardened'; \
3738
# without sandbox \
38-
GOOS=linux GOARCH=amd64 go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_amd64'; \
3939
GOOS=linux GOARCH=arm go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_arm'; \
4040
GOOS=linux GOARCH=arm64 go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-linux_arm64'; \
4141
GOOS=freebsd GOARCH=amd64 go build -C cmd/ -tags unsafe -ldflags="-s -w -X main.AppVersion=$$VERSION" -o '../dist/opinions-freebsd_amd64'; \

README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ It directly calls search engines on underlying websites.
1212
Application is developed with security-first approach:
1313

1414
- functionality is limited by design
15-
- access to the OS is restricted by application-level sandboxing (currently OpenBSD only).
15+
- 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)).
1616

1717
## Usage
1818

@@ -54,14 +54,11 @@ may be different than expected.
5454

5555
## TODO
5656

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

6663
## License
6764

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.20
44

55
require (
66
github.com/andybalholm/cascadia v1.3.2
7+
github.com/seccomp/libseccomp-golang v0.10.0
78
golang.org/x/net v0.17.0
89
golang.org/x/sys v0.13.0
910
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
22
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
3+
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
4+
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
35
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
46
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
57
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=

security/sandbox.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Package security contains OS specific mitigation mechanisms.
22

3-
//go:build !openbsd && !unsafe
3+
//go:build !(linux && amd64) && !openbsd && !unsafe
44

55
package security
66

security/sandbox_linux_amd64.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//go:build linux && amd64 && !openbsd && !unsafe
2+
3+
package security
4+
5+
import (
6+
seccomp "github.com/seccomp/libseccomp-golang"
7+
)
8+
9+
// IsHardened reports whether security sandbox is enabled.
10+
const IsHardened = true
11+
12+
// Sandbox restrict application access to necessary system calls needed by
13+
// network connections and standard i/o.
14+
func Sandbox() error {
15+
// How to create minimal whitelist:
16+
// 1. Create empty list of allowed syscalls
17+
// 2. Set `seccomp.ActLog` as default filter action
18+
// 3. Compile and run program
19+
// 4. Use `dmesg` to find logged syscalls (started with _audit_)
20+
// 5. Translate syscalls numbers to names and add them to allowed list
21+
// 6. Go to point 3 and repeat until no new audit logs
22+
// 7. Reset default filter action to `seccomp.ActKillProcess`
23+
allowedSyscalls := []string{
24+
// similar to stdio pledge
25+
"clone3", "close", "epoll_create1", "epoll_ctl", "epoll_pwait",
26+
"exit_group", "fcntl", "fstat", "futex", "getpid", "getrandom",
27+
"getsockopt", "gettid", "mmap", "mprotect", "munmap", "nanosleep",
28+
"pipe2", "read", "rseq", "rt_sigprocmask", "rt_sigreturn",
29+
"sched_getaffinity", "sched_yield", "set_robust_list", "setsockopt",
30+
"sigaltstack", "tgkill", "uname", "write",
31+
32+
// similar to inet pledge
33+
"connect", "getpeername", "getsockname", "socket",
34+
35+
// similar to rpath pledge
36+
"getdents64", "newfstatat", "openat", "readlinkat",
37+
}
38+
39+
// By default goroutines don't play well with seccomp. Program will hang
40+
// when underlying thread is terminated silently. We need to kill process -
41+
// see: https://github.com/golang/go/issues/3405#issuecomment-750816828
42+
whitelist, err := seccomp.NewFilter(seccomp.ActKillProcess)
43+
if err != nil {
44+
return err
45+
}
46+
47+
for _, callName := range allowedSyscalls {
48+
callId, err := seccomp.GetSyscallFromName(callName)
49+
if err != nil {
50+
return err
51+
}
52+
53+
whitelist.AddRule(callId, seccomp.ActAllow)
54+
}
55+
whitelist.Load()
56+
57+
return nil
58+
}

security/sandbox_openbsd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build openbsd && !unsafe
1+
//go:build openbsd && !(linux && amd64) && !unsafe
22

33
package security
44

0 commit comments

Comments
 (0)