mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
Add support to load a seccomp filter
This commit is contained in:
parent
e3111eef82
commit
04cfb36722
@ -68,6 +68,10 @@ The `executorserver` need root privilege to create `cgroup`. Either creates sub-
|
||||
- for example, by default container 0 will run with 10001 uid & gid and container 1 will run with 10002 uid & gid...
|
||||
- `-enable-cpu-rate` enabled `cpu` cgroup to control cpu rate using cfs_quota & cfs_period control
|
||||
- `-cpu-cfs-period` specifies cfs_period if cpu rate is enabled (default 100ms) (valid value: \[1ms, 1s\])
|
||||
- `-seccomp-conf` specifies `seecomp` filter setting to load when running program
|
||||
- for example, by `strace -c prog` to get all `syscall` needed and restrict to that sub set
|
||||
- however, the `syscall` count in one platform(e.g. x86_64) is not suitable for all platform, so this option is not recommended
|
||||
- the program killed by seccomp filter will have status `Dangerous Syscall`
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
|
||||
@ -15,7 +15,8 @@ type Config struct {
|
||||
PreFork int `flagUsage:"control # of the prefork workers"`
|
||||
TmpFsParam string `flagUsage:"tmpfs mount data (only for default mount with no mount.yaml)" default:"size=16m,nr_inodes=4k"`
|
||||
NetShare bool `flagUsage:"share net namespace with host"`
|
||||
MountConf string `flagUsage:"specifics mount configuration file" default:"mount.yaml"`
|
||||
MountConf string `flagUsage:"specifies mount configuration file" default:"mount.yaml"`
|
||||
SeccompConf string `flagUsage:"specifies seccomp filter" default:"seccomp.yaml"`
|
||||
Parallelism int `flagUsage:"control the # of concurrency execution" default:"4"`
|
||||
CgroupPrefix string `flagUsage:"control cgroup prefix" default:"executor_server"`
|
||||
ContainerCredStart int `flagUsage:"control the start uid&gid for container" default:"10000"`
|
||||
|
||||
@ -79,6 +79,7 @@ func main() {
|
||||
ContainerCredStart: conf.ContainerCredStart,
|
||||
EnableCPURate: conf.EnableCPURate,
|
||||
CPUCfsPeriod: conf.CPUCfsPeriod,
|
||||
SeccompConf: conf.SeccompConf,
|
||||
Logger: logger.Sugar(),
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
1
env/config.go
vendored
1
env/config.go
vendored
@ -16,6 +16,7 @@ type Config struct {
|
||||
TmpFsParam string
|
||||
NetShare bool
|
||||
MountConf string
|
||||
SeccompConf string
|
||||
CgroupPrefix string
|
||||
Cpuset string
|
||||
ContainerCredStart int
|
||||
|
||||
18
env/env_linux.go
vendored
18
env/env_linux.go
vendored
@ -1,6 +1,7 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
@ -45,6 +46,14 @@ func NewBuilder(c Config) (pool.EnvBuilder, error) {
|
||||
m := mb.FilterNotExist().Mounts
|
||||
c.Info("Created container mount at:", mb)
|
||||
|
||||
seccomp, err := readSeccompConf(c.SeccompConf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load seccomp config: %v", err)
|
||||
}
|
||||
if seccomp != nil {
|
||||
c.Info("Load seccomp filter: ", c.SeccompConf)
|
||||
}
|
||||
|
||||
unshareFlags := uintptr(forkexec.UnshareFlags)
|
||||
if c.NetShare {
|
||||
unshareFlags ^= syscall.CLONE_NEWNET
|
||||
@ -111,7 +120,14 @@ func NewBuilder(c Config) (pool.EnvBuilder, error) {
|
||||
if cgb != nil {
|
||||
cgroupPool = pool.NewFakeCgroupPool(cgb, c.CPUCfsPeriod)
|
||||
}
|
||||
return pool.NewEnvBuilder(b, cgroupPool, workDir, c.Cpuset, c.EnableCPURate), nil
|
||||
return pool.NewEnvBuilder(pool.Config{
|
||||
Builder: b,
|
||||
CgroupPool: cgroupPool,
|
||||
WorkDir: workDir,
|
||||
Cpuset: c.Cpuset,
|
||||
CPURate: c.EnableCPURate,
|
||||
Seccomp: seccomp,
|
||||
}), nil
|
||||
}
|
||||
|
||||
type credGen struct {
|
||||
|
||||
47
env/seccomp_linux.go
vendored
Normal file
47
env/seccomp_linux.go
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/elastic/go-seccomp-bpf"
|
||||
"github.com/elastic/go-ucfg/yaml"
|
||||
"golang.org/x/net/bpf"
|
||||
)
|
||||
|
||||
func readSeccompConf(name string) ([]syscall.SockFilter, error) {
|
||||
conf, err := yaml.NewConfigWithFile(name)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var policy seccomp.Policy
|
||||
if err := conf.Unpack(&policy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inst, err := policy.Assemble()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawInst, err := bpf.Assemble(inst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toSockFilter(rawInst), nil
|
||||
}
|
||||
|
||||
func toSockFilter(raw []bpf.RawInstruction) []syscall.SockFilter {
|
||||
filter := make([]syscall.SockFilter, 0, len(raw))
|
||||
for _, instruction := range raw {
|
||||
filter = append(filter, syscall.SockFilter{
|
||||
Code: instruction.Op,
|
||||
Jt: instruction.Jt,
|
||||
Jf: instruction.Jf,
|
||||
K: instruction.K,
|
||||
})
|
||||
}
|
||||
return filter
|
||||
}
|
||||
3
go.mod
3
go.mod
@ -6,6 +6,8 @@ require (
|
||||
cloud.google.com/go v0.74.0 // indirect
|
||||
github.com/creack/pty v1.1.11
|
||||
github.com/criyle/go-sandbox v0.5.8
|
||||
github.com/elastic/go-seccomp-bpf v1.1.0
|
||||
github.com/elastic/go-ucfg v0.7.0
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/gin-contrib/pprof v1.3.0
|
||||
@ -26,6 +28,7 @@ require (
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.16.0
|
||||
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@ -96,7 +96,9 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elastic/go-seccomp-bpf v1.1.0 h1:jUzzDc6LyCtdolZdvL/26dad6rZ9vsc7xZ2eadKECAU=
|
||||
github.com/elastic/go-seccomp-bpf v1.1.0/go.mod h1:l+89Vy5BzjVcaX8USZRMOwmwwDScE+vxCFzzvQwN7T8=
|
||||
github.com/elastic/go-ucfg v0.7.0 h1:1+C/sZdJKww8hKl7XtLPTjs4cFslhQF2fazKTF+ZE+4=
|
||||
github.com/elastic/go-ucfg v0.7.0/go.mod h1:iaiY0NBIYeasNgycLyTvhJftQlQEUO2hpF+FX0JKxzo=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
||||
@ -7,22 +7,34 @@ import (
|
||||
"github.com/criyle/go-sandbox/container"
|
||||
)
|
||||
|
||||
// Config specifies configuration to build environment builder
|
||||
type Config struct {
|
||||
Builder EnvironmentBuilder
|
||||
CgroupPool CgroupPool
|
||||
WorkDir string
|
||||
Seccomp []syscall.SockFilter
|
||||
Cpuset string
|
||||
CPURate bool
|
||||
}
|
||||
|
||||
type environmentBuilder struct {
|
||||
builder EnvironmentBuilder
|
||||
cgPool CgroupPool
|
||||
workDir string
|
||||
seccomp []syscall.SockFilter
|
||||
cpuset string
|
||||
cpuRate bool
|
||||
}
|
||||
|
||||
// NewEnvBuilder creates builder for linux container pools
|
||||
func NewEnvBuilder(builder EnvironmentBuilder, cgPool CgroupPool, workDir, cpuset string, cpuRate bool) EnvBuilder {
|
||||
func NewEnvBuilder(c Config) EnvBuilder {
|
||||
return &environmentBuilder{
|
||||
builder: builder,
|
||||
cgPool: cgPool,
|
||||
workDir: workDir,
|
||||
cpuset: cpuset,
|
||||
cpuRate: cpuRate,
|
||||
builder: c.Builder,
|
||||
cgPool: c.CgroupPool,
|
||||
workDir: c.WorkDir,
|
||||
seccomp: c.Seccomp,
|
||||
cpuset: c.Cpuset,
|
||||
cpuRate: c.CPURate,
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,5 +58,6 @@ func (b *environmentBuilder) Build() (Environment, error) {
|
||||
wd: wd[0],
|
||||
cpuset: b.cpuset,
|
||||
cpuRate: b.cpuRate,
|
||||
seccomp: b.seccomp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ type environ struct {
|
||||
cgPool CgroupPool
|
||||
wd *os.File // container work dir
|
||||
cpuset string
|
||||
seccomp []syscall.SockFilter
|
||||
cpuRate bool
|
||||
}
|
||||
|
||||
@ -70,6 +71,7 @@ func (c *environ) Execve(ctx context.Context, param envexec.ExecveParam) (envexe
|
||||
CTTY: param.TTY,
|
||||
ExecFile: param.ExecFile,
|
||||
RLimits: rLimits.PrepareRLimit(),
|
||||
Seccomp: c.seccomp,
|
||||
SyncFunc: syncFunc,
|
||||
}
|
||||
rt := c.Environment.Execve(ctx, p)
|
||||
|
||||
154
seccomp_example.yaml
Normal file
154
seccomp_example.yaml
Normal file
@ -0,0 +1,154 @@
|
||||
# This is an example seccomp policy for x86_64 that whitelist regular syscalls and prevents network syscalls.
|
||||
# The example is not ready for production use now, should be tuned for specific usages
|
||||
|
||||
# The default action is applied if none of the syscalls match.
|
||||
#
|
||||
# Possible actions:
|
||||
# - kill_process (since Linux 4.14)
|
||||
# - kill_thread
|
||||
# - trap
|
||||
# - errno (returns EPERM)
|
||||
# - trace
|
||||
# - log (since Linux 4.14)
|
||||
# - allow
|
||||
default_action: kill_process
|
||||
|
||||
syscalls:
|
||||
- action: allow
|
||||
names:
|
||||
# file actions
|
||||
- read
|
||||
- write
|
||||
- readv
|
||||
- writev
|
||||
- close
|
||||
- fstat
|
||||
- lseek
|
||||
- dup
|
||||
- dup2
|
||||
- dup3
|
||||
- ioctl
|
||||
- fcntl
|
||||
- fadvise64
|
||||
- pipe
|
||||
- pread64
|
||||
- pwrite64
|
||||
|
||||
# memory action
|
||||
- mmap
|
||||
- mprotect
|
||||
- munmap
|
||||
- brk
|
||||
- mremap
|
||||
- msync
|
||||
- mincore
|
||||
- madvise
|
||||
|
||||
# signal
|
||||
- rt_sigaction
|
||||
- rt_sigprocmask
|
||||
- rt_sigreturn
|
||||
- rt_sigpending
|
||||
- sigaltstack
|
||||
|
||||
# work dir
|
||||
- getcwd
|
||||
|
||||
# exit
|
||||
- exit
|
||||
- exit_group
|
||||
|
||||
# others
|
||||
- arch_prctl
|
||||
- restart_syscall
|
||||
|
||||
# time
|
||||
- gettimeofday
|
||||
- times
|
||||
- time
|
||||
- clock_gettime
|
||||
- clock_getres
|
||||
|
||||
# rlimit
|
||||
- getrlimit
|
||||
- getrusage
|
||||
- setrlimit
|
||||
|
||||
# execve
|
||||
- execve
|
||||
- execveat
|
||||
|
||||
# open
|
||||
- open
|
||||
- openat
|
||||
|
||||
# delete
|
||||
- unlink
|
||||
- unlinkat
|
||||
|
||||
# link
|
||||
- readlink
|
||||
- readlinkat
|
||||
|
||||
# permission check
|
||||
- lstat
|
||||
- stat
|
||||
- access
|
||||
- faccessat
|
||||
|
||||
# process
|
||||
- clone
|
||||
- fork
|
||||
- vfork
|
||||
- nanosleep
|
||||
- wait4
|
||||
|
||||
- getpid
|
||||
- gettid
|
||||
|
||||
# lock
|
||||
- futex
|
||||
|
||||
# other
|
||||
- getdents
|
||||
- getdents64
|
||||
- sysinfo
|
||||
- set_tid_address
|
||||
- set_robust_list
|
||||
- getrandom
|
||||
|
||||
- umask
|
||||
- rename
|
||||
- chmod
|
||||
- mkdir
|
||||
- chdir
|
||||
- fchdir
|
||||
- ftruncate
|
||||
- sched_getaffinity
|
||||
- sched_yield
|
||||
- uname
|
||||
- prlimit64
|
||||
- fchmodat
|
||||
- poll
|
||||
|
||||
# user
|
||||
- getuid
|
||||
- geteuid
|
||||
- getgid
|
||||
- getegid
|
||||
|
||||
- action: errno
|
||||
names:
|
||||
- connect
|
||||
- accept
|
||||
- sendto
|
||||
- recvfrom
|
||||
- sendmsg
|
||||
- recvmsg
|
||||
- bind
|
||||
- listen
|
||||
- setsockopt
|
||||
- socketpair
|
||||
- getsockopt
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user