func (c *CloneParams) Unfreeze(pid int) error { err := syscall.PtraceDetach(pid) co, ok := <-c.comm if !ok { return os.NewSyscallError("PtraceDetach", err) } return childError(co) }
func (t *PTracer) detachThread(thread *thread) { syscall.PtraceDetach(thread.tid) process := thread.process delete(process.threads, thread.tid) delete(t.threads, thread.tid) if len(process.threads) == 0 { delete(t.processes, process.pid) close(process.detached) log.Printf("Process %d detached", process.pid) } }
func main() { tpid := flag.Int("pid", 0, "the pid you want to f**k with") tname := flag.String("rename", "", "the name you want it to be called") flag.Parse() if *tpid == 0 || *tname == "" { flag.Usage() // RTFM os.Exit(1) } StackLocation := FindStack(*tpid) if StackLocation == "" { log.Fatal("Unable to find stack. this shouldnt happen.") } log.Printf("Found stack at %s", StackLocation) cmdline := GetCmdLine(*tpid) offset := GetRamOffset(*tpid, StackLocation, cmdline) data := []byte(fmt.Sprint(*tname)) data = append(data, 0x00) eh, _ := os.FindProcess(*tpid) err := syscall.PtraceAttach(eh.Pid) if err != nil { log.Fatalf("Could not attach to the PID. Why? %s", err) } _, err = syscall.PtracePokeData(eh.Pid, uintptr(offset), data) if err != nil { log.Fatalf("now I've f****d up! %s is the error", err) } // fmt.Printf("No idea what it means, but here is 'c' : %d", c) err = syscall.PtraceDetach(eh.Pid) if err != nil { log.Fatalf("Unable to detach?? Why? %s", err) } err = syscall.Kill(eh.Pid, syscall.SIGCONT) if err != nil { log.Fatalf("Unable to detach?? Why? %s", err) } }
func RenamePid(tpid int, tname string) { log.Printf("Attempting to rename pid %d to %s", tpid, tname) StackLocation := FindStack(tpid) if StackLocation == "" { log.Printf("Unable to find stack. this shouldnt happen.") return } cmdline := GetCmdLine(tpid) offset := GetRamOffset(tpid, StackLocation, cmdline) data := []byte(fmt.Sprint(tname)) data = append(data, 0x00) eh, _ := os.FindProcess(tpid) err := syscall.PtraceAttach(eh.Pid) if err != nil { log.Printf("Could not attach to the PID. Why? %s", err) return } _, err = syscall.PtracePokeData(eh.Pid, uintptr(offset), data) if err != nil { log.Printf("now I've f****d up! %s is the error", err) return } // fmt.Printf("No idea what it means, but here is 'c' : %d", c) err = syscall.PtraceDetach(eh.Pid) if err != nil { log.Printf("Unable to detach?? Why? %s", err) return } err = syscall.Kill(eh.Pid, syscall.SIGCONT) if err != nil { log.Printf("Unable to detach?? Why? %s", err) return } }
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") }
func TestGoshDoesNotReportSigStopOrContinueAsExitEvenUnderPtrace(t *testing.T) { assert := assrt.NewAssert(t) cmdr := NewRunningCommand( exec.Command("bash", "-c", "sleep 1; exit 4;"), ) cmdr.Start() // Ride the wild wind if err := syscall.PtraceAttach(cmdr.Pid()); err != nil { panic(err) } NewRunningCommand(exec.Command("kill", "-SIGSTOP", Itoa(cmdr.Pid()))).Start().Wait() assert.Equal( false, cmdr.WaitSoon(1500*time.Millisecond), ) NewRunningCommand(exec.Command("kill", "-SIGCONT", Itoa(cmdr.Pid()))).Start().Wait() // Must detach ptrace again for the wait to return. if err := syscall.PtraceDetach(cmdr.Pid()); err != nil { // This boggles my mind. You can pause before and after this, and that pid most certainly does exist, but here we occationally get errors nonetheless. // Have to skip, because we are attached, that process does exist, and if we can't detach, waiting for exit is going to hang forever. t.Skipf("error detaching ptrace: %+v -- pid=%v\n", err, cmdr.Pid()) } assert.Equal( 4, cmdr.GetExitCode(), ) assert.Equal( nil, cmdr.err, ) assert.Equal( FINISHED, cmdr.State(), ) }
func (t *thread) ptraceDetach() os.Error { err := syscall.PtraceDetach(t.tid) return os.NewSyscallError("ptrace(DETACH)", err) }
func main() { flag.Parse() if len(flag.Args()) < 1 { os.Exit(1) } // note the unshare system call worketh not for Go. // So do it ourselves. We have to start ourselves up again, // after having spawned ourselves with lots of clone // flags sets. To know that we spawned ourselves we add '#' // as the last arg. # was chosen because shells normally filter // it out, so its presence as our last arg is highly indicative // that we really spawned us. Also, for testing, you can always // pass it by hand to see what the namespace looks like. a := os.Args if a[len(a)-1][0] != '#' { a = append(a, "#") if syscall.Geteuid() != 0 { a[len(a)-1] = "#u" } // spawn ourselves with the right unsharing settings. c := exec.Command(a[0], a[1:]...) c.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID} // c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWNET if syscall.Geteuid() != 0 { c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWUSER // Interesting. Won't build statically? //c.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{ContainerID: 0, HostID: syscall.Getuid(), Size: 1}} //c.SysProcAttr.GidMappings = []syscall.SysProcIDMap{{ContainerID: 0, HostID: syscall.Getgid(), Size: 1}} } c.Stdin = os.Stdin c.Stdout = os.Stdout c.Stderr = os.Stderr //t, err := getTermios(1) //if err != nil { // log.Fatalf("Can't get termios on fd 1: %v", err) //} if err := c.Run(); err != nil { log.Printf(err.Error()) } //if err := t.set(1); err != nil { // log.Printf("Can't reset termios on fd1: %v", err) //} os.Exit(1) } unprivileged := a[len(a)-1] == "#u" // unlike pflask, we require that you set a chroot. // If you make it /, strange things are bound to happen. // if that is too limiting we'll have to change this. if *chroot == "" { log.Fatalf("you are required to set the chroot via --chroot") } a = flag.Args() //log.Printf("greetings %v\n", a) a = a[:len(a)-1] ptm, pts, sname, err := ptsopen() if err != nil { log.Fatalf(err.Error()) } // child code. Not really. What really happens here is we set // ourselves into the container, and spawn the child. It's a bit odd // but we're the master, but we'll run in the container? I don't know // how else to do it. This may require we set some things up first, // esp. the network. But, it's all fun and games until someone loses // an eye. MountAll(*chroot, unprivileged) if !unprivileged { copy_nodes(*chroot) } make_ptmx(*chroot) make_symlinks(*chroot) make_console(*chroot, sname, unprivileged) //umask(0022); /* TODO: drop capabilities */ //do_user(user); e := make(map[string]string) if *keepenv { for _, v := range os.Environ() { k := strings.SplitN(v, "=", 2) e[k[0]] = k[1] } } term := os.Getenv("TERM") e["TERM"] = term e["PATH"] = "/usr/sbin:/usr/bin:/sbin:/bin" e["USER"] = *user e["LOGNAME"] = *user e["HOME"] = "/root" if *env != "" { for _, c := range strings.Split(*env, ",") { k := strings.SplitN(c, "=", 2) if len(k) != 2 { log.Printf("Bogus environment string %v", c) continue } e[k[0]] = k[1] } } e["container"] = "pflask" if *cgroup == "" { var envs []string for k, v := range e { envs = append(envs, k+"="+v) } if err := syscall.Chroot(*chroot); err != nil { log.Fatal(err) } if err := syscall.Chdir(*chdir); err != nil { log.Fatal(err) } log.Fatal(syscall.Exec(a[0], a[1:], envs)) } c := exec.Command(a[0], a[1:]...) c.Env = nil for k, v := range e { c.Env = append(c.Env, k+"="+v) } c.SysProcAttr = &syscall.SysProcAttr{ Chroot: *chroot, Setctty: true, Setsid: true, } c.Stdout = pts c.Stdin = pts c.Stderr = c.Stdout c.SysProcAttr.Setctty = true c.SysProcAttr.Setsid = true c.SysProcAttr.Ptrace = true c.Dir = *chdir err = c.Start() if err != nil { panic(err) } kid := c.Process.Pid log.Printf("Started %d\n", kid) // set up the containers, then resume the process. // Its children will get the containers as it clones. cg := cgroupname(*cgpath) cg.Do(*cgroup, kid) // sometimes the detach fails. Looks like a race condition: we're // sending the detach before the child has hit the TRACE_ME point. // Experimentally, when it fails, even one seconds it too short to // sleep. Sleep for 5 seconds. // Oh well it's not that. It's that there is some one of these // processes not in the PID namespace of the child? Who knows, sigh. // This is an aspect of the Go runtime that is seriously broken. for i := 0; ; i++ { if err = syscall.PtraceDetach(kid); err != nil { log.Printf("Could not detach %v, sleeping 250 milliseconds", kid) time.Sleep(250 * time.Millisecond) continue } if i > 100 { log.Fatalf("Tried for 10 seconds to get a DETACH. Let's fix the go runtime someday") } break } raw() go func() { io.Copy(os.Stdout, ptm) os.Exit(1) }() io.Copy(ptm, os.Stdin) }
func (t *Tracer) Detach() error { return syscall.PtraceDetach(t.Process.Pid) }
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) } }