func (t *tracerImpl) Run() (err error) { if t.cmd.SysProcAttr == nil { t.cmd.SysProcAttr = &syscall.SysProcAttr{Ptrace: true} } else { t.cmd.SysProcAttr.Ptrace = true } runtime.LockOSThread() if err = t.cmd.Start(); err != nil { return } var waitStatus syscall.WaitStatus if _, err = syscall.Wait4(t.cmd.Process.Pid, &waitStatus, 0, nil); err != nil { return } if waitStatus.Exited() { return } // Set options to detect our syscalls if err = syscall.PtraceSetOptions(t.cmd.Process.Pid, syscall.PTRACE_O_TRACESYSGOOD); err != nil { return } var regsEntry, regsExit syscall.PtraceRegs // Get first syscall if err = syscall.PtraceGetRegs(t.cmd.Process.Pid, ®sEntry); err != nil { return } var exited bool for { if exited, err = wait_for_syscall(t.cmd.Process.Pid); exited || err != nil { return } // Get syscall info if err = syscall.PtraceGetRegs(t.cmd.Process.Pid, ®sEntry); err != nil { return } // Enter syscall t.callback(regsEntry, false) if exited, err = wait_for_syscall(t.cmd.Process.Pid); exited || err != nil { return } // Get syscall returned value if err = syscall.PtraceGetRegs(t.cmd.Process.Pid, ®sExit); err != nil { return } t.callback(regsExit, true) } }
func read_ptrace_events(args []string) (*exec.Cmd, func() *syscall.PtraceRegs) { cmd := exec.Command(args[0], args[1:]...) cmd.SysProcAttr = &syscall.SysProcAttr{Ptrace: true} cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Start() if err != nil { panic(err) } _, err = cmd.Process.Wait() if err != nil { panic(err) } child := cmd.Process.Pid err = syscall.PtraceSetOptions(child, syscall.PTRACE_O_TRACESYSGOOD) if err != nil { panic(err) } var regs syscall.PtraceRegs return cmd, func() *syscall.PtraceRegs { err = syscall.PtraceSyscall(child, 0) if err != nil { panic(err) } state, err := cmd.Process.Wait() if err != nil { panic(err) } waitstatus, ok := state.Sys().(syscall.WaitStatus) if !ok { panic(err) } if waitstatus.Exited() { // Process quit return nil } if !waitstatus.Stopped() { panic("Not handled: process isn't sigstopped!") } sig := waitstatus.StopSignal() if sig&0x80 == 0 { // Not something we're build to handle // High bit should be set for syscalls because of PTRACE_O_SYSGOOD return nil } err = syscall.PtraceGetRegs(child, ®s) if err != nil { panic(err) } return ®s } }
func handleSyscall(spid int) *resultPack { var regs syscall.PtraceRegs if err := syscall.PtraceGetRegs(spid, ®s); err != nil { poePanic(err, "getreg failed") } switch regs.Orig_rax { case syscall.SYS_KILL: goto allow default: goto kill } kill: if err := syscall.Kill(spid, syscall.SIGKILL); err != nil { poePanic(err, "failed to kill process which called prohibited syscall") } else if name, err := ResolveSeccompSyscallName(regs.Orig_rax); err != nil { poePanic(err, "seccomp_syscall_resolve_num_arch() failed") } else { return &resultPack{POE_SIGNALED, -1, fmt.Sprintf("System call %s is blocked", name)} } allow: if err := syscall.PtraceCont(spid, 0); err != nil { poePanic(err, "PTRACE_CONT failed") } return nil }
// trace thread calls this func (t *thread) syscallStopped() { var err error if t.state == NORMAL { if err = syscall.PtraceGetRegs(t.tid, &t.callRegs); err != nil { t.logf("GetRegs failed, pid=%d, err=%v", t.tid, err) } t.state = INSYSCALL return } t.state = NORMAL if err = syscall.PtraceGetRegs(t.tid, &t.resultRegs); err != nil { t.logf("GetRegs failed, pid=%d, err=%v", t.tid, err) return } if t.process == nil { t.logf("Got syscall, but don't know parent process!") return } switch t.callRegs.Orig_rax { case ACCEPT, ACCEPT4: t.handleAccept(&t.callRegs, &t.resultRegs) case CLOSE: t.handleClose(&t.callRegs, &t.resultRegs) case CONNECT: t.handleConnect(&t.callRegs, &t.resultRegs) case READ, WRITE, RECVFROM, SENDTO: t.handleIO(&t.callRegs, &t.resultRegs) // we can ignore these syscalls case SETROBUSTLIST, GETID, MMAP, MPROTECT, MADVISE, SOCKET, CLONE, STAT, SELECT: return case OPEN, FUTEX, SHUTDOWN, GETTIMEOFDAY, MUNMAP: return default: t.logf("syscall(%d)", t.callRegs.Orig_rax) } }
// GetRegisters is a wrapper for ptrace(PTRACE_GETREGS) func (p *Process) GetRegisters() (*RegisterState, error) { registers := &RegisterState{} err := syscall.PtraceGetRegs(p.Pid, ®isters.PtraceRegs) if err != nil { return nil, err } return registers, nil }
func (t *Tracer) GetRegs() (*syscall.PtraceRegs, error) { regs := &syscall.PtraceRegs{} err := syscall.PtraceGetRegs(t.Process.Pid, regs) if err != nil { return nil, err } return regs, nil }
func main() { log.SetFlags(0) log.SetPrefix("ministrace: ") flag.Usage = usage flag.Parse() if flag.NArg() < 1 { usage() } args := flag.Args() exec, err := exec.LookPath(args[0]) if err == nil { args[0] = exec } proc, err := os.StartProcess(args[0], args, &os.ProcAttr{ Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, Env: os.Environ(), Sys: &syscall.SysProcAttr{ Ptrace: true, Pdeathsig: syscall.SIGCHLD, }, }) ck(err) syscall.PtraceSetOptions(proc.Pid, syscall.PTRACE_O_TRACESYSGOOD) for { if waitSyscall(proc) { break } var regs syscall.PtraceRegs syscall.PtraceGetRegs(proc.Pid, ®s) fmt.Printf("%s = ", xsys(regs.Orig_rax)) if waitSyscall(proc) { break } syscall.PtraceGetRegs(proc.Pid, ®s) fmt.Printf("%#x\n", regs.Rax) } }
func (t *Task) Tracer() error { runtime.LockOSThread() if err := syscall.PtraceAttach(t.pid); err != nil { return err } defer func() { // syscall.PtraceCont(t.pid, 0) syscall.PtraceDetach(t.pid) }() regsout := new(syscall.PtraceRegs) status := new(syscall.WaitStatus) var timer *time.Timer refresh := func() { t.RefreshFiles(); timer.Stop(); timer = nil } for { if _, err := syscall.Wait4(t.pid, status, 0, nil); err != nil { log.Println("wait failed", err) return err } if status.Exited() { log.Println("exited") return nil } if err := syscall.PtraceGetRegs(t.pid, regsout); err != nil { log.Println("getregs failed", err) return err } // linux_amd64 if regsout.Orig_rax == syscall.SYS_OPEN { if timer != nil { if timer.Stop() == false { log.Println("cannot stop the timer") } } timer = time.AfterFunc(1e9, refresh) // Wait until open()s "settle". } if err := PtraceSyscall(t.pid); err != nil { log.Println("PtraceSyscall failed", err) return err } } panic("can't reach") }
// traceSyscalls executes a command exec with the arguments args and calls // the function callback for every syscall executed by the command's process. func traceSyscalls(proc *os.Process, state func(pid int, regs *syscall.PtraceRegs)) { // flags used with ptrace const flags = syscall.PTRACE_O_TRACEVFORK | syscall.PTRACE_O_TRACEFORK | syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEEXEC | syscall.PTRACE_O_TRACESYSGOOD if err := syscall.PtraceSetOptions(proc.Pid, flags); err != nil { log.Fatal("PtrageSetOptions", err) } if err := syscall.PtraceSyscall(proc.Pid, 0); err != nil { log.Fatalf("PtraceCont: %v", err) } for { signal := 0 pid, status, err := wait(-1) if err != nil { break } if status.Exited() || status.Signaled() { continue } if status.Stopped() { switch waitEvent(status) { case EventFork, EventVFork, EventClone, EventExec: if cpid, err := syscall.PtraceGetEventMsg(pid); err == nil { log.Printf("process %d created new process %d", pid, cpid) } default: if stopSignal := status.StopSignal(); stopSignal&0x7f != syscall.SIGTRAP { signal = int(stopSignal) } var regs syscall.PtraceRegs if syscall.PtraceGetRegs(pid, ®s) == nil { state(pid, ®s) } } } syscall.PtraceSyscall(pid, signal) } }
func (pt *Ptrace) Regs() (*syscall.PtraceRegs, error) { regs := &syscall.PtraceRegs{} err := syscall.PtraceGetRegs(pt.Pid(), regs) return regs, err }
func run() { // If the debugger itself is multi-threaded, ptrace calls must come from // the same thread that originally attached to the remote thread. runtime.LockOSThread() f, err := os.Open(exeFilename) if err != nil { log.Printf(`%q not found. Did you run "go build ." in that directory?`, exeFilename) log.Fatalf("Open: %v", err) } defer f.Close() dwarfData, err := loadDwarfData(f) if err != nil { log.Fatalf("loadDwarfData: %v", err) } proc, err := os.StartProcess(exeFilename, []string{exeFilename}, &os.ProcAttr{ Files: []*os.File{ os.Stdin, os.Stdout, os.Stderr, }, Sys: &syscall.SysProcAttr{ Ptrace: true, Pdeathsig: syscall.SIGKILL, }, }) if err != nil { log.Fatalf("StartProcess: %v", err) } fmt.Printf("\tproc.Pid=%d\n", proc.Pid) _, status, err := wait(proc.Pid) if err != nil { log.Fatalf("wait: %v", err) } if status != 0x00057f { // 0x05=SIGTRAP, 0x7f=stopped. log.Fatalf("status: got %#x, want %#x", status, 0x57f) } err = syscall.PtraceSetOptions(proc.Pid, syscall.PTRACE_O_TRACECLONE|syscall.PTRACE_O_TRACEEXIT) if err != nil { log.Fatalf("PtraceSetOptions: %v", err) } addr, err := lookupSym(dwarfData, "fmt.Printf") if err != nil { log.Fatalf("lookupSym: %v", err) } fmt.Printf("\tfmt.Printf=%#x\n", addr) var buf [1]byte if err := peek(proc.Pid, addr, buf[:1]); err != nil { log.Fatalf("peek: %v", err) } breakpoints := map[uint64]breakpoint{ addr: {pc: addr, origInstr: buf[0]}, } buf[0] = breakpointInstr if err := poke(proc.Pid, addr, buf[:1]); err != nil { log.Fatalf("poke: %v", err) } err = syscall.PtraceCont(proc.Pid, 0) if err != nil { log.Fatalf("PtraceCont: %v", err) } for { pid, status, err := wait(-1) if err != nil { log.Fatalf("wait: %v", err) } switch status { case 0x00057f: // 0x05=SIGTRAP, 0x7f=stopped. regs := syscall.PtraceRegs{} if err := syscall.PtraceGetRegs(pid, ®s); err != nil { log.Fatalf("PtraceGetRegs: %v", err) } regs.Rip -= breakpointInstrLen if err := syscall.PtraceSetRegs(pid, ®s); err != nil { log.Fatalf("PtraceSetRegs: %v", err) } bp, ok := breakpoints[regs.Rip] if !ok { log.Fatalf("no breakpoint for address %#x\n", regs.Rip) } buf[0] = bp.origInstr if err := poke(pid, addr, buf[:1]); err != nil { log.Fatalf("poke: %v", err) } fmt.Printf("\thit breakpoint at %#x, pid=%5d\n", regs.Rip, pid) if err := syscall.PtraceSingleStep(pid); err != nil { log.Fatalf("PtraceSingleStep: %v", err) } _, status, err := wait(pid) if err != nil { log.Fatalf("wait: %v", err) } if status != 0x00057f { log.Fatalf("PtraceSingleStep: unexpected status %#x\n", status) } buf[0] = breakpointInstr if err := poke(pid, addr, buf[:1]); err != nil { log.Fatalf("poke: %v", err) } case 0x00137f: // 0x13=SIGSTOP, 0x7f=stopped. // No-op. case 0x03057f: // 0x05=SIGTRAP, 0x7f=stopped, 0x03=PTRACE_EVENT_CLONE. msg, err := syscall.PtraceGetEventMsg(pid) if err != nil { log.Fatalf("PtraceGetEventMsg: %v", err) } fmt.Printf("\tclone: new pid=%d\n", msg) default: log.Fatalf("unexpected status %#x\n", status) } err = syscall.PtraceCont(pid, 0) if err != nil { log.Fatalf("PtraceCont: %v", err) } } }
func (s *Server) ptraceGetRegs(pid int, regsout *syscall.PtraceRegs) (err error) { s.fc <- func() error { return syscall.PtraceGetRegs(pid, regsout) } return <-s.ec }
func Tracer() { var train = false var cmd string var cmdArgs []string var p *oz.Profile var noprofile = flag.Bool("train", false, "Training mode") var debug = flag.Bool("debug", false, "Debug") var appendpolicy = flag.Bool("append", false, "Append to existing policy if exists") var trainingoutput = flag.String("output", "", "Training policy output file") flag.Parse() var args = flag.Args() if *noprofile == true { train = true // TODO: remove hardcoded path and read prefix from /etc/oz.conf cmd = "/usr/bin/oz-seccomp" cmdArgs = append([]string{"-mode=train"}, args...) } else { p = new(oz.Profile) if err := json.NewDecoder(os.Stdin).Decode(&p); err != nil { log.Error("unable to decode profile data: %v", err) os.Exit(1) } if p.Seccomp.Mode == oz.PROFILE_SECCOMP_TRAIN { train = true } *debug = p.Seccomp.Debug cmd = args[0] cmdArgs = args[1:] } var cpid = 0 done := false log.Info("Tracer running command (%v) arguments (%v)\n", cmd, cmdArgs) c := exec.Command(cmd) c.SysProcAttr = &syscall.SysProcAttr{Ptrace: true} c.Env = os.Environ() c.Args = append(c.Args, cmdArgs...) if *noprofile == false { pi, err := c.StdinPipe() if err != nil { fmt.Errorf("error creating stdin pipe for tracer process: %v", err) os.Exit(1) } jdata, err := json.Marshal(p) if err != nil { fmt.Errorf("Unable to marshal seccomp state: %+v", err) os.Exit(1) } io.Copy(pi, bytes.NewBuffer(jdata)) pi.Close() } children := make(map[int]bool) renderFunctions := getRenderingFunctions() trainingset := make(map[int]bool) trainingargs := make(map[int]map[int][]uint) if err := c.Start(); err == nil { cpid = c.Process.Pid children[c.Process.Pid] = true var s syscall.WaitStatus pid, err := syscall.Wait4(-1, &s, syscall.WALL, nil) children[pid] = true if err != nil { log.Error("Error (wait4) err:%v pid:%i", err, pid) } log.Info("Tracing child pid: %v\n", pid) for done == false { pflags := unix.PTRACE_O_TRACESECCOMP pflags |= unix.PTRACE_O_TRACEFORK pflags |= unix.PTRACE_O_TRACEVFORK pflags |= unix.PTRACE_O_TRACECLONE pflags |= C.PTRACE_O_EXITKILL syscall.PtraceSetOptions(pid, pflags) syscall.PtraceCont(pid, 0) pid, err = syscall.Wait4(-1, &s, syscall.WALL, nil) if err != nil { log.Error("Error (wait4) err:%v pid:%i children:%v\n", err, pid, children) done = true continue } children[pid] = true if s.Exited() == true { delete(children, pid) log.Info("Child pid %v finished.\n", pid) if len(children) == 0 { done = true } continue } if s.Signaled() == true { log.Error("Pid signaled, pid: %v signal: %v", pid, s) delete(children, pid) continue } switch uint32(s) >> 8 { case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_SECCOMP << 8): var regs syscall.PtraceRegs err = syscall.PtraceGetRegs(pid, ®s) if err != nil { log.Error("Error (ptrace): %v", err) } systemcall, err := syscallByNum(getSyscallNumber(regs)) if err != nil { log.Error("Error: %v", err) continue } /* Render the system call invocation */ r := getSyscallRegisterArgs(regs) call := "" if train == true { trainingset[getSyscallNumber(regs)] = true if systemcall.captureArgs != nil { for c, i := range systemcall.captureArgs { if i == 1 { if trainingargs[getSyscallNumber(regs)] == nil { trainingargs[getSyscallNumber(regs)] = make(map[int][]uint) } if contains(trainingargs[getSyscallNumber(regs)][c], uint(r[c])) == false { trainingargs[getSyscallNumber(regs)][c] = append(trainingargs[getSyscallNumber(regs)][c], uint(r[c])) } } } } } if f, ok := renderFunctions[getSyscallNumber(regs)]; ok { call, err = f(pid, r) if err != nil { log.Info("%v", err) continue } if *debug == true { call += "\n " + renderSyscallBasic(pid, systemcall, regs) } } else { call = renderSyscallBasic(pid, systemcall, regs) } log.Info("seccomp hit on sandbox pid %v (%v) syscall %v (%v):\n %s", pid, getProcessCmdLine(pid), systemcall.name, systemcall.num, call) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXIT << 8): if *debug == true { log.Error("Ptrace exit event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } delete(children, pid) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_CLONE << 8): newpid, err := syscall.PtraceGetEventMsg(pid) if err != nil { log.Error("PTrace event message retrieval failed: %v", err) } children[int(newpid)] = true if *debug == true { log.Error("Ptrace clone event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_FORK << 8): if *debug == true { log.Error("PTrace fork event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } newpid, err := syscall.PtraceGetEventMsg(pid) if err != nil { log.Error("PTrace event message retrieval failed: %v", err) } children[int(newpid)] = true continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK << 8): if *debug == true { log.Error("Ptrace vfork event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } newpid, err := syscall.PtraceGetEventMsg(pid) if err != nil { log.Error("PTrace event message retrieval failed: %v", err) } children[int(newpid)] = true continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK_DONE << 8): if *debug == true { log.Error("Ptrace vfork done event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } newpid, err := syscall.PtraceGetEventMsg(pid) if err != nil { log.Error("PTrace event message retrieval failed: %v", err) } children[int(newpid)] = true continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXEC << 8): if *debug == true { log.Error("Ptrace exec event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_STOP << 8): if *debug == true { log.Error("Ptrace stop event detected pid %v (%s)", pid, getProcessCmdLine(pid)) } continue case uint32(unix.SIGTRAP): if *debug == true { log.Error("SIGTRAP detected in pid %v (%s)", pid, getProcessCmdLine(pid)) } continue case uint32(unix.SIGCHLD): if *debug == true { log.Error("SIGCHLD detected pid %v (%s)", pid, getProcessCmdLine(pid)) } continue case uint32(unix.SIGSTOP): if *debug == true { log.Error("SIGSTOP detected pid %v (%s)", pid, getProcessCmdLine(pid)) } continue case uint32(unix.SIGSEGV): if *debug == true { log.Error("SIGSEGV detected pid %v (%s)", pid, getProcessCmdLine(pid)) } err = syscall.Kill(pid, 9) if err != nil { log.Error("kill: %v", err) os.Exit(1) } delete(children, pid) continue default: y := s.StopSignal() if *debug == true { log.Error("Child stopped for unknown reasons pid %v status %v signal %i (%s)", pid, s, y, getProcessCmdLine(pid)) } continue } } if train == true { var u *user.User var e error u, e = user.Current() var resolvedpath = "" if e != nil { log.Error("user.Current(): %v", e) } if *trainingoutput != "" { resolvedpath = *trainingoutput } else { if *noprofile == false { resolvedpath, e = fs.ResolvePathNoGlob(p.Seccomp.TrainOutput, u) if e != nil { log.Error("resolveVars(): %v", e) } } else { s := fmt.Sprintf("${HOME}/%s-%d.seccomp", fname(os.Args[2]), cpid) resolvedpath, e = fs.ResolvePathNoGlob(s, u) } } policyout := "execve:1\n" for call := range trainingset { done := false for c := range trainingargs { if c == call { for a, v := range trainingargs[c] { sc, _ := syscallByNum(call) policyout += fmt.Sprintf("%s:%s\n", sc.name, genArgs(uint(a), (v))) done = true } } } if done == false { sc, _ := syscallByNum(call) policyout += fmt.Sprintf("%s:1\n", sc.name) } } if *appendpolicy == true { log.Error("Not yet implemented.") } f, err := os.OpenFile(resolvedpath, os.O_CREATE|os.O_RDWR, 0600) if err == nil { _, err := f.WriteString(policyout) if err != nil { log.Error("Error writing policy file: %v", err) } err = f.Close() if err != nil { log.Error("Error closing policy file: %v", err) } } else { log.Error("Error opening policy file \"%s\": %v", resolvedpath, err) } } } }
func Tracer() { p := new(oz.Profile) if err := json.NewDecoder(os.Stdin).Decode(&p); err != nil { log.Error("unable to decode profile data: %v", err) os.Exit(1) } var proc_attr syscall.ProcAttr var sys_attr syscall.SysProcAttr sys_attr.Ptrace = true done := false proc_attr.Sys = &sys_attr cmd := os.Args[1] cmdArgs := os.Args[2:] log.Info("Tracer running command (%v) arguments (%v)\n", cmd, cmdArgs) c := exec.Command(cmd) c.SysProcAttr = &syscall.SysProcAttr{Ptrace: true} c.Env = os.Environ() c.Args = append(c.Args, cmdArgs...) pi, err := c.StdinPipe() if err != nil { fmt.Errorf("error creating stdin pipe for tracer process: %v", err) os.Exit(1) } jdata, err := json.Marshal(p) if err != nil { fmt.Errorf("Unable to marshal seccomp state: %+v", err) os.Exit(1) } io.Copy(pi, bytes.NewBuffer(jdata)) log.Info(string(jdata)) pi.Close() children := make(map[int]bool) renderFunctions := getRenderingFunctions() if err := c.Start(); err == nil { children[c.Process.Pid] = true var s syscall.WaitStatus pid, err := syscall.Wait4(-1, &s, syscall.WALL, nil) children[pid] = true if err != nil { log.Error("Error (wait4) here first: %v %i", err, pid) } log.Info("Tracing child pid: %v\n", pid) for done == false { syscall.PtraceSetOptions(pid, unix.PTRACE_O_TRACESECCOMP|unix.PTRACE_O_TRACEFORK|unix.PTRACE_O_TRACEVFORK|unix.PTRACE_O_TRACECLONE) syscall.PtraceCont(pid, 0) pid, err = syscall.Wait4(-1, &s, syscall.WALL, nil) if err != nil { log.Error("Error (wait4) here: %v %i %v\n", err, pid, children) if len(children) == 0 { done = true } continue } children[pid] = true if s.Exited() == true { delete(children, pid) log.Info("Child pid %v finished.\n", pid) if len(children) == 0 { done = true } continue } if s.Signaled() == true { log.Error("Other pid signalled %v %v", pid, s) delete(children, pid) continue } switch uint32(s) >> 8 { case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_SECCOMP << 8): if err != nil { log.Error("Error (ptrace): %v", err) continue } var regs syscall.PtraceRegs err = syscall.PtraceGetRegs(pid, ®s) if err != nil { log.Error("Error (ptrace): %v", err) } systemcall, err := syscallByNum(getSyscallNumber(regs)) if err != nil { log.Error("Error: %v", err) continue } /* Render the system call invocation */ r := getSyscallRegisterArgs(regs) call := "" if f, ok := renderFunctions[getSyscallNumber(regs)]; ok { call, err = f(pid, r) if err != nil { log.Info("%v", err) continue } } else { call = renderSyscallBasic(pid, systemcall, regs) } log.Info("==============================================\nseccomp hit on sandbox pid %v (%v) syscall %v (%v):\n\n%s\nI ==============================================\n\n", pid, getProcessCmdLine(pid), systemcall.name, systemcall.num, call) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXIT << 8): log.Error("Ptrace exit event detected pid %v (%s)", pid, getProcessCmdLine(pid)) case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_CLONE << 8): log.Error("Ptrace clone event detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_FORK << 8): log.Error("PTrace fork event detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK << 8): log.Error("Ptrace vfork event detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK_DONE << 8): log.Error("Ptrace vfork done event detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXEC << 8): log.Error("Ptrace exec event detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_STOP << 8): log.Error("Ptrace stop event detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGTRAP): log.Error("SIGTRAP detected in pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGCHLD): log.Error("SIGCHLD detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue case uint32(unix.SIGSTOP): log.Error("SIGSTOP detected pid %v (%s)", pid, getProcessCmdLine(pid)) continue default: y := s.StopSignal() log.Error("Child stopped for unknown reasons pid %v status %v signal %i (%s)", pid, s, y, getProcessCmdLine(pid)) continue } } } }
func (c *Cmd) Run() error { runtime.LockOSThread() defer runtime.UnlockOSThread() err := c.Cmd.Start() if err != nil { return err } ready := map[int]bool{} status := syscall.WaitStatus(0) usage := syscall.Rusage{} for { pid, err := syscall.Wait4(c.Cmd.Process.Pid, &status, 0, &usage) if err != nil { return err } if !ready[pid] { _, _, errno := syscall.RawSyscall6(syscall.SYS_PRLIMIT64, uintptr(pid), syscall.RLIMIT_CPU, uintptr(unsafe.Pointer(&syscall.Rlimit{ Cur: uint64(c.Limits.Cpu)/1e9 + 1, Max: uint64(c.Limits.Cpu)/1e9 + 1, })), 0, 0, 0) if errno != 0 { err = errno return err } _, _, errno = syscall.RawSyscall6(syscall.SYS_PRLIMIT64, uintptr(pid), syscall.RLIMIT_DATA, uintptr(unsafe.Pointer(&syscall.Rlimit{ Cur: c.Limits.Memory, Max: c.Limits.Memory, })), 0, 0, 0) if errno != 0 { err = errno return err } ready[pid] = true } c.Usages.Cpu = time.Duration(usage.Utime.Nano()) c.Usages.Memory = uint64(usage.Maxrss * (1 << 10)) switch { case status.Exited(): if status.ExitStatus() != 0 { return ExitError(status) } return nil case status.Signaled(): return ExitError(status) case status.Stopped(): switch { case status.StopSignal()&syscall.SIGTRAP > 0: regs := syscall.PtraceRegs{} err = syscall.PtraceGetRegs(pid, ®s) if err != nil { return err } switch regs.Orig_rax { case syscall.SYS_READ: case syscall.SYS_WRITE: case syscall.SYS_OPEN: case syscall.SYS_CLOSE: case syscall.SYS_STAT: case syscall.SYS_FSTAT: case syscall.SYS_LSTAT: case syscall.SYS_POLL: case syscall.SYS_LSEEK: case syscall.SYS_MMAP: case syscall.SYS_MPROTECT: case syscall.SYS_MUNMAP: case syscall.SYS_BRK: case syscall.SYS_RT_SIGACTION: case syscall.SYS_RT_SIGPROCMASK: case syscall.SYS_RT_SIGRETURN: case syscall.SYS_IOCTL: case syscall.SYS_PREAD64: case syscall.SYS_PWRITE64: case syscall.SYS_READV: case syscall.SYS_WRITEV: case syscall.SYS_ACCESS: case syscall.SYS_PIPE: case syscall.SYS_SELECT: case syscall.SYS_SCHED_YIELD: case syscall.SYS_MREMAP: case syscall.SYS_MSYNC: case syscall.SYS_MINCORE: case syscall.SYS_MADVISE: case syscall.SYS_SHMGET: case syscall.SYS_SHMAT: case syscall.SYS_SHMCTL: case syscall.SYS_DUP: case syscall.SYS_DUP2: case syscall.SYS_PAUSE: case syscall.SYS_NANOSLEEP: case syscall.SYS_GETITIMER: case syscall.SYS_ALARM: case syscall.SYS_SETITIMER: case syscall.SYS_GETPID: case syscall.SYS_SENDFILE: case syscall.SYS_SOCKET: case syscall.SYS_CONNECT: case syscall.SYS_ACCEPT: case syscall.SYS_SENDTO: case syscall.SYS_RECVFROM: case syscall.SYS_SENDMSG: case syscall.SYS_RECVMSG: case syscall.SYS_SHUTDOWN: case syscall.SYS_BIND: case syscall.SYS_LISTEN: case syscall.SYS_GETSOCKNAME: case syscall.SYS_GETPEERNAME: case syscall.SYS_SOCKETPAIR: case syscall.SYS_SETSOCKOPT: case syscall.SYS_GETSOCKOPT: case syscall.SYS_CLONE: case syscall.SYS_FORK: case syscall.SYS_VFORK: case syscall.SYS_EXECVE: // err = syscall.Kill(pid, syscall.SIGKILL) // if err != nil { // return err // } case syscall.SYS_EXIT: case syscall.SYS_WAIT4: case syscall.SYS_KILL: case syscall.SYS_UNAME: case syscall.SYS_SEMGET: case syscall.SYS_SEMOP: case syscall.SYS_SEMCTL: case syscall.SYS_SHMDT: case syscall.SYS_MSGGET: case syscall.SYS_MSGSND: case syscall.SYS_MSGRCV: case syscall.SYS_MSGCTL: case syscall.SYS_FCNTL: case syscall.SYS_FLOCK: case syscall.SYS_FSYNC: case syscall.SYS_FDATASYNC: case syscall.SYS_TRUNCATE: case syscall.SYS_FTRUNCATE: case syscall.SYS_GETDENTS: case syscall.SYS_GETCWD: case syscall.SYS_CHDIR: case syscall.SYS_FCHDIR: case syscall.SYS_RENAME: case syscall.SYS_MKDIR: case syscall.SYS_RMDIR: case syscall.SYS_CREAT: case syscall.SYS_LINK: case syscall.SYS_UNLINK: case syscall.SYS_SYMLINK: case syscall.SYS_READLINK: case syscall.SYS_CHMOD: case syscall.SYS_FCHMOD: case syscall.SYS_CHOWN: case syscall.SYS_FCHOWN: case syscall.SYS_LCHOWN: case syscall.SYS_UMASK: case syscall.SYS_GETTIMEOFDAY: case syscall.SYS_GETRLIMIT: case syscall.SYS_GETRUSAGE: case syscall.SYS_SYSINFO: case syscall.SYS_TIMES: case syscall.SYS_PTRACE: case syscall.SYS_GETUID: case syscall.SYS_SYSLOG: case syscall.SYS_GETGID: case syscall.SYS_SETUID: case syscall.SYS_SETGID: case syscall.SYS_GETEUID: case syscall.SYS_GETEGID: case syscall.SYS_SETPGID: case syscall.SYS_GETPPID: case syscall.SYS_GETPGRP: case syscall.SYS_SETSID: case syscall.SYS_SETREUID: case syscall.SYS_SETREGID: case syscall.SYS_GETGROUPS: case syscall.SYS_SETGROUPS: case syscall.SYS_SETRESUID: case syscall.SYS_GETRESUID: case syscall.SYS_SETRESGID: case syscall.SYS_GETRESGID: case syscall.SYS_GETPGID: case syscall.SYS_SETFSUID: case syscall.SYS_SETFSGID: case syscall.SYS_GETSID: case syscall.SYS_CAPGET: case syscall.SYS_CAPSET: case syscall.SYS_RT_SIGPENDING: case syscall.SYS_RT_SIGTIMEDWAIT: case syscall.SYS_RT_SIGQUEUEINFO: case syscall.SYS_RT_SIGSUSPEND: case syscall.SYS_SIGALTSTACK: case syscall.SYS_UTIME: case syscall.SYS_MKNOD: case syscall.SYS_USELIB: case syscall.SYS_PERSONALITY: case syscall.SYS_USTAT: case syscall.SYS_STATFS: case syscall.SYS_FSTATFS: case syscall.SYS_SYSFS: case syscall.SYS_GETPRIORITY: case syscall.SYS_SETPRIORITY: case syscall.SYS_SCHED_SETPARAM: case syscall.SYS_SCHED_GETPARAM: case syscall.SYS_SCHED_SETSCHEDULER: case syscall.SYS_SCHED_GETSCHEDULER: case syscall.SYS_SCHED_GET_PRIORITY_MAX: case syscall.SYS_SCHED_GET_PRIORITY_MIN: case syscall.SYS_SCHED_RR_GET_INTERVAL: case syscall.SYS_MLOCK: case syscall.SYS_MUNLOCK: case syscall.SYS_MLOCKALL: case syscall.SYS_MUNLOCKALL: case syscall.SYS_VHANGUP: case syscall.SYS_MODIFY_LDT: case syscall.SYS_PIVOT_ROOT: case syscall.SYS__SYSCTL: case syscall.SYS_PRCTL: case syscall.SYS_ARCH_PRCTL: case syscall.SYS_ADJTIMEX: case syscall.SYS_SETRLIMIT: case syscall.SYS_CHROOT: case syscall.SYS_SYNC: case syscall.SYS_ACCT: case syscall.SYS_SETTIMEOFDAY: case syscall.SYS_MOUNT: case syscall.SYS_UMOUNT2: case syscall.SYS_SWAPON: case syscall.SYS_SWAPOFF: case syscall.SYS_REBOOT: case syscall.SYS_SETHOSTNAME: case syscall.SYS_SETDOMAINNAME: case syscall.SYS_IOPL: case syscall.SYS_IOPERM: case syscall.SYS_CREATE_MODULE: case syscall.SYS_INIT_MODULE: case syscall.SYS_DELETE_MODULE: case syscall.SYS_GET_KERNEL_SYMS: case syscall.SYS_QUERY_MODULE: case syscall.SYS_QUOTACTL: case syscall.SYS_NFSSERVCTL: case syscall.SYS_GETPMSG: case syscall.SYS_PUTPMSG: case syscall.SYS_AFS_SYSCALL: case syscall.SYS_TUXCALL: case syscall.SYS_SECURITY: case syscall.SYS_GETTID: case syscall.SYS_READAHEAD: case syscall.SYS_SETXATTR: case syscall.SYS_LSETXATTR: case syscall.SYS_FSETXATTR: case syscall.SYS_GETXATTR: case syscall.SYS_LGETXATTR: case syscall.SYS_FGETXATTR: case syscall.SYS_LISTXATTR: case syscall.SYS_LLISTXATTR: case syscall.SYS_FLISTXATTR: case syscall.SYS_REMOVEXATTR: case syscall.SYS_LREMOVEXATTR: case syscall.SYS_FREMOVEXATTR: case syscall.SYS_TKILL: case syscall.SYS_TIME: case syscall.SYS_FUTEX: case syscall.SYS_SCHED_SETAFFINITY: case syscall.SYS_SCHED_GETAFFINITY: case syscall.SYS_SET_THREAD_AREA: case syscall.SYS_IO_SETUP: case syscall.SYS_IO_DESTROY: case syscall.SYS_IO_GETEVENTS: case syscall.SYS_IO_SUBMIT: case syscall.SYS_IO_CANCEL: case syscall.SYS_GET_THREAD_AREA: case syscall.SYS_LOOKUP_DCOOKIE: case syscall.SYS_EPOLL_CREATE: case syscall.SYS_EPOLL_CTL_OLD: case syscall.SYS_EPOLL_WAIT_OLD: case syscall.SYS_REMAP_FILE_PAGES: case syscall.SYS_GETDENTS64: case syscall.SYS_SET_TID_ADDRESS: case syscall.SYS_RESTART_SYSCALL: case syscall.SYS_SEMTIMEDOP: case syscall.SYS_FADVISE64: case syscall.SYS_TIMER_CREATE: case syscall.SYS_TIMER_SETTIME: case syscall.SYS_TIMER_GETTIME: case syscall.SYS_TIMER_GETOVERRUN: case syscall.SYS_TIMER_DELETE: case syscall.SYS_CLOCK_SETTIME: case syscall.SYS_CLOCK_GETTIME: case syscall.SYS_CLOCK_GETRES: case syscall.SYS_CLOCK_NANOSLEEP: case syscall.SYS_EXIT_GROUP: case syscall.SYS_EPOLL_WAIT: case syscall.SYS_EPOLL_CTL: case syscall.SYS_TGKILL: case syscall.SYS_UTIMES: case syscall.SYS_VSERVER: case syscall.SYS_MBIND: case syscall.SYS_SET_MEMPOLICY: case syscall.SYS_GET_MEMPOLICY: case syscall.SYS_MQ_OPEN: case syscall.SYS_MQ_UNLINK: case syscall.SYS_MQ_TIMEDSEND: case syscall.SYS_MQ_TIMEDRECEIVE: case syscall.SYS_MQ_NOTIFY: case syscall.SYS_MQ_GETSETATTR: case syscall.SYS_KEXEC_LOAD: case syscall.SYS_WAITID: case syscall.SYS_ADD_KEY: case syscall.SYS_REQUEST_KEY: case syscall.SYS_KEYCTL: case syscall.SYS_IOPRIO_SET: case syscall.SYS_IOPRIO_GET: case syscall.SYS_INOTIFY_INIT: case syscall.SYS_INOTIFY_ADD_WATCH: case syscall.SYS_INOTIFY_RM_WATCH: case syscall.SYS_MIGRATE_PAGES: case syscall.SYS_OPENAT: case syscall.SYS_MKDIRAT: case syscall.SYS_MKNODAT: case syscall.SYS_FCHOWNAT: case syscall.SYS_FUTIMESAT: case syscall.SYS_NEWFSTATAT: case syscall.SYS_UNLINKAT: case syscall.SYS_RENAMEAT: case syscall.SYS_LINKAT: case syscall.SYS_SYMLINKAT: case syscall.SYS_READLINKAT: case syscall.SYS_FCHMODAT: case syscall.SYS_FACCESSAT: case syscall.SYS_PSELECT6: case syscall.SYS_PPOLL: case syscall.SYS_UNSHARE: case syscall.SYS_SET_ROBUST_LIST: case syscall.SYS_GET_ROBUST_LIST: case syscall.SYS_SPLICE: case syscall.SYS_TEE: case syscall.SYS_SYNC_FILE_RANGE: case syscall.SYS_VMSPLICE: case syscall.SYS_MOVE_PAGES: case syscall.SYS_UTIMENSAT: case syscall.SYS_EPOLL_PWAIT: case syscall.SYS_SIGNALFD: case syscall.SYS_TIMERFD_CREATE: case syscall.SYS_EVENTFD: case syscall.SYS_FALLOCATE: case syscall.SYS_TIMERFD_SETTIME: case syscall.SYS_TIMERFD_GETTIME: case syscall.SYS_ACCEPT4: case syscall.SYS_SIGNALFD4: case syscall.SYS_EVENTFD2: case syscall.SYS_EPOLL_CREATE1: case syscall.SYS_DUP3: case syscall.SYS_PIPE2: case syscall.SYS_INOTIFY_INIT1: case syscall.SYS_PREADV: case syscall.SYS_PWRITEV: case syscall.SYS_RT_TGSIGQUEUEINFO: case syscall.SYS_PERF_EVENT_OPEN: case syscall.SYS_RECVMMSG: case syscall.SYS_FANOTIFY_INIT: case syscall.SYS_FANOTIFY_MARK: case syscall.SYS_PRLIMIT64: } err = syscall.PtraceSyscall(pid, 0) if err != nil { return err } default: return ExitError(status) } } } panic("unreachable") }
func (t *thread) ptraceGetRegs(regs *syscall.PtraceRegs) os.Error { err := syscall.PtraceGetRegs(t.tid, regs) return os.NewSyscallError("ptrace(GETREGS)", err) }
func Tracer() { p := new(oz.Profile) if err := json.NewDecoder(os.Stdin).Decode(&p); err != nil { log.Error("unable to decode profile data: %v", err) os.Exit(1) } var proc_attr syscall.ProcAttr var sys_attr syscall.SysProcAttr sys_attr.Ptrace = true done := false proc_attr.Sys = &sys_attr cmd := os.Args[1] cmdArgs := os.Args[2:] log.Info("Tracer running command (%v) arguments (%v)\n", cmd, cmdArgs) c := exec.Command(cmd) c.SysProcAttr = &syscall.SysProcAttr{Ptrace: true} c.Env = os.Environ() c.Args = append(c.Args, cmdArgs...) pi, err := c.StdinPipe() if err != nil { fmt.Errorf("error creating stdin pipe for tracer process: %v", err) os.Exit(1) } jdata, err := json.Marshal(p) if err != nil { fmt.Errorf("Unable to marshal seccomp state: %+v", err) os.Exit(1) } io.Copy(pi, bytes.NewBuffer(jdata)) log.Info(string(jdata)) pi.Close() children := make(map[int]bool) if err := c.Start(); err == nil { children[c.Process.Pid] = true var s syscall.WaitStatus pid, err := syscall.Wait4(-1, &s, syscall.WALL, nil) children[pid] = true if err != nil { log.Error("Error (wait4): %v", err) } log.Info("Tracing child pid: %v\n", pid) for done == false { syscall.PtraceSetOptions(pid, unix.PTRACE_O_TRACESECCOMP|unix.PTRACE_O_TRACEFORK|unix.PTRACE_O_TRACEVFORK|unix.PTRACE_O_TRACECLONE|unix.PTRACE_O_TRACEEXIT) syscall.PtraceCont(pid, 0) pid, err = syscall.Wait4(-1, &s, syscall.WALL, nil) if err != nil { log.Error("Error (wait4): %v\n", err) if len(children) == 0 { done = true } continue } children[pid] = true if s.Exited() == true { delete(children, pid) log.Info("Child pid %v finished.\n", pid) if len(children) == 0 { done = true } continue } if uint32(s)>>8 == (uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_SECCOMP << 8)) { if err != nil { log.Error("Error (ptrace): %v", err) continue } var regs syscall.PtraceRegs err = syscall.PtraceGetRegs(pid, ®s) if err != nil { log.Error("Error (ptrace): %v", err) } systemcall, err := syscallByNum(int(regs.Orig_rax)) if err != nil { log.Error("Error: %v", err) continue } var callrep string = fmt.Sprintf("%s(", systemcall.name) var reg uint64 = 0 for arg := range systemcall.args { if systemcall.args[arg] == 0 { break } if arg > 0 { callrep += fmt.Sprintf(",") } switch arg { case 0: reg = regs.Rdi case 1: reg = regs.Rsi case 2: reg = regs.Rdx case 3: reg = regs.Rcx case 4: reg = regs.R8 case 5: reg = regs.R9 } if systemcall.args[arg] == STRINGARG { str, err := readStringArg(pid, uintptr(reg)) if err != nil { log.Error("Error: %v", err) } else { callrep += fmt.Sprintf("\"%s\"", str) } } else if systemcall.args[arg] == INTARG { callrep += fmt.Sprintf("%d", uint64(reg)) } else { /* Stringify pointers in writes to stdout/stderr */ write, err := syscallByName("write") if err != nil { log.Error("Error: %v", err) } if systemcall.num == write.num && (regs.Rdi == uint64(syscall.Stdout) || regs.Rdi == uint64(syscall.Stderr)) { str, err := readStringArg(pid, uintptr(reg)) if err != nil { log.Error("Error %v", err) } else { if isPrintableASCII(str) == true { callrep += fmt.Sprintf("\"%s\"", str) } else { callrep += fmt.Sprintf("0x%X", uintptr(reg)) } } } else { callrep += fmt.Sprintf("0x%X", uintptr(reg)) } } } callrep += ")" log.Info("==============================================\nseccomp hit on sandbox pid %v (%v) syscall %v (%v): \n\n%s\nI ==============================================\n\n", pid, getProcessCmdLine(pid), systemcall.name, regs.Orig_rax, callrep) } } } else { log.Error("Error: %v", err) } }
func Run(startChan <-chan int, stopChan chan struct{}, appName string, appArgs []string, dirName string) <-chan *report.PtMonitorReport { log.Info("ptmon: starting...") sysInfo := system.GetSystemInfo() archName := system.MachineToArchName(sysInfo.Machine) syscallResolver := system.CallNumberResolver(archName) reportChan := make(chan *report.PtMonitorReport, 1) go func() { ptReport := &report.PtMonitorReport{ ArchName: string(archName), SyscallStats: map[string]report.SyscallStatInfo{}, } syscallStats := map[int16]uint64{} eventChan := make(chan syscallEvent) doneMonitoring := make(chan int) var app *exec.Cmd go func() { //Ptrace is not pretty... and it requires that you do all ptrace calls from the same thread runtime.LockOSThread() var err error app, err = target.Start(appName, appArgs, dirName, true) utils.FailOn(err) targetPid := app.Process.Pid log.Debugf("ptmon: target PID ==> %d\n", targetPid) var wstat syscall.WaitStatus _, err = syscall.Wait4(targetPid, &wstat, 0, nil) if err != nil { log.Warnf("ptmon: error waiting for %d: %v\n", targetPid, err) doneMonitoring <- 1 } log.Debugln("ptmon: initial process status =>", wstat) if wstat.Exited() { log.Warn("ptmon: app exited (unexpected)") doneMonitoring <- 2 } if wstat.Signaled() { log.Warn("ptmon: app signalled (unexpected)") doneMonitoring <- 3 } syscallReturn := false gotCallNum := false gotRetVal := false var callNum uint64 var retVal uint64 for wstat.Stopped() { var regs syscall.PtraceRegs switch syscallReturn { case false: if err := syscall.PtraceGetRegs(targetPid, ®s); err != nil { log.Fatalf("ptmon: PtraceGetRegs(call): %v", err) } callNum = regs.Orig_rax syscallReturn = true gotCallNum = true case true: if err := syscall.PtraceGetRegs(targetPid, ®s); err != nil { log.Fatalf("ptmon: PtraceGetRegs(return): %v", err) } retVal = regs.Rax syscallReturn = false gotRetVal = true } err = syscall.PtraceSyscall(targetPid, 0) if err != nil { log.Warnf("ptmon: PtraceSyscall error: %v\n", err) break } _, err = syscall.Wait4(targetPid, &wstat, 0, nil) if err != nil { log.Warnf("ptmon: error waiting 4 %d: %v\n", targetPid, err) break } if gotCallNum && gotRetVal { gotCallNum = false gotRetVal = false eventChan <- syscallEvent{ callNum: int16(callNum), retVal: retVal, } } } log.Infoln("ptmon: monitor is exiting... status=", wstat) doneMonitoring <- 0 }() done: for { select { case rc := <-doneMonitoring: log.Info("ptmon: done =>", rc) break done case <-stopChan: log.Info("ptmon: stopping...") //NOTE: need a better way to stop the target app... if err := app.Process.Signal(syscall.SIGTERM); err != nil { log.Warnln("ptmon: error stopping target app =>", err) if err := app.Process.Kill(); err != nil { log.Warnln("ptmon: error killing target app =>", err) } } break done case e := <-eventChan: ptReport.SyscallCount++ if _, ok := syscallStats[e.callNum]; ok { syscallStats[e.callNum]++ } else { syscallStats[e.callNum] = 1 } } } log.Debugf("ptmon: executed syscall count = %d\n", ptReport.SyscallCount) log.Debugf("ptmon: number of syscalls: %v\n", len(syscallStats)) for scNum, scCount := range syscallStats { log.Debugf("[%v] %v = %v", scNum, syscallResolver(scNum), scCount) ptReport.SyscallStats[strconv.FormatInt(int64(scNum), 10)] = report.SyscallStatInfo{ Number: scNum, Name: syscallResolver(scNum), Count: scCount, } } ptReport.SyscallNum = uint32(len(ptReport.SyscallStats)) reportChan <- ptReport }() return reportChan }
func main() { var wstat syscall.WaitStatus var complete func(syscall.PtraceRegs) = nil var die = false regs := syscall.PtraceRegs{} isSyscall := func(wstat syscall.WaitStatus) bool { return (((uint32(wstat) & 0xff00) >> 8) & 0x80) != 0 } sc := initSyscalls() c := make(chan os.Signal, 1) signal.Notify(c, os.Kill, os.Interrupt) go check(c, &die) if pid == -1 { log.Fatal("No pid set") } err := syscall.PtraceAttach(pid) if err != nil { log.Print("attach") log.Print(err) goto fail } _, err = syscall.Wait4(pid, &wstat, 0, nil) if err != nil { log.Printf("wait %d err %s\n", pid, err) goto fail } err = syscall.PtraceSetOptions(pid, syscall.PTRACE_O_TRACESYSGOOD) if err != nil { log.Print("ptrace set options") log.Print(err) goto fail } for !die { err = syscall.PtraceSyscall(pid, 0) if err != nil { log.Print("syscall") log.Print(err) goto fail } _, err = syscall.Wait4(pid, &wstat, 0, nil) if err != nil { log.Printf("wait %d err %s\n", pid, err) goto fail } // ENTER if wstat.Stopped() { if isSyscall(wstat) { err = syscall.PtraceGetRegs(pid, ®s) if err != nil { log.Print("regs") log.Print(err) goto fail } complete = sc.Call(regs) } } err = syscall.PtraceSyscall(pid, 0) if err != nil { log.Print("syscall 2") log.Print(err) goto fail } _, err = syscall.Wait4(pid, &wstat, 0, nil) if err != nil { log.Printf("wait %d err %s\n", pid, err) goto fail } os.Stdout.Sync() if wstat.Stopped() { if isSyscall(wstat) { err = syscall.PtraceGetRegs(pid, ®s) if err != nil { log.Print("regs") log.Print(err) goto fail } //log.Printf("NUM: %d ::%#v", syscallNum, regs) if complete != nil { complete(regs) complete = nil } } } } fail: syscall.Kill(pid, 18) err = syscall.PtraceDetach(pid) if err != nil { log.Print("detach") log.Print(err) } }