fortify/test/sandbox/ptrace.go
Ophestra 389402f955
All checks were successful
Test / Create distribution (push) Successful in 26s
Test / Fpkg (push) Successful in 34s
Test / Fortify (push) Successful in 2m28s
Test / Data race detector (push) Successful in 3m12s
Test / Flake checks (push) Successful in 59s
test/sandbox/ptrace: generic filter block type
Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-03-28 01:47:24 +09:00

120 lines
2.4 KiB
Go

package sandbox
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"syscall"
"time"
"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 {
const (
statePrefix = "State:"
stateSuffix = "t (tracing stop)"
)
var r io.ReadSeekCloser
if f, err := os.Open(fmt.Sprintf("/proc/%d/status", pid)); err != nil {
return err
} else {
r = f
}
if _, errno := ptrace(PTRACE_ATTACH, pid, 0, nil); errno != 0 {
return &ptraceError{"PTRACE_ATTACH", errno}
}
// ugly! but there does not appear to be another way
for {
time.Sleep(10 * time.Millisecond)
if _, err := r.Seek(0, io.SeekStart); err != nil {
return err
}
s := bufio.NewScanner(r)
var found bool
for s.Scan() {
found = strings.HasPrefix(s.Text(), statePrefix)
if found {
break
}
}
if err := s.Err(); err != nil {
return err
}
if !found {
return syscall.EBADE
}
if strings.HasSuffix(s.Text(), stateSuffix) {
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
}