summaryrefslogtreecommitdiff
path: root/internal/generate
diff options
context:
space:
mode:
Diffstat (limited to 'internal/generate')
-rw-r--r--internal/generate/bpfhandler.go27
-rw-r--r--internal/generate/classify.go13
-rw-r--r--internal/generate/classify_test.go101
-rw-r--r--internal/generate/codegen_test.go61
-rw-r--r--internal/generate/kindregistry.go3
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.