From 991a85ce59fc6d8966024ae5837e70d565dfb0e6 Mon Sep 17 00:00:00 2001 From: Karol Baraniecki Date: Tue, 5 Sep 2023 00:33:56 +0200 Subject: [PATCH 1/2] Add a missing table null-terminator in the test This caused testcmd on arm64 to fail by execve reading from random uninitialised memory --- testcmd/testcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcmd/testcmd.c b/testcmd/testcmd.c index 10dd260..09def22 100644 --- a/testcmd/testcmd.c +++ b/testcmd/testcmd.c @@ -17,7 +17,7 @@ int execer(void *arg) { if (fd < 0) { perror("open /usr/bin/env"); } - char *argv[] = {"env", "cp", "../b", "../a"}; + char *argv[] = {"env", "cp", "../b", "../a", NULL}; syscall(SYS_execveat, fd, "", argv, NULL, AT_EMPTY_PATH); perror("execveat"); } From a042b7d574b7ad5617380ff822058f569f1f6ef8 Mon Sep 17 00:00:00 2001 From: Karol Baraniecki Date: Tue, 5 Sep 2023 00:07:50 +0200 Subject: [PATCH 2/2] Introduce arm64 compatibility --- main.go | 132 +++++++++++++++++++++++----------------------- pstate.go | 1 + regs.go | 25 +++++++++ regs_amd64.go | 58 ++++++++++++++++++++ regs_arm64.go | 62 ++++++++++++++++++++++ seccomp.go | 84 ++++++++++++++++------------- syscalls/amd64.go | 47 +++++++++++++++++ syscalls/arm64.go | 47 +++++++++++++++++ testcmd/testcmd.c | 8 ++- trace.go | 10 ---- 10 files changed, 362 insertions(+), 112 deletions(-) create mode 100644 regs.go create mode 100644 regs_amd64.go create mode 100644 regs_arm64.go create mode 100644 syscalls/amd64.go create mode 100644 syscalls/arm64.go diff --git a/main.go b/main.go index c292884..1658279 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( "syscall" "github.com/orivej/e" + s "github.com/orivej/fptrace/syscalls" "golang.org/x/sys/unix" "golang.org/x/text/collate" "golang.org/x/text/language" @@ -196,8 +197,8 @@ func mainLoop(sys *SysState, mainPID int, onExec func(*ProcState), onExit func(* newpid := int(unewpid) cloneFiles := false if trapCause == syscall.PTRACE_EVENT_CLONE { - regs, ok := getRegs(pid) - cloneFiles = ok && regs.Rdx&syscall.CLONE_FILES != 0 + regs, ok := getSysexitRegs(pstate, pid) + cloneFiles = ok && regs.arg2&syscall.CLONE_FILES != 0 } pstates[newpid] = pstate.Clone(cloneFiles) running[newpid] = true @@ -273,45 +274,45 @@ func terminate(pid int, pstate *ProcState, onExit func(p *ProcState)) { } func sysenter(pid int, pstate *ProcState, sys *SysState) bool { - regs, ok := getRegs(pid) + regs, ok := getSysenterRegs(pstate, pid) if !ok { return false } - pstate.Syscall = int(regs.Orig_rax) + pstate.Syscall = int(regs.syscall) switch pstate.Syscall { - case syscall.SYS_EXECVE: + case s.SYS_EXECVE: pstate.NextCmd = Cmd{ - Path: pstate.Abs(readString(pid, regs.Rdi)), - Args: readStrings(pid, regs.Rsi), + Path: pstate.Abs(readString(pid, regs.arg0)), + Args: readStrings(pid, regs.arg1), Dir: pstate.CurDir, } if *flEnv { - pstate.NextCmd.Env = readStrings(pid, regs.Rdx) + pstate.NextCmd.Env = readStrings(pid, regs.arg2) } fmt.Println(pid, "execve", pstate.NextCmd) - case unix.SYS_EXECVEAT: + case s.SYS_EXECVEAT: pstate.NextCmd = Cmd{ - Path: absAt(int32(regs.Rdi), readString(pid, regs.Rsi), pid, pstate, sys), - Args: readStrings(pid, regs.Rdx), + Path: absAt(int32(regs.arg0), readString(pid, regs.arg1), pid, pstate, sys), + Args: readStrings(pid, regs.arg2), Dir: pstate.CurDir, } if *flEnv { - pstate.NextCmd.Env = readStrings(pid, regs.R10) + pstate.NextCmd.Env = readStrings(pid, regs.arg3) } fmt.Println(pid, "execveat", pstate.NextCmd) - case syscall.SYS_UNLINK, syscall.SYS_RMDIR: + case s.SYS_UNLINK, s.SYS_RMDIR: if *flUndelete { - regs.Orig_rax = syscall.SYS_ACCESS - regs.Rsi = syscall.F_OK - err := syscall.PtraceSetRegs(pid, ®s) + regs.syscall = s.SYS_ACCESS + regs.arg1 = unix.F_OK + err := ptraceSetSysenterRegs(pstate, pid, regs) e.Exit(err) } - case syscall.SYS_UNLINKAT: + case s.SYS_UNLINKAT: if *flUndelete { - regs.Orig_rax = syscall.SYS_FACCESSAT - regs.R10 = regs.Rdx - regs.Rdx = syscall.F_OK - err := syscall.PtraceSetRegs(pid, ®s) + regs.syscall = s.SYS_FACCESSAT + regs.arg3 = regs.arg2 + regs.arg2 = unix.F_OK + err := ptraceSetSysenterRegs(pstate, pid, regs) e.Exit(err) } } @@ -319,34 +320,35 @@ func sysenter(pid int, pstate *ProcState, sys *SysState) bool { } func sysexit(pid int, pstate *ProcState, sys *SysState) bool { - regs, ok := getRegs(pid) + regs, ok := getSysexitRegs(pstate, pid) if !ok { return false } - ret := int(regs.Rax) + ret := int(regs.ret) if ret < 0 { return true } ret32 := int32(ret) - if pstate.Syscall == syscall.SYS_FCNTL { - switch regs.Rsi { + if pstate.Syscall == s.SYS_FCNTL { + switch regs.arg1 { case syscall.F_DUPFD: - pstate.Syscall = syscall.SYS_DUP + pstate.Syscall = s.SYS_DUP case syscall.F_DUPFD_CLOEXEC: - pstate.Syscall = syscall.SYS_DUP3 - regs.Rdx = syscall.O_CLOEXEC + pstate.Syscall = s.SYS_DUP3 + regs.arg2 = syscall.O_CLOEXEC case syscall.F_SETFD: - b := regs.Rdx&syscall.FD_CLOEXEC != 0 - pstate.FDCX[int32(regs.Rdi)] = b - fmt.Println(pid, "fcntl/setfd", regs.Rdi, b) + b := regs.arg2&syscall.FD_CLOEXEC != 0 + pstate.FDCX[int32(regs.arg0)] = b + fmt.Println(pid, "fcntl/setfd", regs.arg0, b) } } switch pstate.Syscall { - case syscall.SYS_OPEN, syscall.SYS_OPENAT: - call, at, name, flags := "open", int32(unix.AT_FDCWD), regs.Rdi, regs.Rsi - if pstate.Syscall == syscall.SYS_OPENAT { - call, at, name, flags = "openat", int32(regs.Rdi), regs.Rsi, regs.Rdx + case s.SYS_OPEN, s.SYS_OPENAT: + call, at, name, flags := "open", int32(unix.AT_FDCWD), regs.arg0, regs.arg1 + if pstate.Syscall == s.SYS_OPENAT { + call, at, name, flags = "openat", int32(regs.arg0), regs.arg1, regs.arg2 } + var path string switch { default: @@ -375,72 +377,72 @@ func sysexit(pid int, pstate *ProcState, sys *SysState) bool { } } pstate.IOs.Map[write].Add(inode) - case syscall.SYS_CHDIR: - path := pstate.Abs(readString(pid, regs.Rdi)) + case s.SYS_CHDIR: + path := pstate.Abs(readString(pid, regs.arg0)) pstate.CurDir = path fmt.Println(pid, "chdir", path) - case syscall.SYS_FCHDIR: - path := sys.FS.Path(pstate.FDs[int32(regs.Rdi)]) + case s.SYS_FCHDIR: + path := sys.FS.Path(pstate.FDs[int32(regs.arg0)]) pstate.CurDir = path fmt.Println(pid, "fchdir", path) - case syscall.SYS_LINK: - oldpath := pstate.Abs(readString(pid, regs.Rdi)) - newpath := pstate.Abs(readString(pid, regs.Rsi)) + case s.SYS_LINK: + oldpath := pstate.Abs(readString(pid, regs.arg0)) + newpath := pstate.Abs(readString(pid, regs.arg1)) oldnode := sys.FS.Inode(oldpath) if !pstate.IOs.Map[W].Has[oldnode] { pstate.IOs.Map[R].Add(oldnode) } pstate.IOs.Map[W].Add(sys.FS.Inode(newpath)) fmt.Println(pid, "link", oldpath, newpath) - case syscall.SYS_LINKAT: - oldpath := absAt(int32(regs.Rdi), readString(pid, regs.Rsi), pid, pstate, sys) - newpath := absAt(int32(regs.Rdx), readString(pid, regs.R10), pid, pstate, sys) + case s.SYS_LINKAT: + oldpath := absAt(int32(regs.arg0), readString(pid, regs.arg1), pid, pstate, sys) + newpath := absAt(int32(regs.arg2), readString(pid, regs.arg3), pid, pstate, sys) oldnode := sys.FS.Inode(oldpath) if !pstate.IOs.Map[W].Has[oldnode] { pstate.IOs.Map[R].Add(oldnode) } pstate.IOs.Map[W].Add(sys.FS.Inode(newpath)) fmt.Println(pid, "linkat", oldpath, newpath) - case syscall.SYS_RENAME: - oldpath := pstate.Abs(readString(pid, regs.Rdi)) - newpath := pstate.Abs(readString(pid, regs.Rsi)) + case s.SYS_RENAME: + oldpath := pstate.Abs(readString(pid, regs.arg0)) + newpath := pstate.Abs(readString(pid, regs.arg1)) sys.FS.Rename(oldpath, newpath) fmt.Println(pid, "rename", oldpath, newpath) - case syscall.SYS_RENAMEAT, unix.SYS_RENAMEAT2: - oldpath := absAt(int32(regs.Rdi), readString(pid, regs.Rsi), pid, pstate, sys) - newpath := absAt(int32(regs.Rdx), readString(pid, regs.R10), pid, pstate, sys) + case s.SYS_RENAMEAT, s.SYS_RENAMEAT2: + oldpath := absAt(int32(regs.arg0), readString(pid, regs.arg1), pid, pstate, sys) + newpath := absAt(int32(regs.arg2), readString(pid, regs.arg3), pid, pstate, sys) sys.FS.Rename(oldpath, newpath) fmt.Println(pid, "renameat", oldpath, newpath) - case syscall.SYS_DUP, syscall.SYS_DUP2, syscall.SYS_DUP3: - pstate.FDs[ret32] = pstate.FDs[int32(regs.Rdi)] - if pstate.Syscall == syscall.SYS_DUP3 && regs.Rdx&syscall.O_CLOEXEC != 0 { + case s.SYS_DUP, s.SYS_DUP2, s.SYS_DUP3: + pstate.FDs[ret32] = pstate.FDs[int32(regs.arg0)] + if pstate.Syscall == s.SYS_DUP3 && regs.arg2&syscall.O_CLOEXEC != 0 { pstate.FDCX[ret32] = true } - fmt.Println(pid, "dup", regs.Rdi, ret32, pstate.FDCX[ret32]) - case syscall.SYS_READ, syscall.SYS_PREAD64, syscall.SYS_READV, syscall.SYS_PREADV, unix.SYS_PREADV2: - inode := pstate.FDs[int32(regs.Rdi)] + fmt.Println(pid, "dup", regs.arg0, ret32, pstate.FDCX[ret32]) + case s.SYS_READ, s.SYS_PREAD64, s.SYS_READV, s.SYS_PREADV, s.SYS_PREADV2: + inode := pstate.FDs[int32(regs.arg0)] if inode != 0 && !pstate.IOs.Map[W].Has[inode] { pstate.IOs.Map[R].Add(inode) } - case syscall.SYS_WRITE, syscall.SYS_PWRITE64, syscall.SYS_WRITEV, syscall.SYS_PWRITEV, unix.SYS_PWRITEV2: - inode := pstate.FDs[int32(regs.Rdi)] + case s.SYS_WRITE, s.SYS_PWRITE64, s.SYS_WRITEV, s.SYS_PWRITEV, s.SYS_PWRITEV2: + inode := pstate.FDs[int32(regs.arg0)] if inode != 0 { pstate.IOs.Map[W].Add(inode) } - case syscall.SYS_CLOSE: - n := int32(regs.Rdi) + case s.SYS_CLOSE: + n := int32(regs.arg0) pstate.FDs[n] = 0 delete(pstate.FDCX, n) - fmt.Println(pid, "close", regs.Rdi) - case syscall.SYS_PIPE: + fmt.Println(pid, "close", regs.arg0) + case s.SYS_PIPE, s.SYS_PIPE2: var buf [8]byte - _, err := syscall.PtracePeekData(pid, uintptr(regs.Rdi), buf[:]) + _, err := syscall.PtracePeekData(pid, uintptr(regs.arg0), buf[:]) e.Exit(err) readfd := int32(binary.LittleEndian.Uint32(buf[:4])) writefd := int32(binary.LittleEndian.Uint32(buf[4:])) inode := sys.FS.Pipe() pstate.FDs[readfd], pstate.FDs[writefd] = inode, inode - if regs.Rsi&syscall.O_CLOEXEC != 0 { + if regs.arg1&syscall.O_CLOEXEC != 0 { pstate.FDCX[readfd], pstate.FDCX[writefd] = true, true } fmt.Println(pid, "pipe", readfd, writefd, pstate.FDCX[readfd]) diff --git a/pstate.go b/pstate.go index 9247a93..d6b9324 100644 --- a/pstate.go +++ b/pstate.go @@ -26,6 +26,7 @@ type Cmd struct { type ProcState struct { SysEnter bool // true on enter to syscall Syscall int // call number on exit from syscall + Arg0 uint64 // syscall arg0 on syscall exit CurDir string // working directory CurCmd *Cmd // current command NextCmd Cmd // command after return from execve diff --git a/regs.go b/regs.go new file mode 100644 index 0000000..99b2099 --- /dev/null +++ b/regs.go @@ -0,0 +1,25 @@ +package main + +import "syscall" + +type Regs struct { + syscall int64 + arg0 uint64 + arg1 uint64 + arg2 uint64 + arg3 uint64 + arg4 uint64 + arg5 uint64 + ret uint64 + + platform syscall.PtraceRegs +} + +func getPlatformRegs(pid int) (syscall.PtraceRegs, bool) { + var regs syscall.PtraceRegs + err := syscall.PtraceGetRegs(pid, ®s) + if err != nil && err.(syscall.Errno) == syscall.ESRCH { + return regs, false + } + return regs, true +} diff --git a/regs_amd64.go b/regs_amd64.go new file mode 100644 index 0000000..33570ce --- /dev/null +++ b/regs_amd64.go @@ -0,0 +1,58 @@ +//go:build linux && amd64 +// +build linux,amd64 + +package main + +import ( + "syscall" +) + +func getSysenterRegs(pstate *ProcState, pid int) (regs Regs, ok bool) { + regs.platform, ok = getPlatformRegs(pid) + if !ok { + return regs, false + } + + regs.syscall = int64(regs.platform.Orig_rax) + regs.arg0 = regs.platform.Rdi + regs.arg1 = regs.platform.Rsi + regs.arg2 = regs.platform.Rdx + regs.arg3 = regs.platform.R10 + regs.arg4 = regs.platform.R8 + regs.arg5 = regs.platform.R9 + + return regs, true +} + +func getSysexitRegs(pstate *ProcState, pid int) (regs Regs, ok bool) { + regs.platform, ok = getPlatformRegs(pid) + if !ok { + return regs, false + } + + regs.syscall = int64(regs.platform.Orig_rax) + regs.arg0 = regs.platform.Rdi + regs.arg1 = regs.platform.Rsi + regs.arg2 = regs.platform.Rdx + regs.arg3 = regs.platform.R10 + regs.arg4 = regs.platform.R8 + regs.arg5 = regs.platform.R9 + regs.ret = regs.platform.Rax + + return regs, true +} + +func ptraceSetSysenterRegs(pstate *ProcState, pid int, regs Regs) error { + ptraceRegs := regs.platform + + ptraceRegs.Orig_rax = uint64(regs.syscall) + ptraceRegs.Rdi = regs.arg0 + ptraceRegs.Rsi = regs.arg1 + ptraceRegs.Rdx = regs.arg2 + ptraceRegs.R10 = regs.arg3 + ptraceRegs.R8 = regs.arg4 + ptraceRegs.R9 = regs.arg5 + ptraceRegs.Rax = regs.ret + + return syscall.PtraceSetRegs(pid, &ptraceRegs) +} diff --git a/regs_arm64.go b/regs_arm64.go new file mode 100644 index 0000000..9be8e85 --- /dev/null +++ b/regs_arm64.go @@ -0,0 +1,62 @@ +//go:build linux && arm64 +// +build linux,arm64 + +package main + +import ( + "syscall" +) + +func getSysenterRegs(pstate *ProcState, pid int) (regs Regs, ok bool) { + regs.platform, ok = getPlatformRegs(pid) + if !ok { + return regs, false + } + + regs.syscall = int64(regs.platform.Regs[8]) + regs.arg0 = regs.platform.Regs[0] + regs.arg1 = regs.platform.Regs[1] + regs.arg2 = regs.platform.Regs[2] + regs.arg3 = regs.platform.Regs[3] + regs.arg4 = regs.platform.Regs[4] + regs.arg5 = regs.platform.Regs[5] + + // on arm64 Linux overrides x0 with the sys return value, and doesn't provide + // a way to retrieve the original value like with orig_rax on x64 + pstate.Arg0 = regs.arg0 + + return regs, true +} + +func getSysexitRegs(pstate *ProcState, pid int) (regs Regs, ok bool) { + regs.platform, ok = getPlatformRegs(pid) + if !ok { + return regs, false + } + + regs.syscall = int64(regs.platform.Regs[8]) + regs.arg0 = pstate.Arg0 + regs.arg1 = regs.platform.Regs[1] + regs.arg2 = regs.platform.Regs[2] + regs.arg3 = regs.platform.Regs[3] + regs.arg4 = regs.platform.Regs[4] + regs.arg5 = regs.platform.Regs[5] + regs.ret = regs.platform.Regs[0] + + return regs, true +} + +func ptraceSetSysenterRegs(pstate *ProcState, pid int, regs Regs) error { + pstate.Arg0 = regs.arg0 + + ptraceRegs := regs.platform + ptraceRegs.Regs[8] = uint64(regs.syscall) + ptraceRegs.Regs[0] = regs.arg0 + ptraceRegs.Regs[1] = regs.arg1 + ptraceRegs.Regs[2] = regs.arg2 + ptraceRegs.Regs[3] = regs.arg3 + ptraceRegs.Regs[4] = regs.arg4 + ptraceRegs.Regs[5] = regs.arg5 + + return syscall.PtraceSetRegs(pid, &ptraceRegs) +} diff --git a/seccomp.go b/seccomp.go index 716f8de..10f4f45 100644 --- a/seccomp.go +++ b/seccomp.go @@ -1,4 +1,5 @@ -//+build ignore +//go:build ignore +// +build ignore package main @@ -7,8 +8,8 @@ import ( "os" "github.com/orivej/e" + sys "github.com/orivej/fptrace/syscalls" "golang.org/x/net/bpf" - "golang.org/x/sys/unix" ) const ( @@ -16,47 +17,58 @@ const ( SECCOMP_RET_ALLOW = 0x7fff0000 ) -var syscalls = []uint32{ - unix.SYS_CHDIR, - unix.SYS_CLOSE, - unix.SYS_DUP, - unix.SYS_DUP2, - unix.SYS_DUP3, - unix.SYS_EXECVE, - unix.SYS_EXECVEAT, - unix.SYS_FCHDIR, - unix.SYS_FCNTL, - unix.SYS_LINK, - unix.SYS_LINKAT, - unix.SYS_OPEN, - unix.SYS_OPENAT, - unix.SYS_PIPE, - unix.SYS_PREAD64, - unix.SYS_PREADV, - unix.SYS_PREADV2, - unix.SYS_PWRITE64, - unix.SYS_PWRITEV, - unix.SYS_PWRITEV2, - unix.SYS_READ, - unix.SYS_READV, - unix.SYS_RENAME, - unix.SYS_RENAMEAT, - unix.SYS_RENAMEAT2, - unix.SYS_RMDIR, - unix.SYS_UNLINK, - unix.SYS_UNLINKAT, - unix.SYS_WRITE, - unix.SYS_WRITEV, +var syscalls = []int64{ + sys.SYS_CHDIR, + sys.SYS_CLOSE, + sys.SYS_DUP, + sys.SYS_DUP2, + sys.SYS_DUP3, + sys.SYS_EXECVE, + sys.SYS_EXECVEAT, + sys.SYS_FCHDIR, + sys.SYS_FCNTL, + sys.SYS_LINK, + sys.SYS_LINKAT, + sys.SYS_OPEN, + sys.SYS_OPENAT, + sys.SYS_PIPE, + sys.SYS_PIPE2, + sys.SYS_PREAD64, + sys.SYS_PREADV, + sys.SYS_PREADV2, + sys.SYS_PWRITE64, + sys.SYS_PWRITEV, + sys.SYS_PWRITEV2, + sys.SYS_READ, + sys.SYS_READV, + sys.SYS_RENAME, + sys.SYS_RENAMEAT, + sys.SYS_RENAMEAT2, + sys.SYS_RMDIR, + sys.SYS_UNLINK, + sys.SYS_UNLINKAT, + sys.SYS_WRITE, + sys.SYS_WRITEV, +} + +func syscallsOnThisArch() (available []int64) { + for _, syscall := range syscalls { + if syscall > sys.NOT_ON_THIS_ARCH_MAX { + available = append(available, syscall) + } + } + return } func main() { - n := len(syscalls) + available := syscallsOnThisArch() + n := len(available) p := make([]bpf.Instruction, n+3) p[0] = bpf.LoadAbsolute{Off: 0, Size: 4} p[n+1] = bpf.RetConstant{Val: SECCOMP_RET_ALLOW} p[n+2] = bpf.RetConstant{Val: SECCOMP_RET_TRACE} - for i, sc := range syscalls { - p[i+1] = bpf.JumpIf{Cond: bpf.JumpEqual, Val: sc, SkipTrue: uint8(n - i)} + for i, sc := range available { + p[i+1] = bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(sc), SkipTrue: uint8(n - i)} } ins, err := bpf.Assemble(p) e.Exit(err) diff --git a/syscalls/amd64.go b/syscalls/amd64.go new file mode 100644 index 0000000..0577969 --- /dev/null +++ b/syscalls/amd64.go @@ -0,0 +1,47 @@ +//go:build linux && amd64 +// +build linux,amd64 + +package syscalls + +import "golang.org/x/sys/unix" + +const ( + // specifies max sys id that doesn't exist in this cpu architecture, but does in other ones + NOT_ON_THIS_ARCH_MAX = -1 + + SYS_CHDIR = unix.SYS_CHDIR + SYS_CLOSE = unix.SYS_CLOSE + SYS_DUP = unix.SYS_DUP + SYS_DUP2 = unix.SYS_DUP2 + SYS_DUP3 = unix.SYS_DUP3 + SYS_EXECVE = unix.SYS_EXECVE + SYS_EXECVEAT = unix.SYS_EXECVEAT + SYS_FCHDIR = unix.SYS_FCHDIR + SYS_FCNTL = unix.SYS_FCNTL + SYS_LINK = unix.SYS_LINK + SYS_LINKAT = unix.SYS_LINKAT + SYS_OPEN = unix.SYS_OPEN + SYS_OPENAT = unix.SYS_OPENAT + SYS_PIPE = unix.SYS_PIPE + SYS_PIPE2 = unix.SYS_PIPE2 + SYS_PREAD64 = unix.SYS_PREAD64 + SYS_PREADV = unix.SYS_PREADV + SYS_PREADV2 = unix.SYS_PREADV2 + SYS_PWRITE64 = unix.SYS_PWRITE64 + SYS_PWRITEV = unix.SYS_PWRITEV + SYS_PWRITEV2 = unix.SYS_PWRITEV2 + SYS_READ = unix.SYS_READ + SYS_READV = unix.SYS_READV + SYS_RENAME = unix.SYS_RENAME + SYS_RENAMEAT = unix.SYS_RENAMEAT + SYS_RENAMEAT2 = unix.SYS_RENAMEAT2 + SYS_RMDIR = unix.SYS_RMDIR + SYS_UNLINK = unix.SYS_UNLINK + SYS_UNLINKAT = unix.SYS_UNLINKAT + SYS_WRITE = unix.SYS_WRITE + SYS_WRITEV = unix.SYS_WRITEV + + // syscalls fptrace refers to but doesn't trace on + SYS_ACCESS = unix.SYS_ACCESS + SYS_FACCESSAT = unix.SYS_FACCESSAT +) diff --git a/syscalls/arm64.go b/syscalls/arm64.go new file mode 100644 index 0000000..787d241 --- /dev/null +++ b/syscalls/arm64.go @@ -0,0 +1,47 @@ +//go:build linux && arm64 +// +build linux,arm64 + +package syscalls + +import "golang.org/x/sys/unix" + +const ( + // specifies max syscall id that doesn't exist in this cpu architecture, but does in other ones + NOT_ON_THIS_ARCH_MAX = -1 + + SYS_CHDIR = unix.SYS_CHDIR + SYS_CLOSE = unix.SYS_CLOSE + SYS_DUP = unix.SYS_DUP + SYS_DUP2 = NOT_ON_THIS_ARCH_MAX - iota + SYS_DUP3 = unix.SYS_DUP3 + SYS_EXECVE = unix.SYS_EXECVE + SYS_EXECVEAT = unix.SYS_EXECVEAT + SYS_FCHDIR = unix.SYS_FCHDIR + SYS_FCNTL = unix.SYS_FCNTL + SYS_LINK = NOT_ON_THIS_ARCH_MAX - iota + SYS_LINKAT = unix.SYS_LINKAT + SYS_OPEN = NOT_ON_THIS_ARCH_MAX - iota + SYS_OPENAT = unix.SYS_OPENAT + SYS_PIPE = NOT_ON_THIS_ARCH_MAX - iota + SYS_PIPE2 = unix.SYS_PIPE2 + SYS_PREAD64 = unix.SYS_PREAD64 + SYS_PREADV = unix.SYS_PREADV + SYS_PREADV2 = unix.SYS_PREADV2 + SYS_PWRITE64 = unix.SYS_PWRITE64 + SYS_PWRITEV = unix.SYS_PWRITEV + SYS_PWRITEV2 = unix.SYS_PWRITEV2 + SYS_READ = unix.SYS_READ + SYS_READV = unix.SYS_READV + SYS_RENAME = NOT_ON_THIS_ARCH_MAX - iota + SYS_RENAMEAT = unix.SYS_RENAMEAT + SYS_RENAMEAT2 = unix.SYS_RENAMEAT2 + SYS_RMDIR = NOT_ON_THIS_ARCH_MAX - iota + SYS_UNLINK = NOT_ON_THIS_ARCH_MAX - iota + SYS_UNLINKAT = unix.SYS_UNLINKAT + SYS_WRITE = unix.SYS_WRITE + SYS_WRITEV = unix.SYS_WRITEV + + // syscalls fptrace refers to but doesn't trace on + SYS_ACCESS = NOT_ON_THIS_ARCH_MAX - iota + SYS_FACCESSAT = unix.SYS_FACCESSAT +) diff --git a/testcmd/testcmd.c b/testcmd/testcmd.c index 09def22..d22d045 100644 --- a/testcmd/testcmd.c +++ b/testcmd/testcmd.c @@ -9,7 +9,13 @@ #include #ifndef SYS_execveat -#define SYS_execveat 322 +# if defined(__aarch64__) +# define SYS_execveat 281 +# elif defined(__x86_64__) +# define SYS_execveat 322 +# else +# error Unknown architecture +# endif #endif int execer(void *arg) { diff --git a/trace.go b/trace.go index 47fd56d..319c777 100644 --- a/trace.go +++ b/trace.go @@ -14,16 +14,6 @@ import ( var errTraceeExited = errors.New("tracee failed to start") -func getRegs(pid int) (syscall.PtraceRegs, bool) { - var regs syscall.PtraceRegs - err := syscall.PtraceGetRegs(pid, ®s) - if err != nil && err.(syscall.Errno) == syscall.ESRCH { - return regs, false - } - e.Exit(err) - return regs, true -} - func readString(pid int, addr uint64) string { var chunk [64]byte var buf []byte