Beispiel #1
0
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, &regsEntry); 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, &regsEntry); 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, &regsExit); err != nil {
			return
		}
		t.callback(regsExit, true)
	}
}
Beispiel #2
0
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, &regs)
		if err != nil {
			panic(err)
		}
		return &regs
	}
}
Beispiel #3
0
func handleSyscall(spid int) *resultPack {
	var regs syscall.PtraceRegs
	if err := syscall.PtraceGetRegs(spid, &regs); 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
}
Beispiel #4
0
// 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)
	}
}
Beispiel #5
0
// GetRegisters is a wrapper for ptrace(PTRACE_GETREGS)
func (p *Process) GetRegisters() (*RegisterState, error) {
	registers := &RegisterState{}
	err := syscall.PtraceGetRegs(p.Pid, &registers.PtraceRegs)
	if err != nil {
		return nil, err
	}
	return registers, nil
}
Beispiel #6
0
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
}
Beispiel #7
0
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, &regs)
		fmt.Printf("%s = ", xsys(regs.Orig_rax))

		if waitSyscall(proc) {
			break
		}

		syscall.PtraceGetRegs(proc.Pid, &regs)
		fmt.Printf("%#x\n", regs.Rax)
	}
}
Beispiel #8
0
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")
}
Beispiel #9
0
// 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, &regs) == nil {
					state(pid, &regs)
				}
			}
		}
		syscall.PtraceSyscall(pid, signal)
	}
}
Beispiel #10
0
func (pt *Ptrace) Regs() (*syscall.PtraceRegs, error) {
	regs := &syscall.PtraceRegs{}
	err := syscall.PtraceGetRegs(pt.Pid(), regs)
	return regs, err
}
Beispiel #11
0
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, &regs); err != nil {
				log.Fatalf("PtraceGetRegs: %v", err)
			}
			regs.Rip -= breakpointInstrLen
			if err := syscall.PtraceSetRegs(pid, &regs); 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)
		}
	}
}
Beispiel #12
0
func (s *Server) ptraceGetRegs(pid int, regsout *syscall.PtraceRegs) (err error) {
	s.fc <- func() error {
		return syscall.PtraceGetRegs(pid, regsout)
	}
	return <-s.ec
}
Beispiel #13
0
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, &regs)

				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)
			}
		}
	}
}
Beispiel #14
0
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, &regs)

				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
			}
		}
	}

}
Beispiel #15
0
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, &regs)
				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)
}
Beispiel #17
0
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, &regs)
				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)
	}

}
Beispiel #18
0
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, &regs); err != nil {
						log.Fatalf("ptmon: PtraceGetRegs(call): %v", err)
					}

					callNum = regs.Orig_rax
					syscallReturn = true
					gotCallNum = true
				case true:
					if err := syscall.PtraceGetRegs(targetPid, &regs); 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
}
Beispiel #19
0
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, &regs)
				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, &regs)
				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)
	}
}