WIP: Golang Proot code #1

Draft
Sirherobrine23 wants to merge 5 commits from proot_binding into main
6 changed files with 313 additions and 196 deletions
Showing only changes of commit 68b4eeb842 - Show all commits

2
go.mod
View File

@@ -5,6 +5,7 @@ go 1.24.4
require ( require (
github.com/docker/docker v28.3.3+incompatible github.com/docker/docker v28.3.3+incompatible
github.com/docker/go-connections v0.5.0 github.com/docker/go-connections v0.5.0
golang.org/x/sys v0.34.0
) )
require ( require (
@@ -37,7 +38,6 @@ require (
go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect
golang.org/x/net v0.41.0 // indirect golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/time v0.8.0 // indirect golang.org/x/time v0.8.0 // indirect
google.golang.org/grpc v1.73.0 // indirect google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect google.golang.org/protobuf v1.36.6 // indirect

View File

@@ -474,7 +474,7 @@ static int handle_tracee_event_kernel_4_8(Tracee *tracee, int tracee_status)
default_ptrace_options); default_ptrace_options);
if (status < 0) { if (status < 0) {
note(tracee, ERROR, SYSTEM, "ptrace(PTRACE_SETOPTIONS)"); note(tracee, ERROR, SYSTEM, "ptrace(PTRACE_SETOPTIONS)");
exit(EXIT_FAILURE); exit(EXIT_FAILUtRE);
} }
} }
else { else {

32
proot/cmd/main.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"fmt"
"os"
"sirherobrine23.com.br/go-bds/exec/exec"
"sirherobrine23.com.br/go-bds/exec/proot"
)
func main() {
cmd, _ := proot.NewProc()
err := cmd.Start(&exec.Exec{
Arguments: os.Args[min(1, len(os.Args)):],
Stdout: os.Stdout,
Stderr: os.Stderr,
Stdin: os.Stdin,
})
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(-1)
return
}
if err = cmd.Wait(); err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(-1)
return
}
}

View File

@@ -2,6 +2,7 @@
package proot package proot
import ( import (
"context"
"io" "io"
"os/exec" "os/exec"
@@ -14,12 +15,17 @@ type Proot struct {
Cmd *exec.Cmd // Golang process Cmd *exec.Cmd // Golang process
EventLocked bool EventLocked bool
NoSeccomp bool
Err error Err error
last_exit_status int last_exit_status int
Tracees []*Tracee Tracees []*Tracee
vpid int vpid int
doneEnd *exec.ExitError
done context.Context
donefFn context.CancelFunc
Stdin io.Reader Stdin io.Reader
Stdout, Stderr io.Writer Stdout, Stderr io.Writer
} }
@@ -32,7 +38,8 @@ func (proot *Proot) Wait() error {
} }
return nil return nil
case proot.Cmd != nil && proot.Cmd.Process != nil: case proot.Cmd != nil && proot.Cmd.Process != nil:
return proot.Cmd.Wait() <-proot.done.Done()
return proot.doneEnd
default: default:
return goexec.ErrNoProcess return goexec.ErrNoProcess
} }

View File

@@ -3,18 +3,37 @@
package proot package proot
import ( import (
"context"
"fmt" "fmt"
"log"
"os" "os"
"os/exec" "os/exec"
"reflect"
"runtime" "runtime"
"slices"
"syscall" "syscall"
"time" "time"
"unsafe"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
goexec "sirherobrine23.com.br/go-bds/exec/exec" goexec "sirherobrine23.com.br/go-bds/exec/exec"
) )
const (
DISABLED = iota
DISABLING
ENABLED
FILTER_SYSEXIT = 0x1
)
const (
SIGSTOP_IGNORED = iota /* Ignore SIGSTOP (once the parent is known). */
SIGSTOP_ALLOWED /* Allow SIGSTOP (once the parent is known). */
SIGSTOP_PENDING /* Block SIGSTOP until the parent is unknown. */
)
var _ = goexec.Register("proot", NewProc) var _ = goexec.Register("proot", NewProc)
func NewProc() (*Proot, error) { func NewProc() (*Proot, error) {
@@ -28,6 +47,9 @@ func (proot *Proot) Kill() error { return proot.Cmd.Process.Kill()
func (proot *Proot) Signal(s os.Signal) error { return proot.Cmd.Process.Signal(s) } func (proot *Proot) Signal(s os.Signal) error { return proot.Cmd.Process.Signal(s) }
func (proot *Proot) Close() error { func (proot *Proot) Close() error {
if proot.Cmd.Process != nil {
return proot.Cmd.Process.Signal(os.Interrupt)
}
return nil return nil
} }
@@ -43,13 +65,56 @@ func (proot *Proot) Start(options *goexec.Exec) error {
proot.Cmd.SysProcAttr.Ptrace = true proot.Cmd.SysProcAttr.Ptrace = true
proot.Cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER proot.Cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
// attach stdin
switch {
case options.Stdin != nil:
proot.Cmd.Stdin = options.Stdin
case proot.Stdin != nil:
proot.Cmd.Stdin = proot.Stdin
}
// attach stdout
switch {
case options.Stdout != nil:
proot.Cmd.Stdout = options.Stdout
case proot.Stdout != nil:
proot.Cmd.Stdout = proot.Stdout
}
// attach stderr
switch {
case options.Stderr != nil:
proot.Cmd.Stderr = options.Stderr
case proot.Stderr != nil:
proot.Cmd.Stderr = proot.Stderr
}
runtime.LockOSThread() // Lock thread to use PTRACE runtime.LockOSThread() // Lock thread to use PTRACE
proot.EventLocked = true proot.EventLocked = true
// go proot.Event() // Start background loop event proot.done, proot.donefFn = context.WithCancel(context.Background())
proot.Cmd.Start() go proot.Event() // Start background loop event
proot.Event() // Start background loop event return proot.Cmd.Start()
return nil }
func mountProcessState(pid int, status unix.WaitStatus, rusage *unix.Rusage) *os.ProcessState {
newState := &os.ProcessState{}
ptr := reflect.ValueOf(newState).Elem()
ptrType := ptr.Type()
for index := range ptr.Type().NumField() {
ptr, ptrType := ptr.Field(index), ptrType.Field(index)
switch ptrType.Name {
case "pid":
ptr.SetInt(int64(pid))
case "status":
ptr.Set(reflect.ValueOf(syscall.WaitStatus(status)))
case "rusage":
ptr.Set(reflect.ValueOf(any(rusage).(*syscall.Rusage)))
}
}
return newState
} }
func (proot *Proot) Event() { func (proot *Proot) Event() {
@@ -62,9 +127,14 @@ func (proot *Proot) Event() {
} }
wpid, err := unix.Wait4(proot.Cmd.Process.Pid, &wstatus, unix.WALL, &rusage) wpid, err := unix.Wait4(proot.Cmd.Process.Pid, &wstatus, unix.WALL, &rusage)
fmt.Println(err)
switch err { switch err {
case nil: case nil:
case syscall.Errno(3), syscall.Errno(10): case syscall.Errno(10):
proot.doneEnd = &exec.ExitError{ProcessState: mountProcessState(proot.Cmd.Process.Pid, wstatus, &rusage)}
proot.donefFn()
return
case syscall.Errno(3):
unix.Kill(wpid, unix.PTRACE_CONT) unix.Kill(wpid, unix.PTRACE_CONT)
continue continue
default: default:
@@ -79,17 +149,25 @@ func (proot *Proot) Event() {
wstatus.Continued(), wstatus.Continued(),
) )
log.Printf("Getting tracee to wpid %d\n", wpid)
tracee := proot.GetTracee(nil, wpid, true) tracee := proot.GetTracee(nil, wpid, true)
tracee.Running = false tracee.Running = false
if tracee.AsPtracee != nil { if tracee.AsPtracee != nil {
log.Printf("handle_ptracee_event to %d\n", wpid)
keep_stopped := proot.handle_ptracee_event(tracee, wstatus) keep_stopped := proot.handle_ptracee_event(tracee, wstatus)
if keep_stopped { if keep_stopped {
continue continue
} }
} }
log.Printf("handle_tracee_event to %d\n", wpid)
signal := proot.handle_tracee_event(tracee, wstatus) signal := proot.handle_tracee_event(tracee, wstatus)
log.Printf("restarting tracee to %d with %s\n", wpid, unix.Signal(signal))
if signal == -255 && proot.Err != nil {
fmt.Println(proot.Err)
signal = 0
}
proot.restart_tracee(tracee, unix.Signal(signal)) proot.restart_tracee(tracee, unix.Signal(signal))
} }
} }
@@ -204,16 +282,14 @@ func (proot *Proot) handle_ptracee_event(ptracee *Tracee, event unix.WaitStatus)
unix.Kill(ptracee.Pid, unix.SIGCHLD) unix.Kill(ptracee.Pid, unix.SIGCHLD)
//#define EXPECTED_WAIT_CLONE(wait_options,tracee) ((((wait_options) & __WALL) != 0) || ((((wait_options) & __WCLONE) != 0) && (tracee)->clone) || ((((wait_options) & __WCLONE) == 0) && !(tracee)->clone))
// if ( (PTRACER.wait_pid == -1 || PTRACER.wait_pid == ptracee->pid) && EXPECTED_WAIT_CLONE(PTRACER.wait_options, ptracee))
if ptracer.AsPtracer.WaitPid == -1 || ptracer.AsPtracer.WaitPid == ptracee.Pid && if ptracer.AsPtracer.WaitPid == -1 || ptracer.AsPtracer.WaitPid == ptracee.Pid &&
(ptracer.AsPtracer.WaitOptions&unix.WALL != 0 || (ptracer.AsPtracer.WaitOptions&unix.WCLONE != 0 && ptracee.Clone) || (ptracer.AsPtracer.WaitOptions&unix.WCLONE == 0 && !ptracee.Clone)) { (ptracer.AsPtracer.WaitOptions&unix.WALL != 0 || (ptracer.AsPtracer.WaitOptions&unix.WCLONE != 0 && ptracee.Clone) || (ptracer.AsPtracer.WaitOptions&unix.WCLONE == 0 && !ptracee.Clone)) {
status := proot.update_wait_status(ptracer, ptracee) status := proot.update_wait_status(ptracer, ptracee)
if status != 0 { if status != 0 {
// poke_reg(ptracer, SYSARG_RESULT, (word_t) status); // proot.poke_reg(ptracer, SYSARG_RESULT, (word_t) status);
} }
/* Write ptracer's register cache back. */ /* Write ptracer's register cache back. */
// (void) push_regs(ptracer); // proot.push_regs(ptracer);
ptracer.AsPtracer.WaitPid = 0 ptracer.AsPtracer.WaitPid = 0
restarted := proot.restart_tracee(ptracer, 0) restarted := proot.restart_tracee(ptracer, 0)
@@ -226,31 +302,52 @@ func (proot *Proot) handle_ptracee_event(ptracee *Tracee, event unix.WaitStatus)
} }
func (proot *Proot) update_wait_status(ptracer, ptracee *Tracee) (result int) { func (proot *Proot) update_wait_status(ptracer, ptracee *Tracee) (result int) {
/* Special case: the Linux kernel reports the terminating
* event issued by a process to both its parent and its
* tracer, except when they are the same. In this case the
* Linux kernel reports the terminating event only once to the
* tracing parent ... */
if ptracee.AsPtracee.Ptracer == ptracee.Parent &&
(unix.WaitStatus(ptracee.AsPtracee.Event4.Ptracer.Value).Exited() ||
unix.WaitStatus(ptracee.AsPtracee.Event4.Ptracer.Value).Signaled()) {
/* ... So hide this terminating event (toward its
* tracer, ie. PRoot) and make the second one appear
* (towards its parent, ie. the ptracer). This will
* ensure its exit status is collected from a kernel
* point-of-view (ie. it doesn't stay a zombie
* forever). */
// restart_original_syscall(ptracer);
// /* Special case: the Linux kernel reports the terminating /* Detach this ptracee from its ptracer, PRoot doesn't
// * event issued by a process to both its parent and its * have anything else to emulate. */
// * tracer, except when they are the same. In this case the // detach_from_ptracer(ptracee);
// * Linux kernel reports the terminating event only once to the
// * tracing parent ... */
// if (PTRACEE.ptracer == ptracee->parent
// && (WIFEXITED(PTRACEE.event4.ptracer.value)
// || WIFSIGNALED(PTRACEE.event4.ptracer.value))) {
// /* ... So hide this terminating event (toward its
// * tracer, ie. PRoot) and make the second one appear
// * (towards its parent, ie. the ptracer). This will
// * ensure its exit status is collected from a kernel
// * point-of-view (ie. it doesn't stay a zombie
// * forever). */
// restart_original_syscall(ptracer);
// /* Detach this ptracee from its ptracer, PRoot doesn't /* Zombies can rest in peace once the ptracer is notified. */
// * have anything else to emulate. */ // if (PTRACEE.is_zombie)
// TALLOC_FREE(ptracee);
return 0
}
// address = peek_reg(ptracer, ORIGINAL, SYSARG_2);
// if (address != 0) {
// poke_int32(ptracer, address, PTRACEE.event4.ptracer.value);
// if (errno != 0)
// return -errno;
// }
// PTRACEE.event4.ptracer.pending = false;
/* Be careful; ptracee might get freed before its pid is returned. */
// result = ptracee->pid;
// /* Zombies can rest in peace once the ptracer is notified. */
// if (PTRACEE.is_zombie) {
// detach_from_ptracer(ptracee); // detach_from_ptracer(ptracee);
// TALLOC_FREE(ptracee);
// }
// /* Zombies can rest in peace once the ptracer is // return result;
// * notified. */
// if (PTRACEE.is_zombie)
// TALLOC_FREE(ptracee);
return 0 return 0
} }
@@ -281,6 +378,15 @@ func is_kernel_4_8() bool {
return (major == 4 && minor >= 8) || major > 4 return (major == 4 && minor >= 8) || major > 4
} }
func (proot *Proot) terminate_tracee(tracee *Tracee) {
tracee.Terminated = true
if tracee.KillallOnExit {
for _, tracee := range slices.Backward(proot.Tracees) {
unix.Kill(tracee.Pid, unix.SIGKILL)
}
}
}
func (proot *Proot) handle_tracee_event_kernel_4_8(tracee *Tracee, tracee_status unix.WaitStatus) int { func (proot *Proot) handle_tracee_event_kernel_4_8(tracee *Tracee, tracee_status unix.WaitStatus) int {
/* Don't overwrite restart_how if it is explicitly set /* Don't overwrite restart_how if it is explicitly set
* elsewhere, i.e in the ptrace emulation when single * elsewhere, i.e in the ptrace emulation when single
@@ -300,181 +406,146 @@ func (proot *Proot) handle_tracee_event_kernel_4_8(tracee *Tracee, tracee_status
} }
} }
// var seccomp_detected, seccomp_enabled bool var signal int
var var seccomp_detected, seccomp_enabled bool
// status,
signal int
/* Not a signal-stop by default. */ /* Not a signal-stop by default. */
signal = 0 signal = 0
if tracee_status.Exited() { if tracee_status.Exited() {
// if (WIFEXITED(tracee_status)) {
// last_exit_status = WEXITSTATUS(tracee_status);
// VERBOSE(tracee, 1,
// "vpid %" PRIu64 ": exited with status %d",
// tracee->vpid, last_exit_status);
// terminate_tracee(tracee);
// }
proot.last_exit_status = tracee_status.ExitStatus() proot.last_exit_status = tracee_status.ExitStatus()
proot.terminate_tracee(tracee)
} else if tracee_status.Signaled() { } else if tracee_status.Signaled() {
// else if (WIFSIGNALED(tracee_status)) {
// check_architecture(tracee); // check_architecture(tracee);
// VERBOSE(tracee, 1, proot.terminate_tracee(tracee)
// "vpid %" PRIu64 ": terminated with signal %d",
// tracee->vpid, WTERMSIG(tracee_status));
// terminate_tracee(tracee);
// }
} else if tracee_status.Stopped() { } else if tracee_status.Stopped() {
/* Don't use WSTOPSIG() to extract the signal /* Don't use WSTOPSIG() to extract the signal since it clears the PTRACE_EVENT_* bits. */
* since it clears the PTRACE_EVENT_* bits. */
signal = (int(tracee_status) & 0xfff00) >> 8 signal = (int(tracee_status) & 0xfff00) >> 8
// static bool deliver_sigtrap = false; var deliver_sigtrap bool
// switch (signal) { switch signal {
// case SIGTRAP: { case int(unix.SIGTRAP):
// const unsigned long default_ptrace_options = ( default_ptrace_options :=
// PTRACE_O_TRACESYSGOOD | unix.PTRACE_O_TRACESYSGOOD |
// PTRACE_O_TRACEFORK | unix.PTRACE_O_TRACEFORK |
// PTRACE_O_TRACEVFORK | unix.PTRACE_O_TRACEVFORK |
// PTRACE_O_TRACEVFORKDONE | unix.PTRACE_O_TRACEVFORKDONE |
// PTRACE_O_TRACEEXEC | unix.PTRACE_O_TRACEEXEC |
// PTRACE_O_TRACECLONE | unix.PTRACE_O_TRACECLONE |
// PTRACE_O_TRACEEXIT); unix.PTRACE_O_TRACEEXIT
// /* Distinguish some events from others and if deliver_sigtrap {
// * automatically trace each new process with break
// * the same options. }
// * deliver_sigtrap = true
// * Note that only the first bare SIGTRAP is /* Try to enable seccomp mode 2... */
// * related to the tracing loop, others SIGTRAP err := ptrace(unix.PTRACE_SETOPTIONS, tracee.Pid, 0, uintptr(default_ptrace_options|unix.PTRACE_O_TRACESECCOMP))
// * carry tracing information because of if err != nil {
// * TRACE*FORK/CLONE/EXEC. */ seccomp_enabled = false
// if (deliver_sigtrap) /* ... otherwise use default options only. */
// break; /* Deliver this signal as-is. */ err = ptrace(unix.PTRACE_SETOPTIONS, tracee.Pid, 0, uintptr(default_ptrace_options))
// deliver_sigtrap = true; if err != nil {
// /* Try to enable seccomp mode 2... */ proot.Err = fmt.Errorf("ptrace(PTRACE_SETOPTIONS): %s", err)
// status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL, return -255
// default_ptrace_options | PTRACE_O_TRACESECCOMP); }
// if (status < 0) { } else {
// seccomp_enabled = false; if proot.NoSeccomp {
// /* ... otherwise use default options only. */ seccomp_enabled = true
// status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL, }
// default_ptrace_options); }
// if (status < 0) { fallthrough
// note(tracee, ERROR, SYSTEM, "ptrace(PTRACE_SETOPTIONS)"); case int(unix.SIGTRAP | unix.PTRACE_EVENT_SECCOMP<<8):
// exit(EXIT_FAILURE); if !seccomp_detected && seccomp_enabled {
// } // VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
// } tracee.Seccomp = ENABLED
// else { seccomp_detected = true
// if (getenv("PROOT_NO_SECCOMP") == NULL) }
// seccomp_enabled = true; if signal == int(unix.SIGTRAP|unix.PTRACE_EVENT_SECCOMP<<8) {
// } signal = 0
// } flags := 0
// /* Fall through. */ /* Use the common ptrace flow if seccomp was
// case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8: * explicitly disabled for this tracee. */
// case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: if tracee.Seccomp != ENABLED {
// if (!seccomp_detected && seccomp_enabled) { break
// VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled"); }
// tracee->seccomp = ENABLED; err := ptrace(unix.PTRACE_GETEVENTMSG, tracee.Pid, 0, uintptr(unsafe.Pointer(&flags)))
// seccomp_detected = true; if err != nil {
// } break
// if (signal == (SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8) || }
// signal == (SIGTRAP | PTRACE_EVENT_SECCOMP << 8)) { if (flags & FILTER_SYSEXIT) == 0 {
// unsigned long flags = 0; tracee.RestartHow = unix.PTRACE_CONT
// signal = 0; // translate_syscall(tracee);
// /* Use the common ptrace flow if seccomp was if tracee.Seccomp == DISABLING {
// * explicitly disabled for this tracee. */ tracee.RestartHow = unix.PTRACE_SYSCALL
// if (tracee->seccomp != ENABLED) }
// break; break
// status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags); }
// if (status < 0) }
// break; fallthrough
// if ((flags & FILTER_SYSEXIT) == 0) { case int(unix.SIGTRAP | 0x80):
// tracee->restart_how = PTRACE_CONT; signal = 0
// translate_syscall(tracee); /* This tracee got signaled then freed during the
// if (tracee->seccomp == DISABLING) sysenter stage but the kernel reports the sysexit
// tracee->restart_how = PTRACE_SYSCALL; stage; just discard this spurious tracee/event. */
// break; if tracee.Exe == "" {
// } tracee.RestartHow = unix.PTRACE_CONT /* SYSCALL OR CONT */
// } return 0
// /* Fall through. */ }
// case SIGTRAP | 0x80: switch tracee.Seccomp {
// signal = 0; case ENABLED:
// /* This tracee got signaled then freed during the if tracee.AsPtracee.Ptracer.Status == 0 {
// sysenter stage but the kernel reports the sysexit /* sysenter: ensure the sysexit
// stage; just discard this spurious tracee/event. */ * stage will be hit under seccomp. */
// if (tracee->exe == NULL) { tracee.RestartHow = unix.PTRACE_SYSCALL
// tracee->restart_how = PTRACE_CONT; /* SYSCALL OR CONT */ tracee.SysexitPending = true
// return 0; } else {
// } /* sysexit: the next sysenter
// switch (tracee->seccomp) { * will be notified by seccomp. */
// case ENABLED: tracee.RestartHow = unix.PTRACE_CONT
// if (IS_IN_SYSENTER(tracee)) { tracee.SysexitPending = false
// /* sysenter: ensure the sysexit }
// * stage will be hit under seccomp. */ fallthrough
// tracee->restart_how = PTRACE_SYSCALL; case DISABLED:
// tracee->sysexit_pending = true; // translate_syscall(tracee);
// } /* This syscall has disabled seccomp. */
// else { if tracee.Seccomp == DISABLING {
// /* sysexit: the next sysenter tracee.RestartHow = unix.PTRACE_SYSCALL
// * will be notified by seccomp. */ tracee.Seccomp = DISABLED
// tracee->restart_how = PTRACE_CONT; }
// tracee->sysexit_pending = false; case DISABLING:
// } /* Seccomp was disabled by the
// /* Fall through. */ * previous syscall, but its sysenter
// case DISABLED: * stage was already handled. */
// translate_syscall(tracee); tracee.Seccomp = DISABLED
// /* This syscall has disabled seccomp. */ if tracee.AsPtracee.Ptracer.Status == 0 {
// if (tracee->seccomp == DISABLING) { tracee.Status = 1
// tracee->restart_how = PTRACE_SYSCALL; }
// tracee->seccomp = DISABLED; }
// } case int(unix.SIGTRAP | unix.PTRACE_EVENT_VFORK<<8):
// break; signal = 0
// case DISABLING: // proot.new_child(tracee, CLONE_VFORK);
// /* Seccomp was disabled by the case int(unix.SIGTRAP | unix.PTRACE_EVENT_FORK<<8), int(unix.SIGTRAP | unix.PTRACE_EVENT_CLONE<<8):
// * previous syscall, but its sysenter signal = 0
// * stage was already handled. */ // proot.new_child(tracee, 0);
// tracee->seccomp = DISABLED; case int(unix.SIGTRAP | unix.PTRACE_EVENT_VFORK_DONE<<8), int(unix.SIGTRAP | unix.PTRACE_EVENT_EXEC<<8),
// if (IS_IN_SYSENTER(tracee)) int(unix.SIGTRAP | unix.PTRACE_EVENT_EXIT<<8):
// tracee->status = 1; signal = 0
// break; case int(unix.SIGSTOP):
// } /* Stop this tracee until PRoot has received
// break; * the EVENT_*FORK|CLONE notification. */
// case SIGTRAP | PTRACE_EVENT_VFORK << 8: if tracee.Exe == "" {
// signal = 0; tracee.Sigstop = SIGSTOP_PENDING
// (void) new_child(tracee, CLONE_VFORK); signal = -1
// break; }
// case SIGTRAP | PTRACE_EVENT_FORK << 8: /* For each tracee, the first SIGSTOP
// case SIGTRAP | PTRACE_EVENT_CLONE << 8: * is only used to notify the tracer. */
// signal = 0; if tracee.Sigstop == SIGSTOP_IGNORED {
// (void) new_child(tracee, 0); tracee.Sigstop = SIGSTOP_ALLOWED
// break; signal = 0
// case SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8: }
// case SIGTRAP | PTRACE_EVENT_EXEC << 8: }
// case SIGTRAP | PTRACE_EVENT_EXIT << 8:
// signal = 0;
// break;
// case SIGSTOP:
// /* Stop this tracee until PRoot has received
// * the EVENT_*FORK|CLONE notification. */
// if (tracee->exe == NULL) {
// tracee->sigstop = SIGSTOP_PENDING;
// signal = -1;
// }
// /* For each tracee, the first SIGSTOP
// * is only used to notify the tracer. */
// if (tracee->sigstop == SIGSTOP_IGNORED) {
// tracee->sigstop = SIGSTOP_ALLOWED;
// signal = 0;
// }
// break;
// default:
// /* Deliver this signal as-is. */
// break;
// }
} }
// /* Clear the pending event, if any. */ // /* Clear the pending event, if any. */
// tracee.AsPtracee.Event4.Proot.Pending = false tracee.AsPtracee.Event4.Proot.Pending = false
return signal return signal
} }

View File

@@ -1,6 +1,7 @@
package proot package proot
import ( import (
"os"
"testing" "testing"
"sirherobrine23.com.br/go-bds/exec/exec" "sirherobrine23.com.br/go-bds/exec/exec"
@@ -11,6 +12,9 @@ func TestProot(t *testing.T) {
err := cmd.Start(&exec.Exec{ err := cmd.Start(&exec.Exec{
Arguments: []string{"go", "version"}, Arguments: []string{"go", "version"},
Stdout: os.Stdout,
Stderr: os.Stderr,
Stdin: os.Stdin,
}) })
if err != nil { if err != nil {
@@ -18,5 +22,8 @@ func TestProot(t *testing.T) {
return return
} }
cmd.Wait() if err = cmd.Wait(); err != nil {
t.Error(err)
return
}
} }