mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-09-26 23:19:11 +08:00
*: fix typos
This commit is contained in:
parent
231f3cb58f
commit
ed93876f8c
@ -41,8 +41,8 @@ Default file access syscall check:
|
||||
|
||||
### linux namespace + cgroup
|
||||
|
||||
1. Unshare & bind mount rootfs based on hostfs (elimilated ptrace)
|
||||
2. Use Linux Control Groups to limit & acct CPU & memory (elimilate wait4.rusage)
|
||||
1. Unshare & bind mount rootfs based on hostfs (eliminated ptrace)
|
||||
2. Use Linux Control Groups to limit & acct CPU & memory (eliminated wait4.rusage)
|
||||
3. Container tech with execveat memfd, sethostname, setdomainname
|
||||
|
||||
## Design
|
||||
@ -156,7 +156,7 @@ type Environment interface {
|
||||
- seccomp: provides seccomp type definition
|
||||
- libseccomp: provides utility function that wrappers libseccomp
|
||||
- forkexec: fork-exec provides mount, unshare, ptrace, seccomp, capset before exec
|
||||
- memfd: read regular file and creates a seaed memfd for its contents
|
||||
- memfd: read regular file and creates a sealed memfd for its contents
|
||||
- unixsocket: send / recv oob msg from a unix socket
|
||||
- cgroup: creates cgroup directories and collects resource usage / limits
|
||||
- mount: provides utility function that wrappers mount syscall
|
||||
|
@ -1,44 +1,52 @@
|
||||
// Package container provides pre-forked container environment to
|
||||
// run programs in isolated Linux namespaces.
|
||||
//
|
||||
// Overview
|
||||
// # Overview
|
||||
//
|
||||
// It creates container within unshared container and communicate
|
||||
// with host process using unix socket with
|
||||
// oob for fd / pid and commands encoded by gob.
|
||||
//
|
||||
// Protocol
|
||||
// # Protocol
|
||||
//
|
||||
// Host to container communication protocol is single threaded and always initiated by
|
||||
// the host:
|
||||
//
|
||||
// - ping (alive check):
|
||||
// - reply: pong
|
||||
// ## ping (alive check)
|
||||
//
|
||||
// - conf (set configuration):
|
||||
// - reply pong
|
||||
// - send: ping
|
||||
// - reply: pong
|
||||
//
|
||||
// - open (open files in given mode inside container):
|
||||
// - send: []OpenCmd
|
||||
// - reply: "success", file fds / "error"
|
||||
// ## conf (set configuration)
|
||||
//
|
||||
// - delete (unlink file / rmdir dir inside container):
|
||||
// - send: path
|
||||
// - reply: "finished" / "error"
|
||||
// - send: conf
|
||||
// - reply:
|
||||
//
|
||||
// - reset (clean up container for later use (clear workdir / tmp)):
|
||||
// - send:
|
||||
// - reply: "success"
|
||||
// ## open (open files in given mode inside container):
|
||||
//
|
||||
// - execve: (execute file inside container):
|
||||
// - send: argv, env, rLimits, fds
|
||||
// - reply:
|
||||
// - success: "success", pid
|
||||
// - failed: "failed"
|
||||
// - send (success): "init_finished" (as cmd)
|
||||
// - reply: "finished" / send: "kill" (as cmd)
|
||||
// - send: "kill" (as cmd) / reply: "finished"
|
||||
// - reply:
|
||||
// - send: []OpenCmd
|
||||
// - reply: "success", file fds / "error"
|
||||
//
|
||||
// ## delete (unlink file / rmdir dir inside container):
|
||||
//
|
||||
// - send: path
|
||||
// - reply: "finished" / "error"
|
||||
//
|
||||
// ## reset (clean up container for later use (clear workdir / tmp)):
|
||||
//
|
||||
// - send:
|
||||
// - reply: "success"
|
||||
//
|
||||
// ## execve: (execute file inside container):
|
||||
//
|
||||
// - send: argv, env, rLimits, fds
|
||||
// - reply:
|
||||
// - success: "success", pid
|
||||
// - failed: "failed"
|
||||
// - send (success): "init_finished" (as cmd)
|
||||
// - reply: "finished" / send: "kill" (as cmd)
|
||||
// - send: "kill" (as cmd) / reply: "finished"
|
||||
// - reply:
|
||||
//
|
||||
// Any socket related error will cause the container exit with all process inside container
|
||||
package container
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
||||
)
|
||||
|
||||
// 16k buffsize
|
||||
// 16k buffer size
|
||||
const bufferSize = 16 << 10
|
||||
|
||||
type socket struct {
|
||||
@ -17,18 +17,18 @@ type socket struct {
|
||||
buff []byte
|
||||
|
||||
decoder *gob.Decoder
|
||||
recvBuff bufferRotater
|
||||
recvBuff bufferRotator
|
||||
|
||||
encoder *gob.Encoder
|
||||
sendBuff bytes.Buffer
|
||||
}
|
||||
|
||||
// bufferRotater replace the underlying Buffers to avoid allocation
|
||||
type bufferRotater struct {
|
||||
// bufferRotator replace the underlying Buffers to avoid allocation
|
||||
type bufferRotator struct {
|
||||
*bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *bufferRotater) Rotate(buffer *bytes.Buffer) {
|
||||
func (b *bufferRotator) Rotate(buffer *bytes.Buffer) {
|
||||
b.Buffer = buffer
|
||||
}
|
||||
|
||||
|
6
go.mod
6
go.mod
@ -3,9 +3,9 @@ module github.com/criyle/go-sandbox
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/elastic/go-seccomp-bpf v1.3.0
|
||||
golang.org/x/net v0.18.0
|
||||
golang.org/x/sys v0.14.0
|
||||
github.com/elastic/go-seccomp-bpf v1.4.0
|
||||
golang.org/x/net v0.20.0
|
||||
golang.org/x/sys v0.16.0
|
||||
)
|
||||
|
||||
require github.com/stretchr/testify v1.8.4 // indirect
|
||||
|
12
go.sum
12
go.sum
@ -1,14 +1,14 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elastic/go-seccomp-bpf v1.3.0 h1:e6teyX946lvPOnZERSYRrMYmsjxaQcWhoiGTsxLu3Lc=
|
||||
github.com/elastic/go-seccomp-bpf v1.3.0/go.mod h1:wIMxjTbKpWGQk4CV9WltlG6haB4brjSH/dvAohBPM1I=
|
||||
github.com/elastic/go-seccomp-bpf v1.4.0 h1:6y3lYrEHrLH9QzUgOiK8WDqmPaMnnB785WxibCNIOH4=
|
||||
github.com/elastic/go-seccomp-bpf v1.4.0/go.mod h1:wIMxjTbKpWGQk4CV9WltlG6haB4brjSH/dvAohBPM1I=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -36,7 +36,7 @@ type Cgroup interface {
|
||||
// SetCPUBandwidth sets the cpu bandwidth. Times in ns
|
||||
SetCPUBandwidth(quota, period uint64) error
|
||||
|
||||
// SetCpusetCpus sets the availabile cpu to use (cpuset.cpus).
|
||||
// SetCpusetCpus sets the available cpu to use (cpuset.cpus).
|
||||
SetCPUSet([]byte) error
|
||||
|
||||
// SetMemoryLimit sets memory.limit_in_bytes
|
||||
|
@ -1,13 +1,14 @@
|
||||
// Package cgroup provices builder to create cgroup
|
||||
// Package cgroup provides builder to create cgroup
|
||||
// under systemd defined mount path (i.e.,sys/fs/cgroup) including v1 and
|
||||
// v2 implementation.
|
||||
//
|
||||
// Available cgroup controller:
|
||||
// cpu
|
||||
// cpuset
|
||||
// cpuacct
|
||||
// memory
|
||||
// pids
|
||||
//
|
||||
// cpu
|
||||
// cpuset
|
||||
// cpuacct
|
||||
// memory
|
||||
// pids
|
||||
//
|
||||
// Current not available: devices, freezer, net_cls, blkio, perf_event, net_prio, huge_tlb, rdma
|
||||
package cgroup
|
||||
|
@ -105,7 +105,7 @@ func DetectType() CgroupType {
|
||||
// if /sys/fs/cgroup is mounted as CGROUPV2 or TMPFS (V1)
|
||||
var st unix.Statfs_t
|
||||
if err := unix.Statfs(basePath, &st); err != nil {
|
||||
// ignore errors, defalting to CgroupV1
|
||||
// ignore errors, defaulting to CgroupV1
|
||||
return CgroupTypeV1
|
||||
}
|
||||
if st.Type == unix.CGROUP2_SUPER_MAGIC {
|
||||
|
@ -264,7 +264,7 @@ func copyCgroupPropertyFromParent(path, name string) error {
|
||||
if len(bytes.TrimSpace(b)) > 0 {
|
||||
return nil
|
||||
}
|
||||
// otherwise copy from parent, first to ensure it is empty by recurssion
|
||||
// otherwise copy from parent, first to ensure it is empty by recursion
|
||||
if err := copyCgroupPropertyFromParent(filepath.Dir(path), name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host
|
||||
}
|
||||
}
|
||||
|
||||
// pivit_root
|
||||
// pivot_root
|
||||
if pivotRoot != nil {
|
||||
// mkdir("old_root")
|
||||
_, _, err1 = syscall.RawSyscall(syscall.SYS_MKDIRAT, uintptr(_AT_FDCWD), uintptr(unsafe.Pointer(&oldRoot[0])), 0755)
|
||||
@ -462,7 +462,7 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host
|
||||
// Fix potential ETXTBSY but with caution (max 50 attempt)
|
||||
// The ETXTBSY happens when we copy the executable into container, another goroutine
|
||||
// forks but not execve yet (time consuming for setting up mounting points), the forked
|
||||
// process is still holding the fd of the copyied executable fd. However, we don't
|
||||
// process is still holding the fd of the copied executable fd. However, we don't
|
||||
// want to have different logic to lock the container creation
|
||||
for range [50]struct{}{} {
|
||||
if err1 != syscall.ETXTBSY {
|
||||
|
@ -14,7 +14,7 @@ type Runner struct {
|
||||
// POSIX Resource limit set by set rlimit
|
||||
RLimits []rlimit.RLimit
|
||||
|
||||
// file disriptors map for new process, from 0 to len - 1
|
||||
// file descriptors map for new process, from 0 to len - 1
|
||||
Files []uintptr
|
||||
|
||||
// work path set by chdir(dir) (current working directory for child)
|
||||
@ -24,7 +24,7 @@ type Runner struct {
|
||||
// sandbox profile defines the sandbox profile for sandbox_init syscall
|
||||
SandboxProfile string
|
||||
|
||||
// Parent and child process with sync sataus through a socket pair.
|
||||
// Parent and child process with sync status through a socket pair.
|
||||
// SyncFunc will invoke with the child pid. If SyncFunc return some error,
|
||||
// parent will signal child to stop and report the error
|
||||
// SyncFunc is called right before execve, thus it could track cpu more accurately
|
||||
|
@ -21,7 +21,7 @@ type Runner struct {
|
||||
// POSIX Resource limit set by set rlimit
|
||||
RLimits []rlimit.RLimit
|
||||
|
||||
// file disriptors map for new process, from 0 to len - 1
|
||||
// file descriptors map for new process, from 0 to len - 1
|
||||
Files []uintptr
|
||||
|
||||
// work path set by chdir(dir) (current working directory for child)
|
||||
@ -65,7 +65,7 @@ type Runner struct {
|
||||
// by a child process started by StartProcess.
|
||||
Credential *syscall.Credential
|
||||
|
||||
// Parent and child process with sync sataus through a socket pair.
|
||||
// Parent and child process with sync status through a socket pair.
|
||||
// SyncFunc will invoke with the child pid. If SyncFunc return some error,
|
||||
// parent will signal child to stop and report the error
|
||||
// SyncFunc is called right before execve, thus it could track cpu more accurately
|
||||
|
@ -1,3 +1,3 @@
|
||||
// Package ptracer provides platfirm independent ptrace pooling loop
|
||||
// Package ptracer provides platform independent ptrace pooling loop
|
||||
// interface to trace program syscalls on Linux.
|
||||
package ptracer
|
||||
|
@ -8,7 +8,7 @@ type TraceAction int
|
||||
const (
|
||||
// TraceAllow does not do anything
|
||||
TraceAllow TraceAction = iota
|
||||
// TraceBan skippes the syscall and set the return code specified by SetReturnCode
|
||||
// TraceBan skips the syscall and set the return code specified by SetReturnCode
|
||||
TraceBan
|
||||
// TraceKill referred as dangerous action have been detected
|
||||
TraceKill
|
||||
|
@ -34,7 +34,7 @@ func (t *Tracer) trace(c context.Context, pgid int) (result runner.Result) {
|
||||
cc, cancel := context.WithCancel(c)
|
||||
defer cancel()
|
||||
|
||||
// handle cancelation
|
||||
// handle cancellation
|
||||
go func() {
|
||||
<-cc.Done()
|
||||
killAll(pgid)
|
||||
|
@ -1,33 +1,34 @@
|
||||
// Package runner provides common interface for program runner together with
|
||||
// common types including Result, Limit, Size and Status.
|
||||
//
|
||||
// Status
|
||||
// # Status
|
||||
//
|
||||
// Status defines the program running result status including
|
||||
// Normal
|
||||
// Program Error
|
||||
// Resource Limit Exceeded (Time / Memory / Output)
|
||||
// Unauthorized Access (Disallowed Syscall)
|
||||
// Runtime Error (Signaled / Nonzero Exit Status)
|
||||
// Program Runner Error
|
||||
//
|
||||
// Size
|
||||
// Normal
|
||||
// Program Error
|
||||
// Resource Limit Exceeded (Time / Memory / Output)
|
||||
// Unauthorized Access (Disallowed Syscall)
|
||||
// Runtime Error (Signaled / Nonzero Exit Status)
|
||||
// Program Runner Error
|
||||
//
|
||||
// # Size
|
||||
//
|
||||
// Size defines size in bytes, underlying type is uint64 so it
|
||||
// is effective to store up to EiB of size
|
||||
//
|
||||
// Limit
|
||||
// # Limit
|
||||
//
|
||||
// Limit defines Time & Memory restriction on program runner
|
||||
//
|
||||
// Result
|
||||
// # Result
|
||||
//
|
||||
// Result defines program running result including
|
||||
// Status, ExitStatus, Detailed Error, Time, Memory,
|
||||
// SetupTime and RunningTime (in real clock)
|
||||
//
|
||||
// Runner
|
||||
// # Runner
|
||||
//
|
||||
// General interface to run a program, including a context
|
||||
// for canclation
|
||||
// for cancellation
|
||||
package runner
|
||||
|
@ -20,7 +20,7 @@ type Runner struct {
|
||||
// fexecve
|
||||
ExecFile uintptr
|
||||
|
||||
// file disriptors for new process, from 0 to len - 1
|
||||
// file descriptors for new process, from 0 to len - 1
|
||||
Files []uintptr
|
||||
|
||||
// Resource limit set by set rlimit
|
||||
@ -45,7 +45,7 @@ type Runner struct {
|
||||
SyncFunc func(pid int) error
|
||||
}
|
||||
|
||||
// BanRet defines the return value for a syscall ban acction
|
||||
// BanRet defines the return value for a syscall ban action
|
||||
var BanRet = syscall.EACCES
|
||||
|
||||
// Handler defines the action when a file access encountered
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// Size stores number of byte for the object. E.g. Memory.
|
||||
// Maximun size is bounded by 64-bit limit
|
||||
// Maximum size is bounded by 64-bit limit
|
||||
type Size uint64
|
||||
|
||||
// String stringer interface for print
|
||||
|
@ -19,7 +19,7 @@ type Runner struct {
|
||||
// workdir is the current dir after unshare mount namespaces
|
||||
WorkDir string
|
||||
|
||||
// file disriptors for new process, from 0 to len - 1
|
||||
// file descriptors for new process, from 0 to len - 1
|
||||
Files []uintptr
|
||||
|
||||
// Resource limit set by set rlimit
|
||||
|
Loading…
Reference in New Issue
Block a user