mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
normalize naming schema
This commit is contained in:
parent
ebab7514d1
commit
7b06ce65ac
16
README.md
16
README.md
@ -54,21 +54,21 @@ Default file access syscall check:
|
|||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
- tracer: ptrace tracer and provides syscall trap filter context
|
|
||||||
- deamon: creates pre-forked container to run programs inside
|
- deamon: creates pre-forked container to run programs inside
|
||||||
- runprogram: wrapper to call forkexec and trecer
|
- runner: interface to run program
|
||||||
- rununshared: wrapper to call forkexec and unshared namespaces
|
- config: defines arch & language specified trace condition for seccomp and ptrace
|
||||||
- runconfig: defines arch & language specified trace condition for seccomp and ptrace
|
- ptrace: wrapper to call forkexec and ptracer
|
||||||
- types: general runtime specs
|
- unshare: wrapper to call forkexec and unshared namespaces
|
||||||
- specs: provides general res / result data structures
|
- ptracer: ptrace tracer and provides syscall trap filter context
|
||||||
|
- types: provides general res / result data structures
|
||||||
|
|
||||||
## Executable
|
## Executable
|
||||||
|
|
||||||
- run_program: safely run program by unshare / ptrace / pre-forked containers
|
- runprog: safely run program by unshare / ptrace / pre-forked containers
|
||||||
|
|
||||||
## Configurations
|
## Configurations
|
||||||
|
|
||||||
- run_program/config.go: all configs toward running specs
|
- run/config/config.go: all configs toward running specs
|
||||||
|
|
||||||
## Benchmarks (docker desktop amd64 / native arm64)
|
## Benchmarks (docker desktop amd64 / native arm64)
|
||||||
|
|
||||||
|
|||||||
@ -12,10 +12,11 @@ import (
|
|||||||
"github.com/criyle/go-sandbox/pkg/cgroup"
|
"github.com/criyle/go-sandbox/pkg/cgroup"
|
||||||
"github.com/criyle/go-sandbox/pkg/memfd"
|
"github.com/criyle/go-sandbox/pkg/memfd"
|
||||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||||
"github.com/criyle/go-sandbox/runconfig"
|
"github.com/criyle/go-sandbox/runner"
|
||||||
"github.com/criyle/go-sandbox/runprogram"
|
"github.com/criyle/go-sandbox/runner/config"
|
||||||
"github.com/criyle/go-sandbox/rununshared"
|
"github.com/criyle/go-sandbox/runner/ptrace"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/runner/unshare"
|
||||||
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -33,11 +34,6 @@ var (
|
|||||||
args []string
|
args []string
|
||||||
)
|
)
|
||||||
|
|
||||||
// Runner can be ptraced runner or namespaced runner
|
|
||||||
type Runner interface {
|
|
||||||
Start(<-chan struct{}) (<-chan specs.TraceResult, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printUsage() {
|
func printUsage() {
|
||||||
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] <args>\n", os.Args[0])
|
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] <args>\n", os.Args[0])
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
@ -104,28 +100,28 @@ func main() {
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
rt, err := run()
|
rt, err := start()
|
||||||
if rt == nil {
|
if rt == nil {
|
||||||
rt = &specs.TraceResult{
|
rt = &types.Result{
|
||||||
TraceStatus: specs.TraceCodeFatal,
|
Status: types.StatusFatal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil && rt.TraceStatus != specs.TraceCodeNormal {
|
if err == nil && rt.Status != types.StatusNormal {
|
||||||
err = rt.TraceStatus
|
err = rt.Status
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug(err)
|
debug(err)
|
||||||
c, ok := err.(specs.TraceCode)
|
c, ok := err.(types.Status)
|
||||||
if !ok {
|
if !ok {
|
||||||
c = specs.TraceCodeFatal
|
c = types.StatusFatal
|
||||||
}
|
}
|
||||||
// Handle fatal error from trace
|
// Handle fatal error from trace
|
||||||
fmt.Fprintf(f, "%d %d %d %d\n", int(c), rt.UserTime, rt.UserMem, rt.ExitCode)
|
fmt.Fprintf(f, "%d %d %d %d\n", int(c), rt.UserTime, rt.UserMem, rt.ExitStatus)
|
||||||
if c == specs.TraceCodeFatal {
|
if c == types.StatusFatal {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(f, "%d %d %d %d\n", 0, rt.UserTime, rt.UserMem, rt.ExitCode)
|
fmt.Fprintf(f, "%d %d %d %d\n", 0, rt.UserTime, rt.UserMem, rt.ExitStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,22 +130,22 @@ type deamonRunner struct {
|
|||||||
*deamon.ExecveParam
|
*deamon.ExecveParam
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *deamonRunner) Start(done <-chan struct{}) (<-chan specs.TraceResult, error) {
|
func (r *deamonRunner) Start(done <-chan struct{}) (<-chan types.Result, error) {
|
||||||
return r.Master.Execve(done, r.ExecveParam)
|
return r.Master.Execve(done, r.ExecveParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
func run() (*specs.TraceResult, error) {
|
func start() (*types.Result, error) {
|
||||||
var (
|
var (
|
||||||
runner Runner
|
runner runner.Runner
|
||||||
cg *cgroup.CGroup
|
cg *cgroup.CGroup
|
||||||
err error
|
err error
|
||||||
execFile uintptr
|
execFile uintptr
|
||||||
rt specs.TraceResult
|
rt types.Result
|
||||||
)
|
)
|
||||||
|
|
||||||
addRead := runconfig.GetExtraSet(addReadable, addRawReadable)
|
addRead := config.GetExtraSet(addReadable, addRawReadable)
|
||||||
addWrite := runconfig.GetExtraSet(addWritable, addRawWritable)
|
addWrite := config.GetExtraSet(addWritable, addRawWritable)
|
||||||
h := runconfig.GetConf(pType, workPath, args, addRead, addWrite, allowProc, showDetails)
|
h := config.GetConf(pType, workPath, args, addRead, addWrite, allowProc, showDetails)
|
||||||
|
|
||||||
if useCGroup {
|
if useCGroup {
|
||||||
cg, err = cgroup.NewCGroup("run_program")
|
cg, err = cgroup.NewCGroup("run_program")
|
||||||
@ -245,21 +241,20 @@ func run() (*specs.TraceResult, error) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
runner = &rununshared.RunUnshared{
|
runner = &unshare.Runner{
|
||||||
Args: h.Args,
|
Args: h.Args,
|
||||||
Env: []string{pathEnv},
|
Env: []string{pathEnv},
|
||||||
ExecFile: execFile,
|
ExecFile: execFile,
|
||||||
WorkDir: "/w",
|
WorkDir: "/w",
|
||||||
Files: fds,
|
Files: fds,
|
||||||
RLimits: rlims,
|
RLimits: rlims,
|
||||||
ResLimits: specs.ResLimit{
|
ResLimits: types.Limit{
|
||||||
TimeLimit: timeLimit * 1e3,
|
TimeLimit: timeLimit * 1e3,
|
||||||
RealTimeLimit: realTimeLimit * 1e3,
|
MemoryLimit: memoryLimit << 10,
|
||||||
MemoryLimit: memoryLimit << 10,
|
|
||||||
},
|
},
|
||||||
SyscallAllowed: h.SyscallAllow,
|
SyscallAllowed: h.SyscallAllow,
|
||||||
Root: root,
|
Root: root,
|
||||||
Mounts: rununshared.GetDefaultMounts(root, []rununshared.AddBind{
|
Mounts: unshare.GetDefaultMounts(root, []unshare.AddBind{
|
||||||
{
|
{
|
||||||
Source: workPath,
|
Source: workPath,
|
||||||
Target: "w",
|
Target: "w",
|
||||||
@ -271,16 +266,15 @@ func run() (*specs.TraceResult, error) {
|
|||||||
DomainName: "run_program",
|
DomainName: "run_program",
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
runner = &runprogram.RunProgram{
|
runner = &ptrace.Runner{
|
||||||
Args: h.Args,
|
Args: h.Args,
|
||||||
Env: []string{pathEnv},
|
Env: []string{pathEnv},
|
||||||
ExecFile: execFile,
|
ExecFile: execFile,
|
||||||
WorkDir: workPath,
|
WorkDir: workPath,
|
||||||
RLimits: rlims,
|
RLimits: rlims,
|
||||||
TraceLimit: specs.ResLimit{
|
TraceLimit: types.Limit{
|
||||||
TimeLimit: timeLimit * 1e3,
|
TimeLimit: timeLimit * 1e3,
|
||||||
RealTimeLimit: realTimeLimit * 1e3,
|
MemoryLimit: memoryLimit << 10,
|
||||||
MemoryLimit: memoryLimit << 10,
|
|
||||||
},
|
},
|
||||||
Files: fds,
|
Files: fds,
|
||||||
SyscallAllowed: h.SyscallAllow,
|
SyscallAllowed: h.SyscallAllow,
|
||||||
@ -309,7 +303,7 @@ func run() (*specs.TraceResult, error) {
|
|||||||
case <-sig:
|
case <-sig:
|
||||||
close(done)
|
close(done)
|
||||||
rt = <-s
|
rt = <-s
|
||||||
rt.TraceStatus = specs.TraceCodeFatal
|
rt.Status = types.StatusFatal
|
||||||
|
|
||||||
case <-tC:
|
case <-tC:
|
||||||
close(done)
|
close(done)
|
||||||
@ -320,8 +314,8 @@ func run() (*specs.TraceResult, error) {
|
|||||||
eTime := time.Now()
|
eTime := time.Now()
|
||||||
|
|
||||||
if rt.SetUpTime == 0 {
|
if rt.SetUpTime == 0 {
|
||||||
rt.SetUpTime = int64(rTime.Sub(sTime))
|
rt.SetUpTime = rTime.Sub(sTime)
|
||||||
rt.RunningTime = int64(eTime.Sub(rTime))
|
rt.RunningTime = eTime.Sub(rTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("results:", rt, err)
|
debug("results:", rt, err)
|
||||||
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||||
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerInit is called for container init process
|
// ContainerInit is called for container init process
|
||||||
@ -231,19 +231,19 @@ loop:
|
|||||||
break loop
|
break loop
|
||||||
|
|
||||||
case wstatus.Signaled():
|
case wstatus.Signaled():
|
||||||
var status specs.TraceCode
|
var status types.Status
|
||||||
switch wstatus.Signal() {
|
switch wstatus.Signal() {
|
||||||
// kill signal treats as TLE
|
// kill signal treats as TLE
|
||||||
case syscall.SIGXCPU, syscall.SIGKILL:
|
case syscall.SIGXCPU, syscall.SIGKILL:
|
||||||
status = specs.TraceCodeTLE
|
status = types.StatusTLE
|
||||||
case syscall.SIGXFSZ:
|
case syscall.SIGXFSZ:
|
||||||
status = specs.TraceCodeOLE
|
status = types.StatusOLE
|
||||||
case syscall.SIGSYS:
|
case syscall.SIGSYS:
|
||||||
status = specs.TraceCodeBan
|
status = types.StatusBan
|
||||||
default:
|
default:
|
||||||
status = specs.TraceCodeRE
|
status = types.StatusRE
|
||||||
}
|
}
|
||||||
reply := Reply{TraceStatus: status}
|
reply := Reply{Status: status}
|
||||||
sendReply(s, &reply, nil)
|
sendReply(s, &reply, nil)
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ Any socket related error will cause the deamon exit (with all process inside con
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cmd is the control message send into deamon
|
// Cmd is the control message send into deamon
|
||||||
@ -50,7 +50,7 @@ type Cmd struct {
|
|||||||
|
|
||||||
// Reply is the reply message send back to controller
|
// Reply is the reply message send back to controller
|
||||||
type Reply struct {
|
type Reply struct {
|
||||||
Error string // empty if no error
|
Error string // empty if no error
|
||||||
ExitStatus int // waitpid exit status
|
ExitStatus int // waitpid exit status
|
||||||
TraceStatus specs.TraceCode // TraceCode
|
Status types.Status // return status
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
|
||||||
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
||||||
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecveParam is parameters to run process inside container
|
// ExecveParam is parameters to run process inside container
|
||||||
@ -23,7 +23,7 @@ type ExecveParam struct {
|
|||||||
|
|
||||||
// Execve runs process inside container
|
// Execve runs process inside container
|
||||||
// accepts done for cancelation
|
// accepts done for cancelation
|
||||||
func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan specs.TraceResult, error) {
|
func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.Result, error) {
|
||||||
var files []int
|
var files []int
|
||||||
if param.ExecFile > 0 {
|
if param.ExecFile > 0 {
|
||||||
files = append(files, int(param.ExecFile))
|
files = append(files, int(param.ExecFile))
|
||||||
@ -60,16 +60,16 @@ func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan specs.
|
|||||||
return nil, fmt.Errorf("execve: ok failed(%v)", err)
|
return nil, fmt.Errorf("execve: ok failed(%v)", err)
|
||||||
}
|
}
|
||||||
// make sure goroutine not leaked (blocked) even if result is not consumed
|
// make sure goroutine not leaked (blocked) even if result is not consumed
|
||||||
wait := make(chan specs.TraceResult, 1)
|
wait := make(chan types.Result, 1)
|
||||||
waitDone := make(chan struct{})
|
waitDone := make(chan struct{})
|
||||||
// Wait
|
// Wait
|
||||||
go func() {
|
go func() {
|
||||||
defer close(wait)
|
defer close(wait)
|
||||||
reply2, _, _ := m.recvReply()
|
reply2, _, _ := m.recvReply()
|
||||||
close(waitDone)
|
close(waitDone)
|
||||||
wait <- specs.TraceResult{
|
wait <- types.Result{
|
||||||
ExitCode: reply2.ExitStatus,
|
ExitStatus: reply2.ExitStatus,
|
||||||
TraceStatus: reply2.TraceStatus,
|
Status: reply2.Status,
|
||||||
}
|
}
|
||||||
// done signal (should recv after kill)
|
// done signal (should recv after kill)
|
||||||
m.recvReply()
|
m.recvReply()
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -4,5 +4,5 @@ go 1.12
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1
|
github.com/seccomp/libseccomp-golang v0.9.1
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456
|
golang.org/x/sys v0.0.0-20190830023255-19e00faab6ad
|
||||||
)
|
)
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -1,4 +1,4 @@
|
|||||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
golang.org/x/sys v0.0.0-20190830023255-19e00faab6ad h1:cCejgArrk10gX6kFqjWeLwXD7aVMqWoRpyUCaaJSggc=
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190830023255-19e00faab6ad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Runner is the RunProgramConfig including the exec path, argv
|
// Runner is the runptraceConfig including the exec path, argv
|
||||||
// and resource limits. It creates tracee for ptrace-based tracer.
|
// and resource limits. It creates tracee for ptrace-based tracer.
|
||||||
// It can also create unshared process in another namespace
|
// It can also create unshared process in another namespace
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
unix "golang.org/x/sys/unix"
|
unix "golang.org/x/sys/unix"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
// TraceAction defines the action returned by TraceHandle
|
// TraceAction defines the action returned by TraceHandle
|
||||||
type TraceAction int
|
type TraceAction int
|
||||||
@ -1,11 +1,12 @@
|
|||||||
package tracer
|
package ptracer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
|
||||||
unix "golang.org/x/sys/unix"
|
unix "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgDisallow, Msghandle defines the action needed when traped by
|
// MsgDisallow, Msghandle defines the action needed when traped by
|
||||||
@ -16,9 +17,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Trace starts new goroutine and trace runner with ptrace
|
// Trace starts new goroutine and trace runner with ptrace
|
||||||
func Trace(done <-chan struct{}, handler Handler, runner Runner, limits specs.ResLimit) (<-chan specs.TraceResult, error) {
|
func Trace(done <-chan struct{}, handler Handler, runner Runner, limits types.Limit) (<-chan types.Result, error) {
|
||||||
var err error
|
var err error
|
||||||
result := make(chan specs.TraceResult, 1)
|
result := make(chan types.Result, 1)
|
||||||
start := make(chan struct{})
|
start := make(chan struct{})
|
||||||
finish := make(chan struct{})
|
finish := make(chan struct{})
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ func Trace(done <-chan struct{}, handler Handler, runner Runner, limits specs.Re
|
|||||||
// TraceRun start and traces all child process by runner in the calling goroutine
|
// TraceRun start and traces all child process by runner in the calling goroutine
|
||||||
// parameter done used to cancel work, start is used notify child starts
|
// parameter done used to cancel work, start is used notify child starts
|
||||||
func TraceRun(done <-chan struct{}, start chan<- struct{},
|
func TraceRun(done <-chan struct{}, start chan<- struct{},
|
||||||
handler Handler, runner Runner, limits specs.ResLimit) (result specs.TraceResult, err error) {
|
handler Handler, runner Runner, limits types.Limit) (result types.Result, err error) {
|
||||||
var (
|
var (
|
||||||
wstatus unix.WaitStatus // wait4 wait status
|
wstatus unix.WaitStatus // wait4 wait status
|
||||||
rusage unix.Rusage // wait4 rusage
|
rusage unix.Rusage // wait4 rusage
|
||||||
@ -61,7 +62,7 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
handler.Debug("tracer started: ", pgid, err)
|
handler.Debug("tracer started: ", pgid, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.Debug("start tracee failed: ", err)
|
handler.Debug("start tracee failed: ", err)
|
||||||
result.TraceStatus = specs.TraceCodeRE
|
result.Status = types.StatusRE
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,17 +84,17 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
// also ensure processes was well terminated
|
// also ensure processes was well terminated
|
||||||
defer func() {
|
defer func() {
|
||||||
if tle {
|
if tle {
|
||||||
err = specs.TraceCodeTLE
|
err = types.StatusTLE
|
||||||
}
|
}
|
||||||
if err2 := recover(); err2 != nil {
|
if err2 := recover(); err2 != nil {
|
||||||
handler.Debug(err2)
|
handler.Debug(err2)
|
||||||
err = specs.TraceCodeFatal
|
err = types.StatusFatal
|
||||||
}
|
}
|
||||||
// kill all tracee upon return
|
// kill all tracee upon return
|
||||||
killAll(pgid)
|
killAll(pgid)
|
||||||
collectZombie(pgid)
|
collectZombie(pgid)
|
||||||
result.SetUpTime = fTime.Sub(sTime).Nanoseconds()
|
result.SetUpTime = fTime.Sub(sTime)
|
||||||
result.RunningTime = time.Since(fTime).Nanoseconds()
|
result.RunningTime = time.Since(fTime)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// trace unixs
|
// trace unixs
|
||||||
@ -107,11 +108,11 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.Debug("wait4 failed: ", err)
|
handler.Debug("wait4 failed: ", err)
|
||||||
return result, specs.TraceCodeFatal
|
return result, types.StatusFatal
|
||||||
}
|
}
|
||||||
handler.Debug("------ ", pid, " ------")
|
handler.Debug("------ ", pid, " ------")
|
||||||
|
|
||||||
status := specs.TraceCodeNormal
|
status := types.StatusNormal
|
||||||
if pid == pgid {
|
if pid == pgid {
|
||||||
// update resource usage and check against limits
|
// update resource usage and check against limits
|
||||||
userTime := uint64(rusage.Utime.Sec*1e3 + rusage.Utime.Usec/1e3) // ms
|
userTime := uint64(rusage.Utime.Sec*1e3 + rusage.Utime.Usec/1e3) // ms
|
||||||
@ -119,17 +120,17 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
|
|
||||||
// check tle / mle
|
// check tle / mle
|
||||||
if userTime > limits.TimeLimit {
|
if userTime > limits.TimeLimit {
|
||||||
status = specs.TraceCodeTLE
|
status = types.StatusTLE
|
||||||
}
|
}
|
||||||
if userMem > limits.MemoryLimit {
|
if userMem > limits.MemoryLimit {
|
||||||
status = specs.TraceCodeMLE
|
status = types.StatusMLE
|
||||||
}
|
}
|
||||||
result = specs.TraceResult{
|
result = types.Result{
|
||||||
UserTime: userTime,
|
Status: status,
|
||||||
UserMem: userMem,
|
UserTime: userTime,
|
||||||
TraceStatus: status,
|
UserMem: userMem,
|
||||||
}
|
}
|
||||||
if status != specs.TraceCodeNormal {
|
if status != types.StatusNormal {
|
||||||
return result, status
|
return result, status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,11 +142,11 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
handler.Debug("process exited: ", pid, wstatus.ExitStatus())
|
handler.Debug("process exited: ", pid, wstatus.ExitStatus())
|
||||||
if pid == pgid {
|
if pid == pgid {
|
||||||
if execved {
|
if execved {
|
||||||
result.ExitCode = wstatus.ExitStatus()
|
result.ExitStatus = wstatus.ExitStatus()
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
result.TraceStatus = specs.TraceCodeFatal
|
result.Status = types.StatusFatal
|
||||||
return result, specs.TraceCodeFatal
|
return result, types.StatusFatal
|
||||||
}
|
}
|
||||||
|
|
||||||
case wstatus.Signaled():
|
case wstatus.Signaled():
|
||||||
@ -155,15 +156,15 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
delete(traced, pid)
|
delete(traced, pid)
|
||||||
switch sig {
|
switch sig {
|
||||||
case unix.SIGXCPU, unix.SIGKILL:
|
case unix.SIGXCPU, unix.SIGKILL:
|
||||||
status = specs.TraceCodeTLE
|
status = types.StatusTLE
|
||||||
case unix.SIGXFSZ:
|
case unix.SIGXFSZ:
|
||||||
status = specs.TraceCodeOLE
|
status = types.StatusOLE
|
||||||
case unix.SIGSYS:
|
case unix.SIGSYS:
|
||||||
status = specs.TraceCodeBan
|
status = types.StatusBan
|
||||||
default:
|
default:
|
||||||
status = specs.TraceCodeRE
|
status = types.StatusRE
|
||||||
}
|
}
|
||||||
result.TraceStatus = status
|
result.Status = status
|
||||||
return result, status
|
return result, status
|
||||||
}
|
}
|
||||||
unix.PtraceCont(pid, int(sig))
|
unix.PtraceCont(pid, int(sig))
|
||||||
@ -176,7 +177,7 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
// Ptrace set option valid if the tracee is stopped
|
// Ptrace set option valid if the tracee is stopped
|
||||||
err = setPtraceOption(pid)
|
err = setPtraceOption(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.TraceStatus = specs.TraceCodeFatal
|
result.Status = types.StatusFatal
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
// give the customized handle for syscall
|
// give the customized handle for syscall
|
||||||
err := handleTrap(handler, pid)
|
err := handleTrap(handler, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.TraceStatus = specs.TraceCodeBan
|
result.Status = types.StatusBan
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -218,12 +219,12 @@ func TraceRun(done <-chan struct{}, start chan<- struct{},
|
|||||||
// check if cpu rlimit hit
|
// check if cpu rlimit hit
|
||||||
switch stopSig {
|
switch stopSig {
|
||||||
case unix.SIGXCPU:
|
case unix.SIGXCPU:
|
||||||
status = specs.TraceCodeTLE
|
status = types.StatusTLE
|
||||||
case unix.SIGXFSZ:
|
case unix.SIGXFSZ:
|
||||||
status = specs.TraceCodeOLE
|
status = types.StatusOLE
|
||||||
}
|
}
|
||||||
if status != specs.TraceCodeNormal {
|
if status != types.StatusNormal {
|
||||||
result.TraceStatus = status
|
result.Status = status
|
||||||
return result, status
|
return result, status
|
||||||
}
|
}
|
||||||
// Likely encountered SIGSEGV (segment violation)
|
// Likely encountered SIGSEGV (segment violation)
|
||||||
@ -272,7 +273,7 @@ func handleTrap(handler Handler, pid int) error {
|
|||||||
return ctx.skipSyscall()
|
return ctx.skipSyscall()
|
||||||
|
|
||||||
case TraceKill:
|
case TraceKill:
|
||||||
return specs.TraceCodeBan
|
return types.StatusBan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// This file includes configs for the run program settings
|
// This file includes configs for the run program settings
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ var (
|
|||||||
|
|
||||||
// config for different type of program
|
// config for different type of program
|
||||||
// workpath and arg0 have additional read / stat permission
|
// workpath and arg0 have additional read / stat permission
|
||||||
runprogramConfig = map[string]ProgramConfig{
|
runptraceConfig = map[string]ProgramConfig{
|
||||||
"python2.7": ProgramConfig{
|
"python2.7": ProgramConfig{
|
||||||
Syscall: SyscallConfig{
|
Syscall: SyscallConfig{
|
||||||
ExtraAllow: []string{
|
ExtraAllow: []string{
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// This file includes configs for the run program settings
|
// This file includes configs for the run program settings
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// This file includes configs for the run program settings
|
// This file includes configs for the run program settings
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// This file includes configs for the run program settings
|
// This file includes configs for the run program settings
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// GetConf return file access check set, syscall counter, allow and traced syscall arrays and new args
|
// GetConf return file access check set, syscall counter, allow and traced syscall arrays and new args
|
||||||
func GetConf(pType, workPath string, args, addRead, addWrite []string, allowProc, showDetails bool) *Handler {
|
func GetConf(pType, workPath string, args, addRead, addWrite []string, allowProc, showDetails bool) *Handler {
|
||||||
@ -18,7 +18,7 @@ func GetConf(pType, workPath string, args, addRead, addWrite []string, allowProc
|
|||||||
fs.Readable.AddRange(addRead, workPath)
|
fs.Readable.AddRange(addRead, workPath)
|
||||||
fs.Writable.AddRange(addWrite, workPath)
|
fs.Writable.AddRange(addWrite, workPath)
|
||||||
|
|
||||||
if c, o := runprogramConfig[pType]; o {
|
if c, o := runptraceConfig[pType]; o {
|
||||||
allow = append(allow, c.Syscall.ExtraAllow...)
|
allow = append(allow, c.Syscall.ExtraAllow...)
|
||||||
trace = append(trace, c.Syscall.ExtraBan...)
|
trace = append(trace, c.Syscall.ExtraBan...)
|
||||||
sc.AddRange(c.Syscall.ExtraCount)
|
sc.AddRange(c.Syscall.ExtraCount)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// ProgramConfig defines the extra config apply to program type
|
// ProgramConfig defines the extra config apply to program type
|
||||||
type ProgramConfig struct {
|
type ProgramConfig struct {
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -1,13 +1,13 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/runprogram"
|
"github.com/criyle/go-sandbox/runner/ptrace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler defines file access restricted handler to call the runprogram
|
// Handler defines file access restricted handler to call the ptrace
|
||||||
// safe runner
|
// safe runner
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
SyscallAllow, SyscallTrace, Args []string
|
SyscallAllow, SyscallTrace, Args []string
|
||||||
@ -17,51 +17,51 @@ type Handler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CheckRead checks whether the file have read permission
|
// CheckRead checks whether the file have read permission
|
||||||
func (h *Handler) CheckRead(fn string) runprogram.TraceAction {
|
func (h *Handler) CheckRead(fn string) ptrace.TraceAction {
|
||||||
if !h.FileSet.IsReadableFile(fn) {
|
if !h.FileSet.IsReadableFile(fn) {
|
||||||
return h.onDgsFileDetect(fn)
|
return h.onDgsFileDetect(fn)
|
||||||
}
|
}
|
||||||
return runprogram.TraceAllow
|
return ptrace.TraceAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckWrite checks whether the file have write permission
|
// CheckWrite checks whether the file have write permission
|
||||||
func (h *Handler) CheckWrite(fn string) runprogram.TraceAction {
|
func (h *Handler) CheckWrite(fn string) ptrace.TraceAction {
|
||||||
if !h.FileSet.IsWritableFile(fn) {
|
if !h.FileSet.IsWritableFile(fn) {
|
||||||
return h.onDgsFileDetect(fn)
|
return h.onDgsFileDetect(fn)
|
||||||
}
|
}
|
||||||
return runprogram.TraceAllow
|
return ptrace.TraceAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckStat checks whether the file have stat permission
|
// CheckStat checks whether the file have stat permission
|
||||||
func (h *Handler) CheckStat(fn string) runprogram.TraceAction {
|
func (h *Handler) CheckStat(fn string) ptrace.TraceAction {
|
||||||
if !h.FileSet.IsStatableFile(fn) {
|
if !h.FileSet.IsStatableFile(fn) {
|
||||||
return h.onDgsFileDetect(fn)
|
return h.onDgsFileDetect(fn)
|
||||||
}
|
}
|
||||||
return runprogram.TraceAllow
|
return ptrace.TraceAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckSyscall checks syscalls other than allowed and traced agianst the
|
// CheckSyscall checks syscalls other than allowed and traced agianst the
|
||||||
// SyscallCounter
|
// SyscallCounter
|
||||||
func (h *Handler) CheckSyscall(syscallName string) runprogram.TraceAction {
|
func (h *Handler) CheckSyscall(syscallName string) ptrace.TraceAction {
|
||||||
// if it is traced, then try to count syscall
|
// if it is traced, then try to count syscall
|
||||||
if inside, allow := h.SyscallCounter.Check(syscallName); inside {
|
if inside, allow := h.SyscallCounter.Check(syscallName); inside {
|
||||||
if allow {
|
if allow {
|
||||||
return runprogram.TraceAllow
|
return ptrace.TraceAllow
|
||||||
}
|
}
|
||||||
return runprogram.TraceKill
|
return ptrace.TraceKill
|
||||||
}
|
}
|
||||||
// if it is traced but not counted, it should be soft banned
|
// if it is traced but not counted, it should be soft banned
|
||||||
return runprogram.TraceBan
|
return ptrace.TraceBan
|
||||||
}
|
}
|
||||||
|
|
||||||
// onDgsFileDetect soft ban file if in soft ban set
|
// onDgsFileDetect soft ban file if in soft ban set
|
||||||
// otherwise stops the trace process
|
// otherwise stops the trace process
|
||||||
func (h *Handler) onDgsFileDetect(name string) runprogram.TraceAction {
|
func (h *Handler) onDgsFileDetect(name string) ptrace.TraceAction {
|
||||||
if h.FileSet.IsSoftBanFile(name) {
|
if h.FileSet.IsSoftBanFile(name) {
|
||||||
return runprogram.TraceBan
|
return ptrace.TraceBan
|
||||||
}
|
}
|
||||||
h.print("Dangerous fileopen: ", name)
|
h.print("Dangerous fileopen: ", name)
|
||||||
return runprogram.TraceKill
|
return ptrace.TraceKill
|
||||||
}
|
}
|
||||||
|
|
||||||
// print is used to print debug information
|
// print is used to print debug information
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runconfig
|
package config
|
||||||
|
|
||||||
// SyscallCounter defines a count-down for each each syscall occurs
|
// SyscallCounter defines a count-down for each each syscall occurs
|
||||||
type SyscallCounter map[string]int
|
type SyscallCounter map[string]int
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package runprogram
|
package ptrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/tracer"
|
"github.com/criyle/go-sandbox/ptracer"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tracerHandler struct {
|
type tracerHandler struct {
|
||||||
@ -23,11 +23,11 @@ func (h *tracerHandler) Debug(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) getString(ctx *tracer.Context, addr uint) string {
|
func (h *tracerHandler) getString(ctx *ptracer.Context, addr uint) string {
|
||||||
return absPath(ctx.Pid, ctx.GetString(uintptr(addr)))
|
return absPath(ctx.Pid, ctx.GetString(uintptr(addr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) checkOpen(ctx *tracer.Context, addr uint, flags uint) TraceAction {
|
func (h *tracerHandler) checkOpen(ctx *ptracer.Context, addr uint, flags uint) TraceAction {
|
||||||
fn := h.getString(ctx, addr)
|
fn := h.getString(ctx, addr)
|
||||||
isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) &&
|
isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) &&
|
||||||
(flags&syscall.O_CREAT == 0) &&
|
(flags&syscall.O_CREAT == 0) &&
|
||||||
@ -41,25 +41,25 @@ func (h *tracerHandler) checkOpen(ctx *tracer.Context, addr uint, flags uint) Tr
|
|||||||
return h.Handler.CheckWrite(fn)
|
return h.Handler.CheckWrite(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) checkRead(ctx *tracer.Context, addr uint) TraceAction {
|
func (h *tracerHandler) checkRead(ctx *ptracer.Context, addr uint) TraceAction {
|
||||||
fn := h.getString(ctx, addr)
|
fn := h.getString(ctx, addr)
|
||||||
h.Debug("check read: ", fn)
|
h.Debug("check read: ", fn)
|
||||||
return h.Handler.CheckRead(fn)
|
return h.Handler.CheckRead(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) checkWrite(ctx *tracer.Context, addr uint) TraceAction {
|
func (h *tracerHandler) checkWrite(ctx *ptracer.Context, addr uint) TraceAction {
|
||||||
fn := h.getString(ctx, addr)
|
fn := h.getString(ctx, addr)
|
||||||
h.Debug("check write: ", fn)
|
h.Debug("check write: ", fn)
|
||||||
return h.Handler.CheckWrite(fn)
|
return h.Handler.CheckWrite(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) checkStat(ctx *tracer.Context, addr uint) TraceAction {
|
func (h *tracerHandler) checkStat(ctx *ptracer.Context, addr uint) TraceAction {
|
||||||
fn := h.getString(ctx, addr)
|
fn := h.getString(ctx, addr)
|
||||||
h.Debug("check stat: ", fn)
|
h.Debug("check stat: ", fn)
|
||||||
return h.Handler.CheckStat(fn)
|
return h.Handler.CheckStat(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) Handle(ctx *tracer.Context) tracer.TraceAction {
|
func (h *tracerHandler) Handle(ctx *ptracer.Context) ptracer.TraceAction {
|
||||||
var (
|
var (
|
||||||
action TraceAction
|
action TraceAction
|
||||||
syscallNo = ctx.SyscallNo()
|
syscallNo = ctx.SyscallNo()
|
||||||
@ -108,30 +108,30 @@ func (h *tracerHandler) Handle(ctx *tracer.Context) tracer.TraceAction {
|
|||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case TraceAllow:
|
case TraceAllow:
|
||||||
return tracer.TraceAllow
|
return ptracer.TraceAllow
|
||||||
case TraceBan:
|
case TraceBan:
|
||||||
h.Debug("<soft ban syscall>")
|
h.Debug("<soft ban syscall>")
|
||||||
return softBanSyscall(ctx)
|
return softBanSyscall(ctx)
|
||||||
default:
|
default:
|
||||||
return tracer.TraceKill
|
return ptracer.TraceKill
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) GetSyscallName(ctx *tracer.Context) (string, error) {
|
func (h *tracerHandler) GetSyscallName(ctx *ptracer.Context) (string, error) {
|
||||||
syscallNo := ctx.SyscallNo()
|
syscallNo := ctx.SyscallNo()
|
||||||
return libseccomp.ScmpSyscall(syscallNo).GetName()
|
return libseccomp.ScmpSyscall(syscallNo).GetName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tracerHandler) HandlerDisallow(name string) error {
|
func (h *tracerHandler) HandlerDisallow(name string) error {
|
||||||
if !h.Unsafe {
|
if !h.Unsafe {
|
||||||
return specs.TraceCodeBan
|
return types.StatusBan
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func softBanSyscall(ctx *tracer.Context) tracer.TraceAction {
|
func softBanSyscall(ctx *ptracer.Context) ptracer.TraceAction {
|
||||||
ctx.SetReturnValue(-int(BanRet))
|
ctx.SetReturnValue(-int(BanRet))
|
||||||
return tracer.TraceBan
|
return ptracer.TraceBan
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileMode(flags uint) string {
|
func getFileMode(flags uint) string {
|
||||||
@ -1,16 +1,16 @@
|
|||||||
package runprogram
|
package ptrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||||
"github.com/criyle/go-sandbox/pkg/seccomp"
|
"github.com/criyle/go-sandbox/pkg/seccomp"
|
||||||
"github.com/criyle/go-sandbox/tracer"
|
"github.com/criyle/go-sandbox/ptracer"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start starts the tracing process
|
// Start starts the tracing process
|
||||||
func (r *RunProgram) Start(done <-chan struct{}) (<-chan specs.TraceResult, error) {
|
func (r *Runner) Start(done <-chan struct{}) (<-chan types.Result, error) {
|
||||||
// build seccomp filter
|
// build seccomp filter
|
||||||
filter, err := buildFilter(r.ShowDetails, r.SyscallAllowed, r.SyscallTraced)
|
filter, err := buildFilter(r.ShowDetails, r.SyscallAllowed, r.SyscallTraced)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -42,7 +42,7 @@ func (r *RunProgram) Start(done <-chan struct{}) (<-chan specs.TraceResult, erro
|
|||||||
Unsafe: r.Unsafe,
|
Unsafe: r.Unsafe,
|
||||||
Handler: r.Handler,
|
Handler: r.Handler,
|
||||||
}
|
}
|
||||||
return tracer.Trace(done, th, ch, specs.ResLimit(r.TraceLimit))
|
return ptracer.Trace(done, th, ch, types.Limit(r.TraceLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
// build filter builds the libseccomp filter according to the allow, trace and show details
|
// build filter builds the libseccomp filter according to the allow, trace and show details
|
||||||
@ -51,9 +51,9 @@ func buildFilter(showDetails bool, allow, trace []string) (*libseccomp.ScmpFilte
|
|||||||
var defaultAction libseccomp.ScmpAction
|
var defaultAction libseccomp.ScmpAction
|
||||||
// if debug, allow all syscalls and output what was blocked
|
// if debug, allow all syscalls and output what was blocked
|
||||||
if showDetails {
|
if showDetails {
|
||||||
defaultAction = libseccomp.ActTrace.SetReturnCode(tracer.MsgDisallow)
|
defaultAction = libseccomp.ActTrace.SetReturnCode(ptracer.MsgDisallow)
|
||||||
} else {
|
} else {
|
||||||
defaultAction = libseccomp.ActKill
|
defaultAction = libseccomp.ActKill
|
||||||
}
|
}
|
||||||
return seccomp.BuildFilter(defaultAction, libseccomp.ActTrace.SetReturnCode(tracer.MsgHandle), allow, trace)
|
return seccomp.BuildFilter(defaultAction, libseccomp.ActTrace.SetReturnCode(ptracer.MsgHandle), allow, trace)
|
||||||
}
|
}
|
||||||
@ -1,14 +1,14 @@
|
|||||||
package runprogram
|
package ptrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunProgram defines the spec to run a program safely
|
// Runner defines the spec to run a program safely by ptracer
|
||||||
type RunProgram struct {
|
type Runner struct {
|
||||||
// argv and env for the child process
|
// argv and env for the child process
|
||||||
// work path set by setcwd (current working directory for child)
|
// work path set by setcwd (current working directory for child)
|
||||||
Args []string
|
Args []string
|
||||||
@ -25,7 +25,7 @@ type RunProgram struct {
|
|||||||
RLimits rlimit.RLimits
|
RLimits rlimit.RLimits
|
||||||
|
|
||||||
// Res limit enforced by tracer
|
// Res limit enforced by tracer
|
||||||
TraceLimit specs.ResLimit
|
TraceLimit types.Limit
|
||||||
|
|
||||||
// Allowed / Traced syscall names
|
// Allowed / Traced syscall names
|
||||||
// Notice: file access syscalls should be traced
|
// Notice: file access syscalls should be traced
|
||||||
8
runner/runner.go
Normal file
8
runner/runner.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package runner
|
||||||
|
|
||||||
|
import "github.com/criyle/go-sandbox/types"
|
||||||
|
|
||||||
|
// Runner interface defines method to start running
|
||||||
|
type Runner interface {
|
||||||
|
Start(<-chan struct{}) (<-chan types.Result, error)
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
package rununshared
|
package unshare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/mount"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/criyle/go-sandbox/pkg/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddBind is the additional bind mounts besides the default one
|
// AddBind is the additional bind mounts besides the default one
|
||||||
@ -1,15 +1,16 @@
|
|||||||
package rununshared
|
package unshare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
|
||||||
"github.com/criyle/go-sandbox/pkg/seccomp"
|
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
|
||||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||||
|
"github.com/criyle/go-sandbox/pkg/seccomp"
|
||||||
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -18,7 +19,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Start starts the unshared process
|
// Start starts the unshared process
|
||||||
func (r *RunUnshared) Start(done <-chan struct{}) (<-chan specs.TraceResult, error) {
|
func (r *Runner) Start(done <-chan struct{}) (<-chan types.Result, error) {
|
||||||
filter, err := seccomp.BuildFilter(libseccomp.ActKill, libseccomp.ActTrap, r.SyscallAllowed, []string{})
|
filter, err := seccomp.BuildFilter(libseccomp.ActKill, libseccomp.ActTrap, r.SyscallAllowed, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err)
|
println(err)
|
||||||
@ -51,7 +52,7 @@ func (r *RunUnshared) Start(done <-chan struct{}) (<-chan specs.TraceResult, err
|
|||||||
SyncFunc: r.SyncFunc,
|
SyncFunc: r.SyncFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make(chan specs.TraceResult, 1)
|
result := make(chan types.Result, 1)
|
||||||
start := make(chan struct{})
|
start := make(chan struct{})
|
||||||
finish := make(chan struct{})
|
finish := make(chan struct{})
|
||||||
|
|
||||||
@ -71,13 +72,13 @@ func (r *RunUnshared) Start(done <-chan struct{}) (<-chan specs.TraceResult, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trace tracks child processes
|
// Trace tracks child processes
|
||||||
func (r *RunUnshared) Trace(done <-chan struct{}, start chan<- struct{},
|
func (r *Runner) Trace(done <-chan struct{}, start chan<- struct{},
|
||||||
runner *forkexec.Runner) (result specs.TraceResult, err error) {
|
runner *forkexec.Runner) (result types.Result, err error) {
|
||||||
var (
|
var (
|
||||||
wstatus unix.WaitStatus // wait4 wait status
|
wstatus unix.WaitStatus // wait4 wait status
|
||||||
rusage unix.Rusage // wait4 rusage
|
rusage unix.Rusage // wait4 rusage
|
||||||
tle = false
|
tle = false
|
||||||
status = specs.TraceCodeNormal
|
status = types.StatusNormal
|
||||||
sTime = time.Now() // start time
|
sTime = time.Now() // start time
|
||||||
fTime time.Time // finish time for setup
|
fTime time.Time // finish time for setup
|
||||||
)
|
)
|
||||||
@ -86,7 +87,7 @@ func (r *RunUnshared) Trace(done <-chan struct{}, start chan<- struct{},
|
|||||||
pgid, err := runner.Start()
|
pgid, err := runner.Start()
|
||||||
r.println("Starts: ", pgid, err)
|
r.println("Starts: ", pgid, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.TraceStatus = specs.TraceCodeRE
|
result.Status = types.StatusRE
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,13 +107,13 @@ func (r *RunUnshared) Trace(done <-chan struct{}, start chan<- struct{},
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tle {
|
if tle {
|
||||||
err = specs.TraceCodeTLE
|
err = types.StatusTLE
|
||||||
}
|
}
|
||||||
// kill all tracee upon return
|
// kill all tracee upon return
|
||||||
killAll(pgid)
|
killAll(pgid)
|
||||||
collectZombie(pgid)
|
collectZombie(pgid)
|
||||||
result.SetUpTime = fTime.Sub(sTime).Nanoseconds()
|
result.SetUpTime = fTime.Sub(sTime)
|
||||||
result.RunningTime = time.Since(fTime).Nanoseconds()
|
result.RunningTime = time.Since(fTime)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fTime = time.Now()
|
fTime = time.Now()
|
||||||
@ -120,7 +121,7 @@ func (r *RunUnshared) Trace(done <-chan struct{}, start chan<- struct{},
|
|||||||
_, err := unix.Wait4(pgid, &wstatus, 0, &rusage)
|
_, err := unix.Wait4(pgid, &wstatus, 0, &rusage)
|
||||||
r.println("wait4: ", wstatus)
|
r.println("wait4: ", wstatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, specs.TraceCodeFatal
|
return result, types.StatusFatal
|
||||||
}
|
}
|
||||||
|
|
||||||
// update resource usage and check against limits
|
// update resource usage and check against limits
|
||||||
@ -129,37 +130,37 @@ func (r *RunUnshared) Trace(done <-chan struct{}, start chan<- struct{},
|
|||||||
|
|
||||||
// check tle / mle
|
// check tle / mle
|
||||||
if userTime > r.ResLimits.TimeLimit {
|
if userTime > r.ResLimits.TimeLimit {
|
||||||
status = specs.TraceCodeTLE
|
status = types.StatusTLE
|
||||||
}
|
}
|
||||||
if userMem > r.ResLimits.MemoryLimit {
|
if userMem > r.ResLimits.MemoryLimit {
|
||||||
status = specs.TraceCodeMLE
|
status = types.StatusMLE
|
||||||
}
|
}
|
||||||
result = specs.TraceResult{
|
result = types.Result{
|
||||||
UserTime: userTime,
|
Status: status,
|
||||||
UserMem: userMem,
|
UserTime: userTime,
|
||||||
TraceStatus: status,
|
UserMem: userMem,
|
||||||
}
|
}
|
||||||
if status != specs.TraceCodeNormal {
|
if status != types.StatusNormal {
|
||||||
return result, status
|
return result, status
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case wstatus.Exited():
|
case wstatus.Exited():
|
||||||
result.ExitCode = wstatus.ExitStatus()
|
result.ExitStatus = wstatus.ExitStatus()
|
||||||
return result, nil
|
return result, nil
|
||||||
case wstatus.Signaled():
|
case wstatus.Signaled():
|
||||||
sig := wstatus.Signal()
|
sig := wstatus.Signal()
|
||||||
switch sig {
|
switch sig {
|
||||||
case unix.SIGXCPU, unix.SIGKILL:
|
case unix.SIGXCPU, unix.SIGKILL:
|
||||||
status = specs.TraceCodeTLE
|
status = types.StatusTLE
|
||||||
case unix.SIGXFSZ:
|
case unix.SIGXFSZ:
|
||||||
status = specs.TraceCodeOLE
|
status = types.StatusOLE
|
||||||
case unix.SIGSYS:
|
case unix.SIGSYS:
|
||||||
status = specs.TraceCodeBan
|
status = types.StatusBan
|
||||||
default:
|
default:
|
||||||
status = specs.TraceCodeRE
|
status = types.StatusRE
|
||||||
}
|
}
|
||||||
result.TraceStatus = status
|
result.Status = status
|
||||||
return result, status
|
return result, status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +183,7 @@ func collectZombie(pgid int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunUnshared) println(v ...interface{}) {
|
func (r *Runner) println(v ...interface{}) {
|
||||||
if r.ShowDetails {
|
if r.ShowDetails {
|
||||||
fmt.Fprintln(os.Stderr, v...)
|
fmt.Fprintln(os.Stderr, v...)
|
||||||
}
|
}
|
||||||
@ -1,13 +1,13 @@
|
|||||||
package rununshared
|
package unshare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/criyle/go-sandbox/pkg/mount"
|
"github.com/criyle/go-sandbox/pkg/mount"
|
||||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||||
"github.com/criyle/go-sandbox/types/specs"
|
"github.com/criyle/go-sandbox/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunUnshared runs program in unshared namespaces
|
// Runner runs program in unshared namespaces
|
||||||
type RunUnshared struct {
|
type Runner struct {
|
||||||
// argv and env for the child process
|
// argv and env for the child process
|
||||||
Args []string
|
Args []string
|
||||||
Env []string
|
Env []string
|
||||||
@ -25,7 +25,7 @@ type RunUnshared struct {
|
|||||||
RLimits rlimit.RLimits
|
RLimits rlimit.RLimits
|
||||||
|
|
||||||
// Resource limit enforced by tracer
|
// Resource limit enforced by tracer
|
||||||
ResLimits specs.ResLimit
|
ResLimits types.Limit
|
||||||
|
|
||||||
// Allowed syscall names
|
// Allowed syscall names
|
||||||
SyscallAllowed []string
|
SyscallAllowed []string
|
||||||
@ -1,59 +0,0 @@
|
|||||||
package specs
|
|
||||||
|
|
||||||
// TraceCode is the error type
|
|
||||||
type TraceCode int
|
|
||||||
|
|
||||||
// Different end condtion
|
|
||||||
const (
|
|
||||||
TraceCodeNormal TraceCode = iota // 0
|
|
||||||
TraceCodeInvalid // 1
|
|
||||||
TraceCodeRE // 2
|
|
||||||
TraceCodeMLE // 3
|
|
||||||
TraceCodeTLE // 4
|
|
||||||
TraceCodeOLE // 5
|
|
||||||
TraceCodeBan // 6
|
|
||||||
TraceCodeFatal // 7
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t TraceCode) Error() string {
|
|
||||||
switch t {
|
|
||||||
case TraceCodeNormal:
|
|
||||||
return ""
|
|
||||||
case TraceCodeRE:
|
|
||||||
return "runtime error"
|
|
||||||
case TraceCodeTLE:
|
|
||||||
return "time limit exceeded"
|
|
||||||
case TraceCodeMLE:
|
|
||||||
return "memory limit exceeded"
|
|
||||||
case TraceCodeOLE:
|
|
||||||
return "output limit exceeded"
|
|
||||||
case TraceCodeBan:
|
|
||||||
return "syscall banned"
|
|
||||||
case TraceCodeFatal:
|
|
||||||
return "handle failed"
|
|
||||||
default:
|
|
||||||
return "invalid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TraceStat is the time usages in ns
|
|
||||||
type TraceStat struct {
|
|
||||||
SetUpTime int64
|
|
||||||
RunningTime int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// TraceResult is the result returned by strat trace
|
|
||||||
type TraceResult struct {
|
|
||||||
UserTime uint64 // used user CPU time (in ms)
|
|
||||||
UserMem uint64 // used user memory (in kb)
|
|
||||||
ExitCode int // exit code
|
|
||||||
TraceStatus TraceCode // the final status for the process
|
|
||||||
TraceStat // collects time for the process
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResLimit represents the resource limit for traced process
|
|
||||||
type ResLimit struct {
|
|
||||||
TimeLimit uint64 // user CPU time limit (in ms)
|
|
||||||
RealTimeLimit uint64 // sig_kill will force the process to exit after this limit (in ms)
|
|
||||||
MemoryLimit uint64 // user memory limit (in kB)
|
|
||||||
}
|
|
||||||
41
types/status.go
Normal file
41
types/status.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
// Status is the result Status
|
||||||
|
type Status int
|
||||||
|
|
||||||
|
// Different end condtion
|
||||||
|
const (
|
||||||
|
StatusNormal Status = iota // 0
|
||||||
|
StatusInvalid // 1
|
||||||
|
StatusRE // 2
|
||||||
|
StatusMLE // 3
|
||||||
|
StatusTLE // 4
|
||||||
|
StatusOLE // 5
|
||||||
|
StatusBan // 6
|
||||||
|
StatusFatal // 7
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
statusString = []string{
|
||||||
|
"",
|
||||||
|
"invalid",
|
||||||
|
"runtime error",
|
||||||
|
"memory limit exceeded",
|
||||||
|
"time limit exceeded",
|
||||||
|
"output limit exceeded",
|
||||||
|
"syscall banned",
|
||||||
|
"runner failed",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Status) String() string {
|
||||||
|
i := int(t)
|
||||||
|
if i >= 0 && i < len(statusString) {
|
||||||
|
return statusString[i]
|
||||||
|
}
|
||||||
|
return "invalid"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Status) Error() string {
|
||||||
|
return t.String()
|
||||||
|
}
|
||||||
24
types/types.go
Normal file
24
types/types.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Result is the result returned by strat trace
|
||||||
|
type Result struct {
|
||||||
|
Status // the final status for the process
|
||||||
|
ExitStatus int // exit Status
|
||||||
|
UserTime uint64 // used user CPU time (in ms)
|
||||||
|
UserMem uint64 // used user memory (in kb)
|
||||||
|
Stat // collects time usage for the runner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat is the time usages in ns
|
||||||
|
type Stat struct {
|
||||||
|
SetUpTime time.Duration
|
||||||
|
RunningTime time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit represents the resource limit for traced process
|
||||||
|
type Limit struct {
|
||||||
|
TimeLimit uint64 // user CPU time limit (in ms)
|
||||||
|
MemoryLimit uint64 // user memory limit (in kB)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user