From b53992060e510c5a3cc38b0502b92dc4fc9ab811 Mon Sep 17 00:00:00 2001 From: Ciprian Dorin Craciun Date: Sun, 11 Sep 2022 20:19:56 +0300 Subject: [PATCH] [server] Add initial working Linux `seccomp` filter for the server. --- sources/cmd/server/listen.go | 6 ++ sources/cmd/server/seccomp.go | 103 ++++++++++++++++++++++++++++- sources/cmd/server/server.go | 30 ++++----- sources/go.mod | 1 + sources/go.sum | 2 + sources/lib/seccomp/supported.go | 95 ++++++++++++++++++++++++++ sources/lib/seccomp/unsupported.go | 16 +++++ 7 files changed, 235 insertions(+), 18 deletions(-) create mode 100644 sources/lib/seccomp/supported.go create mode 100644 sources/lib/seccomp/unsupported.go diff --git a/sources/cmd/server/listen.go b/sources/cmd/server/listen.go index 83221c4..ef0f78c 100644 --- a/sources/cmd/server/listen.go +++ b/sources/cmd/server/listen.go @@ -18,6 +18,12 @@ func listenTcp (_endpoint string) (net.Listener, error) { _useTcpListen := false + if ! _useTcpListen { + if seccompApplied { + _useTcpListen = true + } + } + if ! _useTcpListen { if (runtime.GOOS == "android") { _useTcpListen = true diff --git a/sources/cmd/server/seccomp.go b/sources/cmd/server/seccomp.go index 6d8da9f..84d9a26 100644 --- a/sources/cmd/server/seccomp.go +++ b/sources/cmd/server/seccomp.go @@ -11,25 +11,121 @@ import . "github.com/volution/kawipiko/lib/common" +var _seccompBaseSyscalls = []string { + + "brk", + "mmap", + "munmap", + "madvise", + "mprotect", + + "clone3", + "getpid", + "gettid", + "tgkill", + "exit_group", + "sched_yield", + "nanosleep", + + "sigaltstack", + "rt_sigaction", + "rt_sigprocmask", + "rt_sigreturn", + "restart_syscall", + + "futex", + "set_robust_list", + "rseq", + + } + + +// NOTE: While serving. +var _seccompPhase3Syscalls = append ([]string { + + "accept4", + "close", + "getsockname", + "getpeername", + "getsockopt", + "setsockopt", + + "read", + "write", + + "pread64", + "pwrite64", + + "recvmmsg", + "sendmsg", + + "epoll_ctl", + "epoll_pwait", + + "getrandom", + + "getrusage", + + }, _seccompBaseSyscalls ...) + + +// NOTE: While listening. +var _seccompPhase2Syscalls = append ([]string { + + "socket", + "bind", + "listen", + + "pipe2", + "fcntl", + + "epoll_create1", + + "seccomp", + "prctl", + + }, _seccompPhase3Syscalls ...) + + +// NOTE: While loading. +var _seccompPhase1Syscalls = append ([]string { + + "openat", + "fstat", + "newfstatat", + + "mmap", + + "seccomp", + "prctl", + + }, _seccompPhase2Syscalls ...) + + + + func seccompApplyPhase1 () () { + seccompApplied = true log.Printf ("[ii] [d53cf86e] [seccomp.] applying Linux seccomp filter (phase 1)...\n") - if _error := seccomp.ApplyServer (); _error != nil { + if _error := seccomp.AllowOnlySyscalls (_seccompPhase1Syscalls); _error != nil { AbortError (_error, "[58d1492b] failed to apply Linux seccomp filter (phase 1)!") } } func seccompApplyPhase2 () () { + seccompApplied = true log.Printf ("[ii] [a338ddaf] [seccomp.] applying Linux seccomp filter (phase 2)...\n") - if _error := seccomp.ApplyServer (); _error != nil { + if _error := seccomp.AllowOnlySyscalls (_seccompPhase2Syscalls); _error != nil { AbortError (_error, "[68283e68] failed to apply Linux seccomp filter (phase 2)!") } } func seccompApplyPhase3 () () { + seccompApplied = true log.Printf ("[ii] [a319ff21] [seccomp.] applying Linux seccomp filter (phase 3)...\n") - if _error := seccomp.ApplyServer (); _error != nil { + if _error := seccomp.AllowOnlySyscalls (_seccompPhase3Syscalls); _error != nil { AbortError (_error, "[7c5a0f44] failed to apply Linux seccomp filter (phase 3)!") } } @@ -37,5 +133,6 @@ func seccompApplyPhase3 () () { +var seccompApplied = false var seccompSupported = seccomp.Supported diff --git a/sources/cmd/server/server.go b/sources/cmd/server/server.go index dcf6bdd..62a6005 100644 --- a/sources/cmd/server/server.go +++ b/sources/cmd/server/server.go @@ -1035,7 +1035,7 @@ func main_0 () (error) { if _seccompEnabled && (_processes > 1) { AbortError (nil, "[69c06e0c] Linux seccomp is not supported with multiple processes!") } - if _seccompEnabled && ((_profilingCpu != "") || (_profilingMem != "")) { + if _seccompEnabled && ((_profileCpu != "") || (_profileMem != "")) { AbortError (nil, "[1fb06ca1] Linux seccomp is not supported with profiling!") } @@ -1056,19 +1056,6 @@ func main_0 () (error) { - if _seccompEnabled { - seccompApplyPhase1 () - } - - - - - // -------------------------------------------------------------------------------- - // -------------------------------------------------------------------------------- - - - - runtime.GOMAXPROCS (int (_threads)) debug.SetGCPercent (50) @@ -1097,6 +1084,19 @@ func main_0 () (error) { + if _seccompEnabled { + seccompApplyPhase1 () + } + + + + + // -------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------- + + + + if _processes > 1 { log.Printf ("[ii] [06f8c944] [master..] sub-processes starting (`%d` processes with `%d` threads each)...\n", _processes, _threads) @@ -2185,7 +2185,7 @@ func main_0 () (error) { if !_quiet { log.Printf ("[ii] [4cf834b0] [quic-h3.] starting QUIC server...\n") } - if _error := _server.httpQuicServer.Serve (_httpQuicListener); (_error != nil) && (_error.Error () != "server closed") { + if _error := _server.httpQuicServer.Serve (_httpQuicListener); (_error != nil) && (_error.Error () != "quic: Server closed") { AbortError (_error, "[73e700c5] [quic-h3.] failed executing server!") } if !_quiet { diff --git a/sources/go.mod b/sources/go.mod index cb1ea99..81ec212 100644 --- a/sources/go.mod +++ b/sources/go.mod @@ -32,6 +32,7 @@ require ( github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.19.0 // indirect + github.com/seccomp/libseccomp-golang v0.10.0 // indirect github.com/stretchr/testify v1.8.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/zeebo/assert v1.3.1 // indirect diff --git a/sources/go.sum b/sources/go.sum index f3a8587..50f5487 100644 --- a/sources/go.sum +++ b/sources/go.sum @@ -144,6 +144,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= diff --git a/sources/lib/seccomp/supported.go b/sources/lib/seccomp/supported.go new file mode 100644 index 0000000..bc10d37 --- /dev/null +++ b/sources/lib/seccomp/supported.go @@ -0,0 +1,95 @@ + + +//go:build linux && amd64 && seccomp + + + + +package seccomp + + +import "fmt" +import "syscall" + + +import "github.com/seccomp/libseccomp-golang" + + + + +func init () { + + Supported = true + + if false { + + _filter, _error := seccomp.NewFilter (seccomp.ActLog) + if _error != nil { + panic (_error) + } + + if _error = _filter.Load (); _error != nil { + panic (_error) + } + } +} + + + + +func AllowOnlySyscalls (_syscalls []string) (error) { + + _architectures := []seccomp.ScmpArch { + seccomp.ArchNative, + seccomp.ArchX86, + seccomp.ArchX32, + seccomp.ArchAMD64, + } + + _fallbackAction := seccomp.ActKill + switch 0 { + case 1 : + _fallbackAction = seccomp.ActErrno.SetReturnCode (int16 (syscall.EPERM)) + case 2 : + _fallbackAction = seccomp.ActLog + } + + _filter, _error := seccomp.NewFilter (_fallbackAction) + if _error != nil { + return _error + } + + for _, _architecture := range _architectures { + if _error := _filter.AddArch (_architecture); _error != nil { + return _error + } + } + + for _, _syscall := range _syscalls { + + var _sc_syscall seccomp.ScmpSyscall + switch { + + case _syscall[0] == '!' : + continue + + default : + if _sc_syscall_0, _error := seccomp.GetSyscallFromNameByArch (_syscall, seccomp.ArchNative); _error == nil { + _sc_syscall = _sc_syscall_0 + } else { + return fmt.Errorf ("[5cf9cd60] failed resolving syscall `%s`: %w", _syscall, _error) + } + } + + if _error := _filter.AddRule (_sc_syscall, seccomp.ActAllow); _error != nil { + return _error + } + } + + if _error = _filter.Load (); _error != nil { + return _error + } + + return nil +} + diff --git a/sources/lib/seccomp/unsupported.go b/sources/lib/seccomp/unsupported.go new file mode 100644 index 0000000..d884c6b --- /dev/null +++ b/sources/lib/seccomp/unsupported.go @@ -0,0 +1,16 @@ + + +//go:build !(linux && amd64 && seccomp) + + + + +package seccomp + + + + +func AllowOnlySyscalls (_syscalls []string) (error) { + return nil +} +