summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-20 22:43:32 +0300
committerPaul Buetow <paul@buetow.org>2026-05-20 22:43:32 +0300
commit6ca4d5ddacaff05d8bd82a5e9a6dfbb39ac111c9 (patch)
treea0b4469a9eb96bfb0b5a09d5f086219782040982 /cmd
parent7a9839917461b12c810329ccb8fd3c6de06902d2 (diff)
feat: add keyctl ptrace perf_event_open tracing (task 77)
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ioworkload/scenario_security.go134
-rw-r--r--cmd/ioworkload/scenario_security_test.go38
-rw-r--r--cmd/ioworkload/scenarios.go1
3 files changed, 173 insertions, 0 deletions
diff --git a/cmd/ioworkload/scenario_security.go b/cmd/ioworkload/scenario_security.go
new file mode 100644
index 0000000..e9e0fe8
--- /dev/null
+++ b/cmd/ioworkload/scenario_security.go
@@ -0,0 +1,134 @@
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+var keySpecProcessKeyringArg = ^uintptr(1)
+
+func securityKeysPtracePerf() error {
+ nr, err := securitySyscallNumbers(runtime.GOARCH)
+ if err != nil {
+ return err
+ }
+
+ // Best-effort probes: these syscalls may fail with EPERM/EACCES depending on
+ // policy, but the tracepoints are still exercised.
+ runKeySyscalls(nr)
+ runPtraceSyscall(nr)
+ runPerfEventOpenSyscall(nr)
+ return nil
+}
+
+type securitySyscalls struct {
+ addKey uintptr
+ requestKey uintptr
+ keyctl uintptr
+ ptrace uintptr
+ perfEventOpen uintptr
+}
+
+func securitySyscallNumbers(arch string) (securitySyscalls, error) {
+ switch arch {
+ case "amd64":
+ return securitySyscalls{
+ addKey: 248,
+ requestKey: 249,
+ keyctl: 250,
+ ptrace: 101,
+ perfEventOpen: 298,
+ }, nil
+ case "arm64":
+ return securitySyscalls{
+ addKey: 217,
+ requestKey: 218,
+ keyctl: 219,
+ ptrace: 117,
+ perfEventOpen: 241,
+ }, nil
+ default:
+ return securitySyscalls{}, fmt.Errorf("security syscall numbers not defined for GOARCH=%s", arch)
+ }
+}
+
+func runKeySyscalls(nr securitySyscalls) {
+ keyType, _ := syscall.BytePtrFromString("user")
+ desc, _ := syscall.BytePtrFromString("ior-key")
+ payload := []byte("ior")
+
+ var payloadPtr uintptr
+ if len(payload) > 0 {
+ payloadPtr = uintptr(unsafe.Pointer(&payload[0]))
+ }
+
+ _, _, _ = syscall.Syscall6(
+ nr.addKey,
+ uintptr(unsafe.Pointer(keyType)),
+ uintptr(unsafe.Pointer(desc)),
+ payloadPtr,
+ uintptr(len(payload)),
+ keySpecProcessKeyringArg,
+ 0,
+ )
+
+ _, _, _ = syscall.Syscall6(
+ nr.requestKey,
+ uintptr(unsafe.Pointer(keyType)),
+ uintptr(unsafe.Pointer(desc)),
+ 0,
+ keySpecProcessKeyringArg,
+ 0,
+ 0,
+ )
+
+ _, _, _ = syscall.Syscall6(
+ nr.keyctl,
+ 0,
+ keySpecProcessKeyringArg,
+ 0,
+ 0,
+ 0,
+ 0,
+ )
+}
+
+func runPtraceSyscall(nr securitySyscalls) {
+ _, _, _ = syscall.Syscall6(
+ nr.ptrace,
+ uintptr(syscall.PTRACE_TRACEME),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ )
+}
+
+type perfEventAttr struct {
+ Type uint32
+ Size uint32
+ Config uint64
+}
+
+func runPerfEventOpenSyscall(nr securitySyscalls) {
+ attr := perfEventAttr{
+ Type: 1, // PERF_TYPE_SOFTWARE
+ Size: uint32(unsafe.Sizeof(perfEventAttr{})),
+ Config: 0, // PERF_COUNT_SW_CPU_CLOCK
+ }
+ fd, _, _ := syscall.Syscall6(
+ nr.perfEventOpen,
+ uintptr(unsafe.Pointer(&attr)),
+ 0,
+ ^uintptr(0), // cpu = -1
+ ^uintptr(0), // group_fd = -1
+ 0,
+ 0,
+ )
+ if int64(fd) >= 0 {
+ _ = syscall.Close(int(fd))
+ }
+}
diff --git a/cmd/ioworkload/scenario_security_test.go b/cmd/ioworkload/scenario_security_test.go
new file mode 100644
index 0000000..f1b6152
--- /dev/null
+++ b/cmd/ioworkload/scenario_security_test.go
@@ -0,0 +1,38 @@
+package main
+
+import "testing"
+
+func TestSecuritySyscallNumbers(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ arch string
+ wantErr bool
+ addKey uintptr
+ ptrace uintptr
+ perf uintptr
+ }{
+ {name: "amd64", arch: "amd64", addKey: 248, ptrace: 101, perf: 298},
+ {name: "arm64", arch: "arm64", addKey: 217, ptrace: 117, perf: 241},
+ {name: "unsupported", arch: "riscv64", wantErr: true},
+ } {
+ got, err := securitySyscallNumbers(tc.arch)
+ if tc.wantErr {
+ if err == nil {
+ t.Fatalf("%s: expected error", tc.name)
+ }
+ continue
+ }
+ if err != nil {
+ t.Fatalf("%s: unexpected error: %v", tc.name, err)
+ }
+ if got.addKey != tc.addKey || got.ptrace != tc.ptrace || got.perfEventOpen != tc.perf {
+ t.Fatalf(
+ "%s: unexpected numbers add_key=%d ptrace=%d perf_event_open=%d",
+ tc.name,
+ got.addKey,
+ got.ptrace,
+ got.perfEventOpen,
+ )
+ }
+ }
+}
diff --git a/cmd/ioworkload/scenarios.go b/cmd/ioworkload/scenarios.go
index 7ca5aa4..a1039e0 100644
--- a/cmd/ioworkload/scenarios.go
+++ b/cmd/ioworkload/scenarios.go
@@ -111,6 +111,7 @@ var scenarios = map[string]func() error{
"truncate-ftruncate-ebadf": truncateFtruncateEbadf,
"pidfd-getfd-success": pidfdGetfdSuccess,
"pidfd-getfd-failure": pidfdGetfdFailure,
+ "security-keys-ptrace-perf": securityKeysPtracePerf,
"iouring-setup": iouringSetup,
"iouring-enter": iouringEnter,
"iouring-register": iouringRegister,