aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/internal/sandbox/ptrace.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/internal/sandbox/ptrace.go')
-rw-r--r--test/internal/sandbox/ptrace.go87
1 files changed, 87 insertions, 0 deletions
diff --git a/test/internal/sandbox/ptrace.go b/test/internal/sandbox/ptrace.go
new file mode 100644
index 00000000..8272ff5b
--- /dev/null
+++ b/test/internal/sandbox/ptrace.go
@@ -0,0 +1,87 @@
+//go:build testtool
+
+package sandbox
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ NULL = 0
+
+ PTRACE_ATTACH = 16
+ PTRACE_DETACH = 17
+ PTRACE_SECCOMP_GET_FILTER = 0x420c
+)
+
+type ptraceError struct {
+ op string
+ errno syscall.Errno
+}
+
+func (p *ptraceError) Error() string { return fmt.Sprintf("%s: %v", p.op, p.errno) }
+
+func (p *ptraceError) Unwrap() error {
+ if p.errno == 0 {
+ return nil
+ }
+ return p.errno
+}
+
+func ptrace(op uintptr, pid, addr int, data unsafe.Pointer) (r uintptr, errno syscall.Errno) {
+ r, _, errno = syscall.Syscall6(syscall.SYS_PTRACE, op, uintptr(pid), uintptr(addr), uintptr(data), NULL, NULL)
+ return
+}
+
+func ptraceAttach(pid int) error {
+ if _, errno := ptrace(PTRACE_ATTACH, pid, 0, nil); errno != 0 {
+ return &ptraceError{"PTRACE_ATTACH", errno}
+ }
+
+ var status syscall.WaitStatus
+ for {
+ if _, err := syscall.Wait4(pid, &status, syscall.WALL, nil); err != nil {
+ if errors.Is(err, syscall.EINTR) {
+ continue
+ }
+ fatalf("cannot waitpid: %v", err)
+ }
+ break
+ }
+
+ return nil
+}
+
+func ptraceDetach(pid int) error {
+ if _, errno := ptrace(PTRACE_DETACH, pid, 0, nil); errno != 0 {
+ return &ptraceError{"PTRACE_DETACH", errno}
+ }
+ return nil
+}
+
+type sockFilter struct { /* Filter block */
+ code uint16 /* Actual filter code */
+ jt uint8 /* Jump true */
+ jf uint8 /* Jump false */
+ k uint32 /* Generic multiuse field */
+}
+
+func getFilter[T comparable](pid, index int) ([]T, error) {
+ if s := unsafe.Sizeof(*new(T)); s != 8 {
+ panic(fmt.Sprintf("invalid filter block size %d", s))
+ }
+
+ var buf []T
+ if n, errno := ptrace(PTRACE_SECCOMP_GET_FILTER, pid, index, nil); errno != 0 {
+ return nil, &ptraceError{"PTRACE_SECCOMP_GET_FILTER", errno}
+ } else {
+ buf = make([]T, n)
+ }
+ if _, errno := ptrace(PTRACE_SECCOMP_GET_FILTER, pid, index, unsafe.Pointer(&buf[0])); errno != 0 {
+ return nil, &ptraceError{"PTRACE_SECCOMP_GET_FILTER", errno}
+ }
+ return buf, nil
+}