From 338b1ed03ca2d8e75ceaace932b37f2bbecb16b5 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Wed, 25 Sep 2024 09:43:34 +0100 Subject: [PATCH] kprobes: add userspace types used for pretty printing Suggested by Jiri. Introduce userspace types that will be used for pretty printing. This allows to add different enum types into proto definition, have a high level representation that allows to pretty print data to users without propagating those same types into bpf part. We define the bpfCmd enum in proto, add its type in userspace, but we do not propagate this into kernel, we just keep using int types for kernel and we do the translation back into userspace where it makes sense. Suggested-by: Jiri Olsa Signed-off-by: Djalal Harouni --- pkg/api/tracingapi/client_kprobe.go | 7 +++-- pkg/btf/validation.go | 2 +- pkg/generictypes/generictypes.go | 42 ++++++++++++++++++++++++++++ pkg/sensors/tracing/args.go | 17 +++++++---- pkg/sensors/tracing/generickprobe.go | 15 ++++++++-- 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/pkg/api/tracingapi/client_kprobe.go b/pkg/api/tracingapi/client_kprobe.go index b94db1a697d..f7ed3da2f90 100644 --- a/pkg/api/tracingapi/client_kprobe.go +++ b/pkg/api/tracingapi/client_kprobe.go @@ -120,9 +120,10 @@ func (m MsgGenericKprobeArgBytes) IsReturnArg() bool { } type MsgGenericKprobeArgInt struct { - Index uint64 - Value int32 - Label string + Index uint64 + Value int32 + UserSpaceType int32 + Label string } func (m MsgGenericKprobeArgInt) GetIndex() uint64 { diff --git a/pkg/btf/validation.go b/pkg/btf/validation.go index ec8a55e58e2..83eba5222d9 100644 --- a/pkg/btf/validation.go +++ b/pkg/btf/validation.go @@ -335,7 +335,7 @@ func typesCompatible(specTy string, kernelTy string) bool { case "struct user_namespace *": return true } - case "capability": + case "capability", "bpf_cmd": switch kernelTy { case "int": return true diff --git a/pkg/generictypes/generictypes.go b/pkg/generictypes/generictypes.go index d9f0d99e44c..ac84bf0c21f 100644 --- a/pkg/generictypes/generictypes.go +++ b/pkg/generictypes/generictypes.go @@ -61,6 +61,11 @@ const ( GenericInvalidType = -2 ) +// Userspace pretty printer types. +const ( + GenericUserBpfCmdType = 1 +) + var GenericStringToType = map[string]int{ "string": GenericStringType, "int": GenericIntType, @@ -153,6 +158,35 @@ var GenericTypeToStringTable = map[int]string{ GenericInvalidType: "", } +var GenericUserStringToType = map[string]int{ + "bpf_cmd": GenericUserBpfCmdType, +} + +var GenericUserToKernel = map[int]int{ + GenericUserBpfCmdType: GenericIntType, +} + +var GenericUserTypeToStringTable = map[int]string{ + GenericUserBpfCmdType: "bpf_cmd", + GenericInvalidType: "", +} + +func GenericUserTypeFromString(arg string) int { + ty, ok := GenericUserStringToType[arg] + if !ok { + ty = GenericInvalidType + } + return ty +} + +func GenericUserToKernelType(arg int) int { + ty, ok := GenericUserToKernel[arg] + if !ok { + ty = GenericInvalidType + } + return ty +} + func GenericTypeFromString(arg string) int { ty, ok := GenericStringToType[arg] if !ok { @@ -161,6 +195,14 @@ func GenericTypeFromString(arg string) int { return ty } +// GenericUserTypeToString() converts the passed argument type +// to its string representation. +// Returns empty string on non valid types. +func GenericUserTypeToString(ty int) string { + arg, _ := GenericUserTypeToStringTable[ty] + return arg +} + func GenericTypeToString(ty int) (string, error) { arg, ok := GenericTypeToStringTable[ty] if !ok { diff --git a/pkg/sensors/tracing/args.go b/pkg/sensors/tracing/args.go index f9a673cf596..6b51d682412 100644 --- a/pkg/sensors/tracing/args.go +++ b/pkg/sensors/tracing/args.go @@ -23,10 +23,11 @@ import ( ) type argPrinter struct { - ty int - index int - maxData bool - label string + ty int + userType int + index int + maxData bool + label string } const ( @@ -82,9 +83,15 @@ func getArg(r *bytes.Reader, a argPrinter) api.MsgGenericKprobeArg { var output int32 var arg api.MsgGenericKprobeArgInt + if a.userType != gt.GenericInvalidType { + arg.UserSpaceType = int32(a.userType) + } + err := binary.Read(r, binary.LittleEndian, &output) if err != nil { - logger.GetLogger().WithError(err).Warnf("Int type error") + logger.GetLogger(). + WithField("arg.usertype", gt.GenericUserTypeToString(a.userType)). + WithError(err).Warnf("Int type error") } arg.Index = uint64(a.index) diff --git a/pkg/sensors/tracing/generickprobe.go b/pkg/sensors/tracing/generickprobe.go index db6c1891d0a..f47a168f654 100644 --- a/pkg/sensors/tracing/generickprobe.go +++ b/pkg/sensors/tracing/generickprobe.go @@ -724,10 +724,21 @@ func addKprobe(funcName string, f *v1alpha1.KProbeSpec, in *addKprobeIn) (id idt // Parse Arguments for j, a := range f.Args { - argType := gt.GenericTypeFromString(a.Type) + // First try userspace types + argType := gt.GenericInvalidType + userArgType := gt.GenericUserTypeFromString(a.Type) + + if userArgType != gt.GenericInvalidType { + // This is a userspace type, map it to kernel type + argType = gt.GenericUserToKernelType(userArgType) + } else { + argType = gt.GenericTypeFromString(a.Type) + } + if argType == gt.GenericInvalidType { return errFn(fmt.Errorf("Arg(%d) type '%s' unsupported", j, a.Type)) } + if a.MaxData { if argType != gt.GenericCharBuffer { logger.GetLogger().Warnf("maxData flag is ignored (supported for char_buf type)") @@ -751,7 +762,7 @@ func addKprobe(funcName string, f *v1alpha1.KProbeSpec, in *addKprobeIn) (id idt config.ArgM[a.Index] = uint32(argMValue) argsBTFSet[a.Index] = true - argP := argPrinter{index: j, ty: argType, maxData: a.MaxData, label: a.Label} + argP := argPrinter{index: j, ty: argType, userType: userArgType, maxData: a.MaxData, label: a.Label} argSigPrinters = append(argSigPrinters, argP) }