Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory: Swap probe_read to kernel or user version #2213

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
21 changes: 15 additions & 6 deletions bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -636,9 +636,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)
Expand All @@ -652,6 +653,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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, just use argm & ARGM_USERSPACE_DATA. No need for != 0

}

static inline __attribute__((always_inline)) unsigned long
get_arg_meta(int meta, struct msg_generic_kprobe *e)
{
Expand Down Expand Up @@ -1614,7 +1621,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:
Expand Down Expand Up @@ -2663,8 +2671,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;
}
Expand Down
44 changes: 24 additions & 20 deletions pkg/sensors/tracing/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -41,37 +43,39 @@ 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: meta |= ...

}
if arg.ReturnCopy {
meta = meta | argReturnCopyBit
}
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: meta |= ...

}
} else {
// Otherwise, use the provided value.
if *arg.IsUserspaceData {
meta = meta | argUserspaceDataBit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: meta |= ...

}
}
return 0
return meta, nil
}

func getArg(r *bytes.Reader, a argPrinter) api.MsgGenericKprobeArg {
Expand Down
3 changes: 2 additions & 1 deletion pkg/sensors/tracing/generickprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,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)
}
Expand Down
31 changes: 22 additions & 9 deletions pkg/sensors/tracing/generictracepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a check and return an error if nbytes is cannot fit in the number of bits we have.


return gt.GenericConstBuffer, nil

case tracepoint.SizeTy:
Expand All @@ -238,18 +238,24 @@ 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]
if specArg.Index >= nfields {
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,
Expand All @@ -275,12 +281,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,
Expand All @@ -290,15 +300,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
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/sensors/tracing/genericuprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,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
}
Expand Down