From 81046c17e87f486e4a0d37966b03882545da6415 Mon Sep 17 00:00:00 2001 From: Kornilios Kourtis Date: Wed, 9 Oct 2024 18:32:38 +0200 Subject: [PATCH] syscalls: add ABI to syscall information This commit enables the new type for the syscall64 type. Specifically, it makes it so that we get a SyscallId event that includes both the ABI (64- or 32-bit) and the syscall id. Because this changes previous behaviour, we introduce a compatibility flag. Signed-off-by: Kornilios Kourtis --- contrib/upgrade-notes/latest.md | 23 +++++++++++++- docs/data/tetragon_flags.yaml | 4 +++ pkg/api/tracingapi/client_kprobe.go | 5 +++ pkg/encoder/encoder.go | 9 +++++- pkg/grpc/tracing/tracing.go | 8 +++++ pkg/option/config.go | 2 ++ pkg/option/flags.go | 6 ++++ pkg/sensors/tracing/enforcer_32bit_test.go | 18 ++++++++--- pkg/sensors/tracing/enforcer_test.go | 14 +++++++-- pkg/sensors/tracing/generictracepoint.go | 11 +++++-- pkg/sensors/tracing/syscall_list.go | 32 ++++++++++++++++++++ pkg/sensors/tracing/tracepoint_amd64_test.go | 6 ++-- pkg/sensors/tracing/tracepoint_test.go | 2 +- 13 files changed, 124 insertions(+), 16 deletions(-) diff --git a/contrib/upgrade-notes/latest.md b/contrib/upgrade-notes/latest.md index bebca62b221..e351e446056 100644 --- a/contrib/upgrade-notes/latest.md +++ b/contrib/upgrade-notes/latest.md @@ -19,7 +19,28 @@ Depending on your setup, changes listed here might require a manual intervention ### Events (protobuf API) -* TBD + +#### New events for `syscall64` type + +Previous versions of Tetragon did not distinguish between different ABIs when using the syscall64 type +because the output was just a `size_arg` with the id. When executing the `getcpu` syscall, for example, the JSON +for 64- and 32-bits would be: +``` +"args":[{"size_arg":"309"}] +"args":[{"size_arg":"318"}] +``` + +Note that id 318 for `x86_64` is a different syscall: `getrandom` so we cannot distinguish between a `getrandom` syscall on x86_64 +and a `getcpu` call on 32-bit (`i386`). To address this issue, the output of `syscall64` was changed to a `SyscallId` object that +also includes the ABI. So the JSON for 64- and 32-bits `getcpu` now is: + +``` +"args":[{"syscall_id":{"id":309,"abi":"x64"}}] +"args":[{"syscall_id":{"id":318,"abi":"i386"}}] +``` + +Users that want to maintain the old behavior can use the `--enable-compatibility-syscall64-size-type` flag for this version. +The flag will be removed in v1.4. ### Metrics diff --git a/docs/data/tetragon_flags.yaml b/docs/data/tetragon_flags.yaml index a023cbc756f..8fc0669b483 100644 --- a/docs/data/tetragon_flags.yaml +++ b/docs/data/tetragon_flags.yaml @@ -36,6 +36,10 @@ options: - name: enable-cgidmap-debug default_value: "false" usage: enable cgidmap debugging info + - name: enable-compatibility-syscall64-size-type + default_value: "false" + usage: | + syscall64 type will produce output of type size (compatibility flag, will be removed in v1.4) - name: enable-cri default_value: "false" usage: enable CRI client for tetragon diff --git a/pkg/api/tracingapi/client_kprobe.go b/pkg/api/tracingapi/client_kprobe.go index f7ed3da2f90..f8a609484e2 100644 --- a/pkg/api/tracingapi/client_kprobe.go +++ b/pkg/api/tracingapi/client_kprobe.go @@ -246,6 +246,11 @@ type MsgGenericKprobeArgSkb struct { Label string } +type MsgGenericSyscallID struct { + ID uint32 + ABI string +} + func (m MsgGenericKprobeArgSkb) GetIndex() uint64 { return m.Index } diff --git a/pkg/encoder/encoder.go b/pkg/encoder/encoder.go index 3cadd62a979..5e35394e6e6 100644 --- a/pkg/encoder/encoder.go +++ b/pkg/encoder/encoder.go @@ -564,20 +564,27 @@ func (p *CompactEncoder) EventToString(response *tetragon.GetEventsResponse) (st func rawSyscallEnter(tp *tetragon.ProcessTracepoint) string { sysID := int64(-1) - abi, err := syscallinfo.DefaultABI() + defaultABI, err := syscallinfo.DefaultABI() if err != nil { return "unknown" } + abi := defaultABI // we assume that the syscall id is in the first argument if len(tp.Args) > 0 && tp.Args[0] != nil { if x, ok := tp.Args[0].GetArg().(*tetragon.KprobeArgument_LongArg); ok { sysID = x.LongArg + } else if x, ok := tp.Args[0].GetArg().(*tetragon.KprobeArgument_SyscallId); ok { + sysID = int64(x.SyscallId.Id) + abi = x.SyscallId.Abi } } sysName := "unknown" if name, _ := syscallinfo.GetSyscallName(abi, int(sysID)); name != "" { sysName = name + if abi != defaultABI { + sysName = fmt.Sprintf("%s/%s", abi, sysName) + } sysArgs, ok := syscallinfo.GetSyscallArgs(sysName) if ok { sysName += "(" diff --git a/pkg/grpc/tracing/tracing.go b/pkg/grpc/tracing/tracing.go index fd581096252..052b957659c 100644 --- a/pkg/grpc/tracing/tracing.go +++ b/pkg/grpc/tracing/tracing.go @@ -524,6 +524,14 @@ func (msg *MsgGenericTracepointUnix) HandleMessage() *tetragon.GetEventsResponse SockArg: &sk, }}) + case tracingapi.MsgGenericSyscallID: + tetragonArgs = append(tetragonArgs, &tetragon.KprobeArgument{Arg: &tetragon.KprobeArgument_SyscallId{ + SyscallId: &tetragon.SyscallId{ + Id: v.ID, + Abi: v.ABI, + }, + }}) + default: logger.GetLogger().Warnf("handleGenericTracepointMessage: unhandled value: %+v (%T)", arg, arg) } diff --git a/pkg/option/config.go b/pkg/option/config.go index 924a588c7a2..5078bc39218 100644 --- a/pkg/option/config.go +++ b/pkg/option/config.go @@ -104,6 +104,8 @@ type config struct { EventCacheNumRetries int EventCacheRetryDelay int + + CompatibilitySyscall64SizeType bool } var ( diff --git a/pkg/option/flags.go b/pkg/option/flags.go index b2a6b9e1aae..1ae4db596dd 100644 --- a/pkg/option/flags.go +++ b/pkg/option/flags.go @@ -115,6 +115,8 @@ const ( KeyEventCacheRetries = "event-cache-retries" KeyEventCacheRetryDelay = "event-cache-retry-delay" + + KeyCompatibilitySyscall64SizeType = "enable-compatibility-syscall64-size-type" ) type UsernameMetadaCode int @@ -245,6 +247,8 @@ func ReadAndSetFlags() error { Config.EventCacheNumRetries = viper.GetInt(KeyEventCacheRetries) Config.EventCacheRetryDelay = viper.GetInt(KeyEventCacheRetryDelay) + Config.CompatibilitySyscall64SizeType = viper.GetBool(KeyCompatibilitySyscall64SizeType) + return nil } @@ -411,4 +415,6 @@ func AddFlags(flags *pflag.FlagSet) { flags.Int(KeyEventCacheRetries, defaults.DefaultEventCacheNumRetries, "Number of retries for event cache") flags.Int(KeyEventCacheRetryDelay, defaults.DefaultEventCacheRetryDelay, "Delay in seconds between event cache retries") + + flags.Bool(KeyCompatibilitySyscall64SizeType, false, "syscall64 type will produce output of type size (compatibility flag, will be removed in v1.4)") } diff --git a/pkg/sensors/tracing/enforcer_32bit_test.go b/pkg/sensors/tracing/enforcer_32bit_test.go index ffe09057d72..a87baf5a254 100644 --- a/pkg/sensors/tracing/enforcer_32bit_test.go +++ b/pkg/sensors/tracing/enforcer_32bit_test.go @@ -11,6 +11,7 @@ import ( "github.com/cilium/tetragon/api/v1/tetragon" ec "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker" lc "github.com/cilium/tetragon/pkg/matchers/listmatcher" + sm "github.com/cilium/tetragon/pkg/matchers/stringmatcher" "github.com/cilium/tetragon/pkg/syscallinfo/arm32" "github.com/cilium/tetragon/pkg/syscallinfo/i386" "github.com/cilium/tetragon/pkg/testutils" @@ -21,13 +22,16 @@ func TestEnforcerOverride32(t *testing.T) { prctlID := uint64(0) var syscallVal string + sysIDChecker := ec.NewSyscallIdChecker() switch a := runtime.GOARCH; a { case "amd64": syscallVal = "i386/sys_prctl" prctlID = i386.SYS_PRCTL + sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("i386")) case "arm64": syscallVal = "arm32/sys_prctl" prctlID = arm32.SYS_PRCTL + sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("arm32")) default: t.Fatalf("Unknown arch: %s", a) } @@ -43,7 +47,7 @@ func TestEnforcerOverride32(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(prctlID), + ec.NewKprobeArgumentChecker().WithSyscallId(sysIDChecker), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) @@ -62,13 +66,16 @@ func TestEnforcerSignal32(t *testing.T) { prctlID := uint64(0) var syscallVal string + sysIDChecker := ec.NewSyscallIdChecker() switch a := runtime.GOARCH; a { case "amd64": syscallVal = "i386/sys_prctl" prctlID = i386.SYS_PRCTL + sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("i386")) case "arm64": syscallVal = "arm32/sys_prctl" prctlID = arm32.SYS_PRCTL + sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("arm32")) default: t.Fatalf("Unknown arch: %s", a) } @@ -85,7 +92,7 @@ func TestEnforcerSignal32(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(prctlID), + ec.NewKprobeArgumentChecker().WithSyscallId(sysIDChecker), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) @@ -105,13 +112,16 @@ func TestEnforcerOverrideBothBits(t *testing.T) { prctlID := uint64(0) var syscallVal string + sysIDChecker32 := ec.NewSyscallIdChecker() switch a := runtime.GOARCH; a { case "amd64": syscallVal = "i386/sys_prctl" prctlID = i386.SYS_PRCTL + sysIDChecker32 = sysIDChecker32.WithId(uint32(prctlID)).WithAbi(sm.Full("i386")) case "arm64": syscallVal = "arm32/sys_prctl" prctlID = arm32.SYS_PRCTL + sysIDChecker32 = sysIDChecker32.WithId(uint32(prctlID)).WithAbi(sm.Full("arm32")) default: t.Fatalf("Unknown arch: %s", a) } @@ -129,7 +139,7 @@ func TestEnforcerOverrideBothBits(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(prctlID), + ec.NewKprobeArgumentChecker().WithSyscallId(sysIDChecker32), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) @@ -137,7 +147,7 @@ func TestEnforcerOverrideBothBits(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_PRCTL), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_PRCTL)), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) diff --git a/pkg/sensors/tracing/enforcer_test.go b/pkg/sensors/tracing/enforcer_test.go index 732bc1d0d05..558a8c29fb4 100644 --- a/pkg/sensors/tracing/enforcer_test.go +++ b/pkg/sensors/tracing/enforcer_test.go @@ -27,10 +27,12 @@ import ( "github.com/cilium/tetragon/pkg/policyfilter" "github.com/cilium/tetragon/pkg/sensors" "github.com/cilium/tetragon/pkg/sensors/base" + "github.com/cilium/tetragon/pkg/syscallinfo" "github.com/cilium/tetragon/pkg/testutils" tus "github.com/cilium/tetragon/pkg/testutils/sensors" "github.com/cilium/tetragon/pkg/tracingpolicy" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/sys/unix" ) @@ -102,7 +104,7 @@ func TestEnforcerOverride(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(unix.SYS_GETCPU), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, unix.SYS_GETCPU)), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) @@ -156,7 +158,7 @@ func TestEnforcerOverrideManySyscalls(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(unix.SYS_GETCPU), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, unix.SYS_GETCPU)), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) @@ -195,6 +197,12 @@ func TestEnforcerOverrideManySyscalls(t *testing.T) { }) } +func mkSysIDChecker(t *testing.T, id uint64) *ec.SyscallIdChecker { + abi, err := syscallinfo.DefaultABI() + require.NoError(t, err) + return ec.NewSyscallIdChecker().WithId(uint32(id)).WithAbi(sm.Full(abi)) +} + func TestEnforcerSignal(t *testing.T) { testEnforcerCheckSkip(t) @@ -204,7 +212,7 @@ func TestEnforcerSignal(t *testing.T) { WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_PRCTL), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_PRCTL)), )). WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER) diff --git a/pkg/sensors/tracing/generictracepoint.go b/pkg/sensors/tracing/generictracepoint.go index 3f69b70b508..3eb6ffd1d96 100644 --- a/pkg/sensors/tracing/generictracepoint.go +++ b/pkg/sensors/tracing/generictracepoint.go @@ -832,9 +832,14 @@ func handleMsgGenericTracepoint( if err != nil { logger.GetLogger().WithError(err).Warnf("Size type error sizeof %d", m.Common.Size) } - // NB: clear Is32Bit to mantain previous behaviour - val = val & (^uint64(Is32Bit)) - unix.Args = append(unix.Args, val) + if option.Config.CompatibilitySyscall64SizeType { + // NB: clear Is32Bit to mantain previous behaviour + val = val & (^uint64(Is32Bit)) + unix.Args = append(unix.Args, val) + } else { + val := parseSyscall64Value(val) + unix.Args = append(unix.Args, val) + } default: logger.GetLogger().Warnf("handleGenericTracepoint: ignoring: %+v", out) diff --git a/pkg/sensors/tracing/syscall_list.go b/pkg/sensors/tracing/syscall_list.go index fb45dc8fe40..c2fee24c6c1 100644 --- a/pkg/sensors/tracing/syscall_list.go +++ b/pkg/sensors/tracing/syscall_list.go @@ -5,8 +5,10 @@ package tracing import ( "fmt" + "runtime" "strings" + "github.com/cilium/tetragon/pkg/api/tracingapi" "github.com/cilium/tetragon/pkg/arch" "github.com/cilium/tetragon/pkg/syscallinfo" ) @@ -93,6 +95,36 @@ func validateABI(xarg, abi string) error { return nil } +// returns abi, syscall id +func parseSyscall64Value(val uint64) tracingapi.MsgGenericSyscallID { + abi32 := false + if val&Is32Bit != 0 { + abi32 = true + val = val & (^uint64(Is32Bit)) + } + + abi := "unknown" + switch a := runtime.GOARCH; a { + case "amd64": + if abi32 { + abi = "i386" + } else { + abi = "x64" + } + case "arm64": + if abi32 { + abi = "arm32" + } else { + abi = "arm64" + } + } + + return tracingapi.MsgGenericSyscallID{ + ID: uint32(val), + ABI: abi, + } +} + func parseSyscallValue(value SyscallVal) (abi string, name string, err error) { val := string(value) arr := strings.Split(string(val), "/") diff --git a/pkg/sensors/tracing/tracepoint_amd64_test.go b/pkg/sensors/tracing/tracepoint_amd64_test.go index 711b1386e3a..0c298c43586 100644 --- a/pkg/sensors/tracing/tracepoint_amd64_test.go +++ b/pkg/sensors/tracing/tracepoint_amd64_test.go @@ -104,7 +104,7 @@ spec: WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_DUP)), ec.NewKprobeArgumentChecker().WithSizeArg(9999), )) @@ -112,7 +112,7 @@ spec: WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP2), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_DUP2)), ec.NewKprobeArgumentChecker().WithSizeArg(9999), )) @@ -120,7 +120,7 @@ spec: WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP3), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_DUP3)), ec.NewKprobeArgumentChecker().WithSizeArg(9999), )) diff --git a/pkg/sensors/tracing/tracepoint_test.go b/pkg/sensors/tracing/tracepoint_test.go index bdb78f6de26..a672c429e5c 100644 --- a/pkg/sensors/tracing/tracepoint_test.go +++ b/pkg/sensors/tracing/tracepoint_test.go @@ -860,7 +860,7 @@ spec: WithArgs(ec.NewKprobeArgumentListMatcher(). WithOperator(lc.Ordered). WithValues( - ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP), + ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, unix.SYS_DUP)), ec.NewKprobeArgumentChecker().WithSizeArg(uint64(i)), ))