diff options
Diffstat (limited to 'internal/generate')
| -rw-r--r-- | internal/generate/bpfhandler.go | 27 | ||||
| -rw-r--r-- | internal/generate/classify.go | 13 | ||||
| -rw-r--r-- | internal/generate/classify_test.go | 101 | ||||
| -rw-r--r-- | internal/generate/codegen_test.go | 61 | ||||
| -rw-r--r-- | internal/generate/kindregistry.go | 3 |
5 files changed, 204 insertions, 1 deletions
diff --git a/internal/generate/bpfhandler.go b/internal/generate/bpfhandler.go index 57f635a..b166725 100644 --- a/internal/generate/bpfhandler.go +++ b/internal/generate/bpfhandler.go @@ -101,6 +101,12 @@ func generateExtra(tp GeneratedTracepoint, isEnter bool) string { return generateExtraMem(f.Name) case KindSleep: return generateExtraSleep(f.Name) + case KindKeyctl: + return generateExtraKeyctl(f.Name) + case KindPtrace: + return generateExtraPtrace() + case KindPerfOpen: + return generateExtraPerfOpen() case KindOpen: return generateExtraOpen(f) case KindMqOpen: @@ -282,6 +288,27 @@ func generateExtraSleep(name string) string { return " ev->requested_ns = -1;\n if (" + ptrExpr + " != 0) {\n struct __ior_timespec {\n __s64 tv_sec;\n __s64 tv_nsec;\n } ts = {};\n if (bpf_probe_read_user(&ts, sizeof(ts), (void *)" + ptrExpr + ") == 0) {\n ev->requested_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;\n }\n }\n" } +func generateExtraKeyctl(name string) string { + switch name { + case "sys_enter_keyctl": + return " ev->option = (__s32)ctx->args[0];\n ev->key_serial = (__s32)ctx->args[1];\n ev->value = (__u64)ctx->args[2];\n" + case "sys_enter_add_key": + return " ev->option = -1;\n ev->key_serial = (__s32)ctx->args[4];\n ev->value = (__u64)ctx->args[3];\n" + case "sys_enter_request_key": + return " ev->option = -2;\n ev->key_serial = (__s32)ctx->args[3];\n ev->value = 0;\n" + default: + return " ev->option = 0;\n ev->key_serial = 0;\n ev->value = 0;\n" + } +} + +func generateExtraPtrace() string { + return " ev->request = (__s64)ctx->args[0];\n ev->target_pid = (__s32)ctx->args[1];\n ev->data = (__u64)ctx->args[3];\n" +} + +func generateExtraPerfOpen() string { + return " ev->attr_type = 0;\n ev->attr_size = 0;\n ev->config = 0;\n if (ctx->args[0] != 0) {\n struct __ior_perf_event_attr {\n __u32 type;\n __u32 size;\n __u64 config;\n } attr = {};\n if (bpf_probe_read_user(&attr, sizeof(attr), (void *)ctx->args[0]) == 0) {\n ev->attr_type = attr.type;\n ev->attr_size = attr.size;\n ev->config = attr.config;\n }\n }\n ev->target_pid = (__s32)ctx->args[1];\n ev->cpu = (__s32)ctx->args[2];\n ev->group_fd = (__s32)ctx->args[3];\n ev->flags = (__u32)ctx->args[4];\n" +} + // eventStructName returns the C struct name for a TracepointKind. The mapping // is driven by kindRegistry so adding a new kind only requires a registry entry. func eventStructName(kind TracepointKind) string { diff --git a/internal/generate/classify.go b/internal/generate/classify.go index 4afc035..77bab7e 100644 --- a/internal/generate/classify.go +++ b/internal/generate/classify.go @@ -26,6 +26,9 @@ const ( KindPoll KindMem KindSleep + KindKeyctl + KindPtrace + KindPerfOpen ) type RetClassification string @@ -172,6 +175,16 @@ func classifyNameOnly(name string) (ClassificationResult, bool) { return ClassificationResult{Kind: KindSleep}, true case "sys_enter_clock_nanosleep": return ClassificationResult{Kind: KindSleep}, true + case "sys_enter_keyctl": + return ClassificationResult{Kind: KindKeyctl}, true + case "sys_enter_add_key": + return ClassificationResult{Kind: KindKeyctl}, true + case "sys_enter_request_key": + return ClassificationResult{Kind: KindKeyctl}, true + case "sys_enter_ptrace": + return ClassificationResult{Kind: KindPtrace}, true + case "sys_enter_perf_event_open": + return ClassificationResult{Kind: KindPerfOpen}, true case "sys_enter_mq_timedsend": return ClassificationResult{Kind: KindFd}, true case "sys_enter_mq_timedreceive": diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go index 5eef40f..2a12911 100644 --- a/internal/generate/classify_test.go +++ b/internal/generate/classify_test.go @@ -1,6 +1,7 @@ package generate import ( + "strconv" "strings" "testing" ) @@ -453,6 +454,84 @@ func TestClassifyClockNanosleep(t *testing.T) { } } +func TestClassifyKeyctl(t *testing.T) { + r := ClassifyFormat(&Format{ + Name: "sys_enter_keyctl", + ExternalFields: []Field{ + {Type: "long", Name: "__syscall_nr"}, + {Type: "int", Name: "option"}, + {Type: "key_serial_t", Name: "arg2"}, + }, + }) + if r.Kind != KindKeyctl { + t.Errorf("keyctl: got kind %d, want KindKeyctl", r.Kind) + } +} + +func TestClassifyAddKey(t *testing.T) { + r := ClassifyFormat(&Format{ + Name: "sys_enter_add_key", + ExternalFields: []Field{ + {Type: "long", Name: "__syscall_nr"}, + {Type: "const char *", Name: "_type"}, + {Type: "const char *", Name: "_description"}, + {Type: "const void *", Name: "_payload"}, + {Type: "size_t", Name: "plen"}, + {Type: "key_serial_t", Name: "ringid"}, + }, + }) + if r.Kind != KindKeyctl { + t.Errorf("add_key: got kind %d, want KindKeyctl", r.Kind) + } +} + +func TestClassifyRequestKey(t *testing.T) { + r := ClassifyFormat(&Format{ + Name: "sys_enter_request_key", + ExternalFields: []Field{ + {Type: "long", Name: "__syscall_nr"}, + {Type: "const char *", Name: "_type"}, + {Type: "const char *", Name: "_description"}, + {Type: "const char *", Name: "_callout_info"}, + {Type: "key_serial_t", Name: "destringid"}, + }, + }) + if r.Kind != KindKeyctl { + t.Errorf("request_key: got kind %d, want KindKeyctl", r.Kind) + } +} + +func TestClassifyPtrace(t *testing.T) { + r := ClassifyFormat(&Format{ + Name: "sys_enter_ptrace", + ExternalFields: []Field{ + {Type: "long", Name: "__syscall_nr"}, + {Type: "long", Name: "request"}, + {Type: "long", Name: "pid"}, + }, + }) + if r.Kind != KindPtrace { + t.Errorf("ptrace: got kind %d, want KindPtrace", r.Kind) + } +} + +func TestClassifyPerfEventOpen(t *testing.T) { + r := ClassifyFormat(&Format{ + Name: "sys_enter_perf_event_open", + ExternalFields: []Field{ + {Type: "long", Name: "__syscall_nr"}, + {Type: "struct perf_event_attr *", Name: "attr_uptr"}, + {Type: "pid_t", Name: "pid"}, + {Type: "int", Name: "cpu"}, + {Type: "int", Name: "group_fd"}, + {Type: "unsigned long", Name: "flags"}, + }, + }) + if r.Kind != KindPerfOpen { + t.Errorf("perf_event_open: got kind %d, want KindPerfOpen", r.Kind) + } +} + func TestClassifyMqOpen(t *testing.T) { r := ClassifyFormat(&Format{ Name: "sys_enter_mq_open", @@ -664,6 +743,11 @@ func TestClassifySyscallPairAccepted(t *testing.T) { {"mremap", FormatMremap, FormatExitMremap, KindMem}, {"nanosleep", FormatNanosleep, FormatExitNanosleep, KindSleep}, {"clock_nanosleep", FormatClockNanosleep, FormatExitClockNanosleep, KindSleep}, + {"keyctl", syntheticEnter("keyctl", 9200), syntheticExit("keyctl", 9199), KindKeyctl}, + {"add_key", syntheticEnter("add_key", 9202), syntheticExit("add_key", 9201), KindKeyctl}, + {"request_key", syntheticEnter("request_key", 9204), syntheticExit("request_key", 9203), KindKeyctl}, + {"ptrace", syntheticEnter("ptrace", 9206), syntheticExit("ptrace", 9205), KindPtrace}, + {"perf_event_open", syntheticEnter("perf_event_open", 9208), syntheticExit("perf_event_open", 9207), KindPerfOpen}, {"mount", FormatMount, FormatExitMount, KindPathname}, {"umount", FormatUmount, FormatExitUmount, KindPathname}, {"move_mount", FormatMoveMount, FormatExitMoveMount, KindTwoFd}, @@ -716,6 +800,11 @@ func TestClassifySyscallPairEmitsAllFamilies(t *testing.T) { {"mremap", FormatMremap, FormatExitMremap, FamilyMemory}, {"nanosleep", FormatNanosleep, FormatExitNanosleep, FamilyTime}, {"clock_nanosleep", FormatClockNanosleep, FormatExitClockNanosleep, FamilyTime}, + {"keyctl", syntheticEnter("keyctl", 9300), syntheticExit("keyctl", 9299), FamilySecurity}, + {"add_key", syntheticEnter("add_key", 9302), syntheticExit("add_key", 9301), FamilySecurity}, + {"request_key", syntheticEnter("request_key", 9304), syntheticExit("request_key", 9303), FamilySecurity}, + {"ptrace", syntheticEnter("ptrace", 9306), syntheticExit("ptrace", 9305), FamilySecurity}, + {"perf_event_open", syntheticEnter("perf_event_open", 9308), syntheticExit("perf_event_open", 9307), FamilySecurity}, {"mount", FormatMount, FormatExitMount, FamilyFS}, {"umount", FormatUmount, FormatExitUmount, FamilyFS}, {"move_mount", FormatMoveMount, FormatExitMoveMount, FamilyFS}, @@ -893,6 +982,18 @@ func mqFormats(name string, enterID int) []Format { } } +func syntheticEnter(syscall string, id int) string { + return strings.Replace(strings.Replace(FormatKill, "sys_enter_kill", "sys_enter_"+syscall, 1), "ID: 183", "ID: "+itoa(id), 1) +} + +func syntheticExit(syscall string, id int) string { + return strings.Replace(strings.Replace(FormatExitKill, "sys_exit_kill", "sys_exit_"+syscall, 1), "ID: 182", "ID: "+itoa(id), 1) +} + +func itoa(v int) string { + return strconv.Itoa(v) +} + func TestClassifyFormatNoExternalFields(t *testing.T) { f := &Format{ Name: "sys_enter_test", diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index 7ad076f..f1c98df 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -361,6 +361,59 @@ func TestGenerateClockNanosleepHandlerCapturesRequestedTimespec(t *testing.T) { requireContains(t, output, "ev->requested_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;") } +func TestGenerateKeyctlHandler(t *testing.T) { + output := GenerateTracepointsC(mustParseAll(t, syntheticPair("keyctl"))) + + requireContains(t, output, "struct keyctl_event *ev") + requireContains(t, output, "ev->event_type = ENTER_KEYCTL_EVENT;") + requireContains(t, output, "ev->option = (__s32)ctx->args[0];") + requireContains(t, output, "ev->key_serial = (__s32)ctx->args[1];") + requireContains(t, output, "ev->value = (__u64)ctx->args[2];") + requireContains(t, output, "ev->event_type = EXIT_RET_EVENT;") +} + +func TestGenerateAddKeyHandler(t *testing.T) { + output := GenerateTracepointsC(mustParseAll(t, syntheticPair("add_key"))) + + requireContains(t, output, "struct keyctl_event *ev") + requireContains(t, output, "ev->event_type = ENTER_KEYCTL_EVENT;") + requireContains(t, output, "ev->option = -1;") + requireContains(t, output, "ev->key_serial = (__s32)ctx->args[4];") + requireContains(t, output, "ev->value = (__u64)ctx->args[3];") +} + +func TestGenerateRequestKeyHandler(t *testing.T) { + output := GenerateTracepointsC(mustParseAll(t, syntheticPair("request_key"))) + + requireContains(t, output, "struct keyctl_event *ev") + requireContains(t, output, "ev->event_type = ENTER_KEYCTL_EVENT;") + requireContains(t, output, "ev->option = -2;") + requireContains(t, output, "ev->key_serial = (__s32)ctx->args[3];") +} + +func TestGeneratePtraceHandler(t *testing.T) { + output := GenerateTracepointsC(mustParseAll(t, syntheticPair("ptrace"))) + + requireContains(t, output, "struct ptrace_event *ev") + requireContains(t, output, "ev->event_type = ENTER_PTRACE_EVENT;") + requireContains(t, output, "ev->request = (__s64)ctx->args[0];") + requireContains(t, output, "ev->target_pid = (__s32)ctx->args[1];") + requireContains(t, output, "ev->data = (__u64)ctx->args[3];") +} + +func TestGeneratePerfEventOpenHandler(t *testing.T) { + output := GenerateTracepointsC(mustParseAll(t, syntheticPair("perf_event_open"))) + + requireContains(t, output, "struct perf_open_event *ev") + requireContains(t, output, "ev->event_type = ENTER_PERF_OPEN_EVENT;") + requireContains(t, output, "struct __ior_perf_event_attr {") + requireContains(t, output, "ev->attr_type = attr.type;") + requireContains(t, output, "ev->config = attr.config;") + requireContains(t, output, "ev->target_pid = (__s32)ctx->args[1];") + requireContains(t, output, "ev->group_fd = (__s32)ctx->args[3];") + requireContains(t, output, "ev->event_type = EXIT_RET_EVENT;") +} + func TestGenerateNameToHandleAtHandler(t *testing.T) { output := generateFromPair(t, FormatNameToHandleAt, FormatExitNameToHandleAt) @@ -479,6 +532,9 @@ func TestGenerateAllEventTypes(t *testing.T) { {KindPoll, "ENTER_POLL_EVENT", "EXIT_POLL_EVENT"}, {KindMem, "ENTER_MEM_EVENT", "EXIT_MEM_EVENT"}, {KindSleep, "ENTER_SLEEP_EVENT", "EXIT_SLEEP_EVENT"}, + {KindKeyctl, "ENTER_KEYCTL_EVENT", "EXIT_KEYCTL_EVENT"}, + {KindPtrace, "ENTER_PTRACE_EVENT", "EXIT_PTRACE_EVENT"}, + {KindPerfOpen, "ENTER_PERF_OPEN_EVENT", "EXIT_PERF_OPEN_EVENT"}, } for _, tt := range tests { @@ -516,6 +572,9 @@ func TestEventStructNames(t *testing.T) { {KindPoll, "poll_event"}, {KindMem, "mem_event"}, {KindSleep, "sleep_event"}, + {KindKeyctl, "keyctl_event"}, + {KindPtrace, "ptrace_event"}, + {KindPerfOpen, "perf_open_event"}, } for _, tt := range tests { @@ -534,7 +593,7 @@ func TestEnterReject(t *testing.T) { t.Error("KindNone should be enter-rejected") } - accepted := []TracepointKind{KindFd, KindOpen, KindMqOpen, KindPathname, KindName, KindFcntl, KindNull, KindDup3, KindOpenByHandleAt, KindSocket, KindSocketpair, KindAccept, KindPipe, KindEventfd, KindEpollCtl, KindTwoFd, KindPoll, KindMem, KindSleep} + accepted := []TracepointKind{KindFd, KindOpen, KindMqOpen, KindPathname, KindName, KindFcntl, KindNull, KindDup3, KindOpenByHandleAt, KindSocket, KindSocketpair, KindAccept, KindPipe, KindEventfd, KindEpollCtl, KindTwoFd, KindPoll, KindMem, KindSleep, KindKeyctl, KindPtrace, KindPerfOpen} for _, k := range accepted { if isEnterRejected(k) { t.Errorf("kind %d should NOT be enter-rejected", k) diff --git a/internal/generate/kindregistry.go b/internal/generate/kindregistry.go index 188beb0..6afe4c1 100644 --- a/internal/generate/kindregistry.go +++ b/internal/generate/kindregistry.go @@ -36,6 +36,9 @@ var kindRegistry = map[TracepointKind]kindMeta{ KindPoll: {structName: "poll_event", enterAccepted: true}, KindMem: {structName: "mem_event", enterAccepted: true}, KindSleep: {structName: "sleep_event", enterAccepted: true}, + KindKeyctl: {structName: "keyctl_event", enterAccepted: true}, + KindPtrace: {structName: "ptrace_event", enterAccepted: true}, + KindPerfOpen: {structName: "perf_open_event", enterAccepted: true}, // KindNone is intentionally absent: it represents "unclassified" and is // never enter-accepted. lookupKind returns the zero kindMeta (enterAccepted=false) // for any unregistered kind, so KindNone is implicitly rejected. |
