mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
add debug information
This commit is contained in:
parent
976f33ead5
commit
05d7ca1edc
@ -33,6 +33,7 @@ func main() {
|
|||||||
t := tracer.NewTracer()
|
t := tracer.NewTracer()
|
||||||
t.Args = os.Args[1:]
|
t.Args = os.Args[1:]
|
||||||
t.TraceHandle = handle
|
t.TraceHandle = handle
|
||||||
|
//t.Debug = true
|
||||||
rt, err := t.StartTrace()
|
rt, err := t.StartTrace()
|
||||||
log.Println(rt, err)
|
log.Println(rt, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,7 @@ const (
|
|||||||
TraceCodeMLE
|
TraceCodeMLE
|
||||||
TraceCodeOLE
|
TraceCodeOLE
|
||||||
TraceCodeBan
|
TraceCodeBan
|
||||||
|
TraceCodeRE
|
||||||
TraceCodeFatal
|
TraceCodeFatal
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,6 +70,8 @@ func (t TraceCode) Error() string {
|
|||||||
return "output limit exceeded"
|
return "output limit exceeded"
|
||||||
case TraceCodeBan:
|
case TraceCodeBan:
|
||||||
return "syscall banned"
|
return "syscall banned"
|
||||||
|
case TraceCodeRE:
|
||||||
|
return "runtime error"
|
||||||
case TraceCodeFatal:
|
case TraceCodeFatal:
|
||||||
return "handle failed"
|
return "handle failed"
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -2,6 +2,11 @@ package tracer
|
|||||||
|
|
||||||
import libseccomp "github.com/seccomp/libseccomp-golang"
|
import libseccomp "github.com/seccomp/libseccomp-golang"
|
||||||
|
|
||||||
|
const (
|
||||||
|
msgDisallow int16 = iota + 1
|
||||||
|
msgHandle
|
||||||
|
)
|
||||||
|
|
||||||
func addFilterAction(filter *libseccomp.ScmpFilter, name string, action libseccomp.ScmpAction) error {
|
func addFilterAction(filter *libseccomp.ScmpFilter, name string, action libseccomp.ScmpAction) error {
|
||||||
syscallID, err := libseccomp.GetSyscallFromName(name)
|
syscallID, err := libseccomp.GetSyscallFromName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -16,10 +21,10 @@ func addFilterAction(filter *libseccomp.ScmpFilter, name string, action libsecco
|
|||||||
|
|
||||||
func (r *Tracer) buildFilter() (*libseccomp.ScmpFilter, error) {
|
func (r *Tracer) buildFilter() (*libseccomp.ScmpFilter, error) {
|
||||||
// make filter
|
// make filter
|
||||||
//filter, err := libseccomp.NewFilter(libseccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)))
|
|
||||||
var defaultAction libseccomp.ScmpAction
|
var defaultAction libseccomp.ScmpAction
|
||||||
|
// if debug, allow all syscalls and output what was blocked
|
||||||
if r.Debug {
|
if r.Debug {
|
||||||
defaultAction = libseccomp.ActTrace.SetReturnCode(100)
|
defaultAction = libseccomp.ActTrace.SetReturnCode(msgDisallow)
|
||||||
} else {
|
} else {
|
||||||
defaultAction = libseccomp.ActKill
|
defaultAction = libseccomp.ActKill
|
||||||
}
|
}
|
||||||
@ -30,15 +35,13 @@ func (r *Tracer) buildFilter() (*libseccomp.ScmpFilter, error) {
|
|||||||
|
|
||||||
for _, s := range r.Allow {
|
for _, s := range r.Allow {
|
||||||
err := addFilterAction(filter, s, libseccomp.ActAllow)
|
err := addFilterAction(filter, s, libseccomp.ActAllow)
|
||||||
//log.Println("[+] allow syscall: ", s)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range r.Trace {
|
for _, s := range r.Trace {
|
||||||
err := addFilterAction(filter, s, libseccomp.ActTrace.SetReturnCode(10))
|
err := addFilterAction(filter, s, libseccomp.ActTrace.SetReturnCode(msgHandle))
|
||||||
//log.Println("[+] trace syscall: ", s)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,11 +41,11 @@ func (r *Tracer) StartTrace() (result *TraceResult, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Strart trace pid: ", pid)
|
r.println("Strart trace pid: ", pid)
|
||||||
|
|
||||||
// store all tracee process pid existence
|
// store all tracee process pid existence
|
||||||
pids := make(map[int]bool)
|
pids := make(map[int]bool)
|
||||||
//rootPid := pid
|
rootPid := pid
|
||||||
|
|
||||||
// kill all tracee according to pids
|
// kill all tracee according to pids
|
||||||
killAll := func() {
|
killAll := func() {
|
||||||
@ -57,6 +57,13 @@ func (r *Tracer) StartTrace() (result *TraceResult, err error) {
|
|||||||
// kill all tracee upon return
|
// kill all tracee upon return
|
||||||
defer func() {
|
defer func() {
|
||||||
killAll()
|
killAll()
|
||||||
|
// collect zombies
|
||||||
|
for {
|
||||||
|
var wstatus unix.WaitStatus
|
||||||
|
if _, err := unix.Wait4(-1, &wstatus, unix.WALL|unix.WNOWAIT, nil); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set real time limit, kill process after it
|
// Set real time limit, kill process after it
|
||||||
@ -70,15 +77,19 @@ func (r *Tracer) StartTrace() (result *TraceResult, err error) {
|
|||||||
// Trace result
|
// Trace result
|
||||||
var rt TraceResult
|
var rt TraceResult
|
||||||
|
|
||||||
|
// If forked tracee execved, this syscall should not be handled
|
||||||
|
execved := false
|
||||||
|
|
||||||
// trace unixs
|
// trace unixs
|
||||||
for {
|
for {
|
||||||
|
// Wait4 return values
|
||||||
var wstatus unix.WaitStatus
|
var wstatus unix.WaitStatus
|
||||||
var rusage unix.Rusage
|
var rusage unix.Rusage
|
||||||
|
|
||||||
// Wait for all child
|
// Wait for all child
|
||||||
pid, err := unix.Wait4(-1, &wstatus, unix.WALL, &rusage)
|
pid, err := unix.Wait4(-1, &wstatus, unix.WALL, &rusage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Wait4 fatal: ", err)
|
r.println("Wait4 failed: ", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Set option if the process is newly forked
|
// Set option if the process is newly forked
|
||||||
@ -90,6 +101,7 @@ func (r *Tracer) StartTrace() (result *TraceResult, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update resource usage
|
// Update resource usage
|
||||||
rt.UserTime = uint64(rusage.Utime.Sec*1e3 + rusage.Utime.Usec/1e3) // ms
|
rt.UserTime = uint64(rusage.Utime.Sec*1e3 + rusage.Utime.Usec/1e3) // ms
|
||||||
rt.UserMem = uint64(rusage.Maxrss)
|
rt.UserMem = uint64(rusage.Maxrss)
|
||||||
@ -102,79 +114,89 @@ func (r *Tracer) StartTrace() (result *TraceResult, err error) {
|
|||||||
return nil, TraceCodeMLE
|
return nil, TraceCodeMLE
|
||||||
}
|
}
|
||||||
|
|
||||||
if wstatus.Exited() {
|
// check process status
|
||||||
|
switch {
|
||||||
|
case wstatus.Exited():
|
||||||
delete(pids, pid)
|
delete(pids, pid)
|
||||||
log.Println("Exited", pid, wstatus.ExitStatus())
|
r.println("Exited", pid, wstatus.ExitStatus())
|
||||||
break
|
if pid == rootPid {
|
||||||
}
|
if execved {
|
||||||
if wstatus.Signaled() {
|
break
|
||||||
|
}
|
||||||
|
return nil, TraceCodeFatal
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
|
case wstatus.Signaled():
|
||||||
sig := wstatus.Signal()
|
sig := wstatus.Signal()
|
||||||
log.Println("Signal", sig)
|
r.println("Signal", sig)
|
||||||
switch sig {
|
if pid == rootPid {
|
||||||
case unix.SIGKILL:
|
switch sig {
|
||||||
delete(pids, pid)
|
case unix.SIGXCPU:
|
||||||
log.Println("Killed")
|
return nil, TraceCodeTLE
|
||||||
continue
|
case unix.SIGXFSZ:
|
||||||
case unix.SIGSYS:
|
return nil, TraceCodeOLE
|
||||||
delete(pids, pid)
|
case unix.SIGSYS:
|
||||||
log.Println("Blocked syscall")
|
return nil, TraceCodeBan
|
||||||
default:
|
default:
|
||||||
|
return nil, TraceCodeRE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
delete(pids, pid)
|
delete(pids, pid)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if wstatus.Stopped() {
|
case wstatus.Stopped():
|
||||||
if wstatus.StopSignal() == unix.SIGTRAP {
|
if stopSig := wstatus.StopSignal(); stopSig == unix.SIGTRAP {
|
||||||
switch cause := wstatus.TrapCause(); cause {
|
switch cause := wstatus.TrapCause(); cause {
|
||||||
case unix.PTRACE_EVENT_SECCOMP:
|
case unix.PTRACE_EVENT_SECCOMP:
|
||||||
log.Println("Seccomp Traced")
|
if execved {
|
||||||
_, err := unix.PtraceGetEventMsg(pid)
|
// give the customized handle for syscall
|
||||||
if err != nil {
|
act, err := r.handleTrap(pid)
|
||||||
log.Fatalln(err)
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// give the customized handle for syscall
|
switch act {
|
||||||
act, err := r.handleTrap(pid)
|
case TraceBan:
|
||||||
if err != nil {
|
// TODO: action according to handler soft ban
|
||||||
return nil, err
|
case TraceKill:
|
||||||
}
|
return nil, TraceCodeBan
|
||||||
|
}
|
||||||
switch act {
|
|
||||||
case TraceAllow:
|
|
||||||
// do nothing
|
|
||||||
case TraceBan:
|
|
||||||
// TODO: action according to handler soft ban
|
|
||||||
case TraceKill:
|
|
||||||
killAll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case unix.PTRACE_EVENT_CLONE:
|
case unix.PTRACE_EVENT_CLONE:
|
||||||
log.Println("Ptrace stop clone")
|
r.println("Ptrace stop clone")
|
||||||
|
|
||||||
case unix.PTRACE_EVENT_VFORK:
|
case unix.PTRACE_EVENT_VFORK:
|
||||||
log.Println("Ptrace stop vfork")
|
r.println("Ptrace stop vfork")
|
||||||
|
|
||||||
case unix.PTRACE_EVENT_FORK:
|
case unix.PTRACE_EVENT_FORK:
|
||||||
log.Println("Ptrace stop fork")
|
r.println("Ptrace stop fork")
|
||||||
|
|
||||||
case unix.PTRACE_EVENT_EXEC:
|
case unix.PTRACE_EVENT_EXEC:
|
||||||
log.Println("Ptrace stop exec")
|
// forked tracee have successfully called execve
|
||||||
|
execved = true
|
||||||
|
r.println("Ptrace stop exec")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Println("Ptrace trap cause: ", cause, wstatus)
|
r.println("Unexpected ptrace trap cause: ", cause)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Println("Ptrace stop signal: ", wstatus.StopSignal())
|
r.println("Unexpected ptrace stop signal: ", stopSig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue execution
|
// continue execution
|
||||||
unix.PtraceCont(pid, 0)
|
unix.PtraceCont(pid, 0)
|
||||||
}
|
}
|
||||||
// TODO: finish resource consumption result
|
|
||||||
return &rt, nil
|
return &rt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// println only print when debug flag is on
|
||||||
|
func (r *Tracer) println(v ...interface{}) {
|
||||||
|
if r.Debug {
|
||||||
|
log.Println(v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Tracer) verify() {
|
func (r *Tracer) verify() {
|
||||||
if r.RealTimeLimit < r.TimeLimit {
|
if r.RealTimeLimit < r.TimeLimit {
|
||||||
r.RealTimeLimit = r.TimeLimit + 2
|
r.RealTimeLimit = r.TimeLimit + 2
|
||||||
@ -196,14 +218,37 @@ func (r *Tracer) verify() {
|
|||||||
r.Allow = allow
|
r.Allow = allow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleTrap handles the seccomp trap including the custom handle
|
||||||
func (r *Tracer) handleTrap(pid int) (TraceAction, error) {
|
func (r *Tracer) handleTrap(pid int) (TraceAction, error) {
|
||||||
if r.TraceHandle != nil {
|
r.println("Seccomp Traced")
|
||||||
context, err := getTrapContext(pid)
|
msg, err := unix.PtraceGetEventMsg(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return TraceKill, err
|
r.println(err)
|
||||||
}
|
|
||||||
return r.TraceHandle(context), nil
|
|
||||||
}
|
}
|
||||||
|
switch int16(msg) {
|
||||||
|
case msgDisallow:
|
||||||
|
ctx, err := getTrapContext(pid)
|
||||||
|
if err != nil {
|
||||||
|
r.println(err)
|
||||||
|
} else {
|
||||||
|
syscallNo := ctx.SyscallNo()
|
||||||
|
syscallName, err := libseccomp.ScmpSyscall(syscallNo).GetName()
|
||||||
|
r.println("disallowed syscall: ", syscallNo, syscallName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case msgHandle:
|
||||||
|
if r.TraceHandle != nil {
|
||||||
|
ctx, err := getTrapContext(pid)
|
||||||
|
if err != nil {
|
||||||
|
return TraceKill, err
|
||||||
|
}
|
||||||
|
return r.TraceHandle(ctx), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
r.println("unknown message: ", msg)
|
||||||
|
}
|
||||||
|
|
||||||
return TraceAllow, nil
|
return TraceAllow, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user