diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index 6fc5b8a569e..6a622975080 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -47,7 +47,7 @@ enum { fd_ty = 17, /* const_buf_type is a type for buffers with static size that is passed - * in the meta argument + * in the meta argument's upper 16 bits */ const_buf_type = 18, bpf_attr_type = 19, @@ -631,9 +631,10 @@ copy_kernel_module(char *args, unsigned long arg) return sizeof(struct tg_kernel_module); } -#define ARGM_INDEX_MASK 0xf -#define ARGM_RETURN_COPY BIT(4) -#define ARGM_MAX_DATA BIT(5) +#define ARGM_INDEX_MASK 0xf +#define ARGM_RETURN_COPY BIT(4) +#define ARGM_MAX_DATA BIT(5) +#define ARGM_USERSPACE_DATA BIT(6) static inline __attribute__((always_inline)) bool hasReturnCopy(unsigned long argm) @@ -647,6 +648,12 @@ has_max_data(unsigned long argm) return (argm & ARGM_MAX_DATA) != 0; } +static inline __attribute__((always_inline)) bool +is_userspace_data(unsigned long argm) +{ + return (argm & ARGM_USERSPACE_DATA) != 0; +} + static inline __attribute__((always_inline)) unsigned long get_arg_meta(int meta, struct msg_generic_kprobe *e) { @@ -1609,7 +1616,8 @@ static inline __attribute__((always_inline)) size_t type_to_min_size(int type, case char_iovec: return 4; case const_buf_type: - return argm; + // For const_buf_type, the size is in the upper 16 bits of the meta argument. + return argm >> 16; case bpf_attr_type: return sizeof(struct bpf_info_type); case perf_event_type: @@ -2651,8 +2659,9 @@ read_call_arg(void *ctx, struct msg_generic_kprobe *e, int index, int type, size = copy_char_iovec(ctx, orig_off, arg, argm, e); break; case const_buf_type: { + // for const_buf_type the size is in the upper 16 bits of the meta argument // bound size to 1023 to help the verifier out - size = argm & 0x03ff; + size = (argm >> 16) & 0x03ff; probe_read(args, size, (char *)arg); break; } diff --git a/pkg/sensors/tracing/args.go b/pkg/sensors/tracing/args.go index 58444113b18..430a5a04a61 100644 --- a/pkg/sensors/tracing/args.go +++ b/pkg/sensors/tracing/args.go @@ -30,8 +30,10 @@ type argPrinter struct { } const ( - argReturnCopyBit = 1 << 4 - argMaxDataBit = 1 << 5 + argSizeArgIndexMask = int(0xf) + argReturnCopyBit = 1 << 4 + argMaxDataBit = 1 << 5 + argUserspaceDataBit = 1 << 6 ) func argReturnCopy(meta int) bool { @@ -41,17 +43,20 @@ func argReturnCopy(meta int) bool { // meta value format: // bits // -// 0-3 : SizeArgIndex -// 4 : ReturnCopy -// 5 : MaxData -func getMetaValue(arg *v1alpha1.KProbeArg) (int, error) { - var meta int +// 0-3 : SizeArgIndex +// 4 : ReturnCopy +// 5 : MaxData +// 6 : UserspaceData +// 7-15 : reserved +// 16-31 : size for const_buf +func getMetaValue(arg *v1alpha1.KProbeArg, userspaceDataDefault bool) (int, error) { + meta := 0 if arg.SizeArgIndex > 0 { if arg.SizeArgIndex > 15 { return 0, fmt.Errorf("invalid SizeArgIndex value (>15): %v", arg.SizeArgIndex) } - meta = int(arg.SizeArgIndex) + meta = meta | int(arg.SizeArgIndex) } if arg.ReturnCopy { meta = meta | argReturnCopyBit @@ -59,19 +64,18 @@ func getMetaValue(arg *v1alpha1.KProbeArg) (int, error) { if arg.MaxData { meta = meta | argMaxDataBit } - return meta, nil -} - -// getTracepointMetaArg is a temporary helper to find meta values while tracepoint -// converts into new CRD and config formats. -func getTracepointMetaValue(arg *v1alpha1.KProbeArg) int { - if arg.SizeArgIndex > 0 { - return int(arg.SizeArgIndex) - } - if arg.ReturnCopy { - return -1 + if arg.IsUserspaceData == nil { + // If not set in policy, use the default. + if userspaceDataDefault { + meta = meta | argUserspaceDataBit + } + } else { + // Otherwise, use the provided value. + if *arg.IsUserspaceData { + meta = meta | argUserspaceDataBit + } } - return 0 + return meta, nil } func getArg(r *bytes.Reader, a argPrinter) tracingapi.MsgGenericKprobeArg { diff --git a/pkg/sensors/tracing/generickprobe.go b/pkg/sensors/tracing/generickprobe.go index a4c30a51960..f154423fead 100644 --- a/pkg/sensors/tracing/generickprobe.go +++ b/pkg/sensors/tracing/generickprobe.go @@ -662,7 +662,8 @@ func addKprobe(funcName string, f *v1alpha1.KProbeSpec, in *addKprobeIn) (id idt logger.GetLogger().Warnf("maxData flag is ignored (supported from large programs)") } } - argMValue, err := getMetaValue(&a) + // For kprobes, args default to userspace memory for syscalls, and kernel memory otherwise. + argMValue, err := getMetaValue(&a, f.Syscall) if err != nil { return errFn(err) } diff --git a/pkg/sensors/tracing/generictracepoint.go b/pkg/sensors/tracing/generictracepoint.go index 2e8274195c4..ca129dc57db 100644 --- a/pkg/sensors/tracing/generictracepoint.go +++ b/pkg/sensors/tracing/generictracepoint.go @@ -219,10 +219,10 @@ func (out *genericTracepointArg) getGenericTypeId() (int, error) { if err != nil { return gt.GenericInvalidType, fmt.Errorf("failed to get size of array type %w", err) } - if out.MetaArg == 0 { - // set MetaArg equal to the number of bytes we need to copy - out.MetaArg = nbytes - } + // set MetaArg's upper half-word equal to the number of bytes we need to copy + out.MetaArg = out.MetaArg & 0xffff + out.MetaArg = out.MetaArg | (nbytes << 16) + return gt.GenericConstBuffer, nil case tracepoint.SizeTy: @@ -235,6 +235,7 @@ func (out *genericTracepointArg) getGenericTypeId() (int, error) { func buildGenericTracepointArgs(info *tracepoint.Tracepoint, specArgs []v1alpha1.KProbeArg) ([]genericTracepointArg, error) { ret := make([]genericTracepointArg, 0, len(specArgs)) nfields := uint32(len(info.Format.Fields)) + syscall := info.Subsys == "syscalls" || info.Subsys == "raw_syscalls" for argIdx := range specArgs { specArg := &specArgs[argIdx] @@ -242,11 +243,16 @@ func buildGenericTracepointArgs(info *tracepoint.Tracepoint, specArgs []v1alpha1 return nil, fmt.Errorf("tracepoint %s/%s has %d fields but field %d was requested", info.Subsys, info.Event, nfields, specArg.Index) } field := info.Format.Fields[specArg.Index] + // Syscall tracepoint arguments are in userspace memory. + metaTp, err := getMetaValue(specArg, syscall) + if err != nil { + return nil, fmt.Errorf("tracepoint %s/%s getMetaValue error: %w", info.Subsys, info.Event, err) + } ret = append(ret, genericTracepointArg{ CtxOffset: int(field.Offset), ArgIdx: uint32(argIdx), TpIdx: int(specArg.Index), - MetaTp: getTracepointMetaValue(specArg), + MetaTp: metaTp, nopTy: false, format: &field, genericTypeId: gt.GenericInvalidType, @@ -272,12 +278,16 @@ func buildGenericTracepointArgs(info *tracepoint.Tracepoint, specArgs []v1alpha1 } field := info.Format.Fields[tpIdx] argIdx := uint32(len(ret)) + metaArg := 0 + if syscall { + metaArg = argUserspaceDataBit + } ret = append(ret, genericTracepointArg{ CtxOffset: int(field.Offset), ArgIdx: argIdx, TpIdx: tpIdx, MetaTp: 0, - MetaArg: 0, + MetaArg: metaArg, nopTy: true, format: &field, genericTypeId: gt.GenericInvalidType, @@ -287,15 +297,18 @@ func buildGenericTracepointArgs(info *tracepoint.Tracepoint, specArgs []v1alpha1 for idx := 0; idx < len(ret); idx++ { meta := ret[idx].MetaTp - if meta == 0 || meta == -1 { + metaArgIndex := meta & argSizeArgIndexMask + + if metaArgIndex == 0 || (meta&argReturnCopyBit != 0) { ret[idx].MetaArg = meta continue } - a, err := getOrAppendMeta(meta) + a, err := getOrAppendMeta(metaArgIndex) if err != nil { return nil, err } - ret[idx].MetaArg = int(a.ArgIdx) + 1 + meta = meta & ^argSizeArgIndexMask + ret[idx].MetaArg = meta | (int(a.ArgIdx) + 1) } return ret, nil } diff --git a/pkg/sensors/tracing/genericuprobe.go b/pkg/sensors/tracing/genericuprobe.go index e5969a8b311..23941a26237 100644 --- a/pkg/sensors/tracing/genericuprobe.go +++ b/pkg/sensors/tracing/genericuprobe.go @@ -244,7 +244,8 @@ func addUprobe(spec *v1alpha1.UProbeSpec, ids []idtable.EntryID, in *addUprobeIn if argType == gt.GenericInvalidType { return nil, fmt.Errorf("Arg(%d) type '%s' unsupported", i, a.Type) } - argMValue, err := getMetaValue(&a) + // For uprobes, args default to userspace memory. + argMValue, err := getMetaValue(&a, true) if err != nil { return nil, err } diff --git a/pkg/sensors/tracing/kprobe_test.go b/pkg/sensors/tracing/kprobe_test.go index 15456cffd2e..ad91d7fb009 100644 --- a/pkg/sensors/tracing/kprobe_test.go +++ b/pkg/sensors/tracing/kprobe_test.go @@ -4390,7 +4390,7 @@ func testMaxData(t *testing.T, data []byte, checker *ec.UnorderedEventChecker, c func TestKprobeWriteMaxDataTrunc(t *testing.T) { if !kernels.MinKernelVersion("5.3.0") { - t.Skip("TestCopyFd requires at least 5.3.0 version") + t.Skip("TestKprobeWriteMaxDataTrunc requires at least 5.3.0 version") } _, fd2, fdString := createTestFile(t) myPid := observertesthelper.GetMyPid() @@ -4453,7 +4453,7 @@ spec: func TestKprobeWriteMaxData(t *testing.T) { if !kernels.MinKernelVersion("5.3.0") { - t.Skip("TestCopyFd requires at least 5.3.0 version") + t.Skip("TestKprobeWriteMaxData requires at least 5.3.0 version") } _, fd2, fdString := createTestFile(t) myPid := observertesthelper.GetMyPid() @@ -4512,7 +4512,7 @@ spec: func TestKprobeWriteMaxDataFull(t *testing.T) { if !kernels.MinKernelVersion("5.3.0") { - t.Skip("TestCopyFd requires at least 5.3.0 version") + t.Skip("TestKprobeWriteMaxDataFull requires at least 5.3.0 version") } _, fd2, fdString := createTestFile(t) myPid := observertesthelper.GetMyPid() @@ -5783,7 +5783,7 @@ spec: func TestKprobeListSyscallDupsRange(t *testing.T) { if !kernels.MinKernelVersion("5.3.0") { - t.Skip("TestCopyFd requires at least 5.3.0 version") + t.Skip("TestKprobeListSyscallDupsRange requires at least 5.3.0 version") } myPid := observertesthelper.GetMyPid() pidStr := strconv.Itoa(int(myPid))