Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/v1/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions api/v1/tetragon/codegen/eventchecker/eventchecker.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

605 changes: 308 additions & 297 deletions api/v1/tetragon/tetragon.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions api/v1/tetragon/tetragon.proto
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ message KprobeArgument {
KprobeBpfProg bpf_prog_arg = 31;
}
string label = 18;
int32 resolve_err_depth = 32;
}

enum KprobeAction {
Expand Down
1 change: 1 addition & 0 deletions bpf/lib/generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct msg_generic_kprobe {
__u32 tid; // Thread ID that triggered the event
__u64 kernel_stack_id; // Kernel stack trace ID on u32 and potential error, see flag in msg_common.flags
__u64 user_stack_id; // User Stack trace ID
__s32 resolve_err_depth[MAX_POSSIBLE_ARGS];
/* anything above is shared with the userspace so it should match structs MsgGenericKprobe and MsgGenericTracepoint in Go */
char args[24000];
unsigned long a0, a1, a2, a3, a4;
Expand Down
35 changes: 26 additions & 9 deletions bpf/process/generic_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,28 +396,38 @@ extract_arg_depth(u32 i, struct extract_arg_data *data)
{
if (i >= MAX_BTF_ARG_DEPTH || !data->btf_config[i].is_initialized)
return 1;

*data->arg = *data->arg + data->btf_config[i].offset;
if (data->btf_config[i].is_pointer)
probe_read((void *)data->arg, sizeof(char *), (void *)*data->arg);

if (data->btf_config[i].is_pointer) {
if (probe_read((void *)data->arg, sizeof(char *), (void *)*data->arg) < 0) {
*data->resolve_err_depth = i + 1;
return 1;
}
}

return 0;
}

#ifdef __LARGE_BPF_PROG
FUNC_INLINE void extract_arg(struct event_config *config, int index, unsigned long *a)
FUNC_INLINE void extract_arg(struct event_config *config, int index, unsigned long *a,
__s32 *resolve_err_depth)
{
struct config_btf_arg *btf_config;

if (index >= EVENT_CONFIG_MAX_ARG)
return;

asm volatile("%[index] &= %1 ;\n"
: [index] "+r"(index)
: "i"(MAX_SELECTORS_MASK));

if (index >= EVENT_CONFIG_MAX_ARG)
return;

btf_config = config->btf_arg[index];
if (btf_config->is_initialized) {
struct extract_arg_data extract_data = {
.btf_config = btf_config,
.arg = a,
.resolve_err_depth = resolve_err_depth,
};
#ifndef __V61_BPF_PROG
#pragma unroll
Expand All @@ -431,7 +441,10 @@ FUNC_INLINE void extract_arg(struct event_config *config, int index, unsigned lo
}
}
#else
FUNC_INLINE void extract_arg(struct event_config *config, int index, unsigned long *a) {}
FUNC_INLINE void extract_arg(struct event_config *config, int index, unsigned long *a,
__s32 *resolve_err_depth)
{
}
#endif /* __LARGE_BPF_PROG */

FUNC_INLINE int arg_idx(int index)
Expand Down Expand Up @@ -565,9 +578,13 @@ FUNC_INLINE long generic_read_arg(void *ctx, int index, long off, struct bpf_map
ty = config->arg[index];
am = config->arm[index];

#ifdef __LARGE_BPF_PROG
e->resolve_err_depth[index] = 0;
#endif

#if defined(GENERIC_TRACEPOINT) || defined(GENERIC_USDT)
a = (&e->a0)[index];
extract_arg(config, index, &a);
extract_arg(config, index, &a, &e->resolve_err_depth[index]);
#else
arg_index = config->idx[index];
asm volatile("%[arg_index] &= %1 ;\n"
Expand All @@ -588,7 +605,7 @@ FUNC_INLINE long generic_read_arg(void *ctx, int index, long off, struct bpf_map
else
a = (&e->a0)[arg_index];

extract_arg(config, index, &a);
extract_arg(config, index, &a, &e->resolve_err_depth[index]);
Copy link
Contributor

Choose a reason for hiding this comment

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

so if we fail to resolve we still continue and store the 'unresolved data' which likely null, right? I think we can skip it

but how about we make this more generic and we start each argument data with '__u32 error' status and in case of failure we write just error != 0 as argument value.. in case of resolve failure we encode the depth into it

then on user space side the getArg would just read first uint32 from event reader to get the argument status
so all the extra retrieval of error depth from each probe type would not be needed, also probably the argument index will be clear, because you have the error for argument you are about to read, or skip reading if it's != 0

we could use this to store other errors that happen during argument encoding, which there are plenty

and into final event instead of the depth value, I'd add error string that in case of resolve failure would contain something like: "failed to resolve current->file->f_inode"

seems like this could save some cycles and prevent bogus arguments values, because IIUC if we bail from argument storing in the middle on kernel side the user side still tries to read the whole part


if (should_offload_path(ty))
return generic_path_offload(ctx, ty, a, index, off, tailcals);
Expand Down
5 changes: 5 additions & 0 deletions bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ struct config_reg_arg {
struct extract_arg_data {
struct config_btf_arg *btf_config;
unsigned long *arg;
__s32 *resolve_err_depth;
};

#define MAX_BTF_ARG_DEPTH 10
Expand Down Expand Up @@ -2033,6 +2034,10 @@ selector_arg_offset(__u8 *f, struct msg_generic_kprobe *e, __u32 selidx,
if (index > 5)
return 0;

#ifdef __LARGE_BPF_PROG
if (e->resolve_err_depth[index])
return 0;
#endif
args = get_arg(e, index);
switch (filter->type) {
case fd_ty:
Expand Down
2 changes: 2 additions & 0 deletions contrib/tester-progs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ regs-override
uretprobe
uprobe-resolve
uprobe-resolve.btf
uprobe-null
uprobe-null.btf
10 changes: 9 additions & 1 deletion contrib/tester-progs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ PROGS = sigkill-tester \
usdt-override \
usdt-resolve \
uretprobe \
uprobe-resolve
uprobe-resolve \
uprobe-null

PROGS += $(PROGS_ARCH)

Expand Down Expand Up @@ -120,6 +121,13 @@ uprobe-resolve: uprobe-resolve.c
llvm-objcopy -I binary -O elf64-x86-64 --rename-section .data=.BTF [email protected] [email protected]
rm [email protected]

uprobe-null: uprobe-null.c
$(GCC) -ggdb3 -O2 -Wall $< -o $@
pahole -J $@
llvm-objcopy --dump-section [email protected] $@
llvm-objcopy -I binary -O elf64-x86-64 --rename-section .data=.BTF [email protected] [email protected]
rm [email protected]

ifeq ($(shell uname -m),x86_64)
regs-override: regs-override.c
$(GCC) -Wall -fcf-protection=none $< -o $@
Expand Down
62 changes: 62 additions & 0 deletions contrib/tester-progs/uprobe-null.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//go:build ignore

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <stdbool.h>

struct mysubstruct {
int32_t val;
};

struct mystruct {
struct mysubstruct *subp;
};

void usage(char *argv0)
{
fprintf(stderr, "Usage: %s <type>\n", argv0);
fprintf(stderr, "type can be one of: first, middle, nonull\n");
}

// without noinline, the symbol is found, but no event fires
__attribute__((noinline)) int func(struct mystruct *ms) {
if (!ms)
return -1;

if (!ms->subp)
return -1;

printf("%d\n", ms->subp->val);
return 0;
}

int main(int argc, char *argv[])
{

if (argc < 2) {
usage(argv[0]);
exit(1);
}

char *type = argv[1];

if (!strcmp(type, "first")) {
func(NULL);
} else if (!strcmp(type, "middle")) {
struct mystruct ms;
ms.subp = NULL;
func(&ms);
} else if (!strcmp(type, "nonull")) {
struct mystruct ms;
struct mysubstruct mss;
ms.subp = &mss;
mss.val = 0;
func(&ms);
} else {
usage(argv[0]);
exit(1);
}
exit(0);
}
Loading
Loading