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

tetragon: add kprobe session support #3215

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
4 changes: 4 additions & 0 deletions bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ PROCESS += bpf_generic_kprobe_v61.o bpf_generic_retkprobe_v61.o \
PROCESS += bpf_generic_lsm_core_v61.o bpf_generic_lsm_output_v61.o \
bpf_generic_lsm_ima_file_v61.o bpf_generic_lsm_ima_bprm_v61.o

# session
PROCESS += bpf_session_kprobe.o

CGROUP = bpf_cgroup_mkdir.o bpf_cgroup_rmdir.o bpf_cgroup_release.o bpf_cgtracker.o
BPFTEST = bpf_lseek.o

Expand Down Expand Up @@ -116,6 +119,7 @@ CFLAGS_bpf_enforcer.o = -D__BPF_OVERRIDE_RETURN
CFLAGS_bpf_multi_enforcer.o = -D__BPF_OVERRIDE_RETURN -D__MULTI_KPROBE
CFLAGS_bpf_generic_lsm_core.o = -D__LARGE_BPF_PROG
CFLAGS_bpf_generic_lsm_output.o = -D__LARGE_BPF_PROG
CFLAGS_bpf_session_kprobe.o = -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -D__V61_BPF_PROG -D__MULTI_KPROBE

# Rules
MTARGET_o = $(patsubst $(DEPSDIR)%.d,$(OBJSDIR)%.o,$@)
Expand Down
5 changes: 5 additions & 0 deletions bpf/include/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,9 @@ static int BPF_FUNC(seq_write, struct seq_file *m, const void *data, uint32_t le
#endif
#endif

#define __ksym __attribute__((section(".ksyms")))

extern bool bpf_session_is_return(void) __ksym;
extern __u64 *bpf_session_cookie(void) __ksym;

#endif /* __BPF_API__ */
1 change: 1 addition & 0 deletions bpf/lib/generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct msg_generic_kprobe {
bool post; // true if event needs to be posted
} lsm;
};
bool has_return; /* true if there's return probe defined */
};

FUNC_INLINE size_t generic_kprobe_common_size(void)
Expand Down
2 changes: 1 addition & 1 deletion bpf/process/bpf_generic_kprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ generic_kprobe_filter_arg(void *ctx)
__attribute__((section("kprobe"), used)) int
generic_kprobe_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&kprobe_calls);
generic_actions(ctx, (struct bpf_map_def *)&kprobe_calls, true);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion bpf/process/bpf_generic_lsm_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ generic_lsm_filter_arg(void *ctx)
__attribute__((section("lsm"), used)) int
generic_lsm_actions(void *ctx)
{
bool postit = generic_actions(ctx, (struct bpf_map_def *)&lsm_calls);
bool postit = generic_actions(ctx, (struct bpf_map_def *)&lsm_calls, true);

struct msg_generic_kprobe *e;
int zero = 0;
Expand Down
2 changes: 1 addition & 1 deletion bpf/process/bpf_generic_retkprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ BPF_KRETPROBE(generic_retkprobe_filter_arg)
__attribute__((section("kprobe"), used)) int
BPF_KRETPROBE(generic_retkprobe_actions)
{
generic_actions(ctx, (struct bpf_map_def *)&retkprobe_calls);
generic_actions(ctx, (struct bpf_map_def *)&retkprobe_calls, false);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion bpf/process/bpf_generic_tracepoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ generic_tracepoint_arg(void *ctx)
__attribute__((section("tracepoint"), used)) int
generic_tracepoint_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&tp_calls);
generic_actions(ctx, (struct bpf_map_def *)&tp_calls, true);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion bpf/process/bpf_generic_uprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ generic_uprobe_filter_arg(void *ctx)
__attribute__((section("uprobe"), used)) int
generic_uprobe_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&uprobe_calls);
generic_actions(ctx, (struct bpf_map_def *)&uprobe_calls, true);
return 0;
}

Expand Down
153 changes: 153 additions & 0 deletions bpf/process/bpf_session_kprobe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright Authors of Cilium */

#include "vmlinux.h"
#include "api.h"

#define GENERIC_KPROBE

#include "compiler.h"
#include "bpf_event.h"
#include "bpf_task.h"
#include "retprobe_map.h"
#include "types/operations.h"
#include "types/basic.h"
#include "pfilter.h"
#include "policy_filter.h"

char _license[] __attribute__((section("license"), used)) = "Dual BSD/GPL";

int generic_kprobe_setup_event(void *ctx);
int generic_kprobe_process_event(void *ctx);
int generic_kprobe_process_filter(void *ctx);
int generic_kprobe_filter_arg(void *ctx);
int generic_kprobe_actions(void *ctx);
int generic_kprobe_output(void *ctx);

struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 13);
__uint(key_size, sizeof(__u32));
__array(values, int(void *));
} kprobe_calls SEC(".maps") = {
.values = {
[0] = (void *)&generic_kprobe_setup_event,
[1] = (void *)&generic_kprobe_process_event,
[2] = (void *)&generic_kprobe_process_filter,
[3] = (void *)&generic_kprobe_filter_arg,
[4] = (void *)&generic_kprobe_actions,
[5] = (void *)&generic_kprobe_output,
},
};

int generic_retkprobe_filter_arg(void *ctx);
int generic_retkprobe_actions(void *ctx);
int generic_retkprobe_output(void *ctx);

struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 6);
__uint(key_size, sizeof(__u32));
__array(values, int(void *));
} retkprobe_calls SEC(".maps") = {
.values = {
[3] = (void *)&generic_retkprobe_filter_arg,
[4] = (void *)&generic_retkprobe_actions,
[5] = (void *)&generic_retkprobe_output,
},
};

#include "generic_maps.h"
#include "generic_calls.h"

__attribute__((section(("kprobe.session/generic_kprobe")), used)) int
generic_kprobe_event(struct pt_regs *ctx)
{
if (bpf_session_is_return()) {
return generic_retkprobe(ctx, (struct bpf_map_def *)&retkprobe_calls,
PT_REGS_RC(ctx));
}

generic_start_process_filter(ctx, (struct bpf_map_def *)&kprobe_calls);
return 1; /* kill return probe */
}

__attribute__((section("kprobe.session"), used)) int
generic_kprobe_setup_event(void *ctx)
{
generic_process_event_and_setup(ctx, (struct bpf_map_def *)&kprobe_calls);
return 1; /* kill return probe */
}

__attribute__((section("kprobe.session"), used)) int
generic_kprobe_process_event(void *ctx)
{
generic_process_event(ctx, (struct bpf_map_def *)&kprobe_calls);
return 1; /* kill return probe */
}

__attribute__((section("kprobe.session"), used)) int
generic_kprobe_process_filter(void *ctx)
{
int ret;

ret = generic_process_filter();
if (ret == PFILTER_CONTINUE)
tail_call(ctx, &kprobe_calls, TAIL_CALL_FILTER);
else if (ret == PFILTER_ACCEPT)
tail_call(ctx, &kprobe_calls, 0);
/* If filter does not accept drop it. Ideally we would
* log error codes for later review, TBD.
*/
return ret == PFILTER_REJECT ? 1 : 0;
}

__attribute__((section("kprobe.session"), used)) int
generic_kprobe_filter_arg(void *ctx)
{
generic_filter_arg(ctx, (struct bpf_map_def *)&kprobe_calls, true);
return 1; /* kill return probe */
}

__attribute__((section("kprobe.session"), used)) int
generic_kprobe_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&kprobe_calls, true);
return 1; /* kill return probe */
}

__attribute__((section("kprobe.session"), used)) int
generic_kprobe_output(void *ctx)
{
return generic_output(ctx, MSG_OP_GENERIC_KPROBE);
}

__attribute__((section("kprobe.session"), used)) int
generic_retkprobe_filter_arg(void *ctx)
{
return generic_filter_arg(ctx, (struct bpf_map_def *)&retkprobe_calls, false);
}

__attribute__((section("kprobe.session"), used)) int
generic_retkprobe_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&retkprobe_calls, false);
return 0;
}

__attribute__((section("kprobe.session"), used)) int
generic_retkprobe_output(void *ctx)
{
struct msg_generic_kprobe *msg;
int ret = 0, zero = 0;

generic_output(ctx, MSG_OP_GENERIC_KPROBE);

/* make sure we want to trigger return probe */
msg = map_lookup_elem(&process_call_heap, &zero);
ret = msg && msg->has_return;

asm volatile("%[ret] &= 0x1;\n"
: [ret] "+r"(ret));
return ret;
}
24 changes: 16 additions & 8 deletions bpf/process/generic_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ generic_start_process_filter(void *ctx, struct bpf_map_def *calls)
return 0;
msg->func_id = config->func_id;
msg->retprobe_id = 0;
msg->has_return = config->argreturn != 0;

/* Initialize selector index to 0 */
msg->sel.curr = 0;
Expand Down Expand Up @@ -362,10 +363,11 @@ do_actions(void *ctx, struct selector_action *actions)
}

FUNC_INLINE long
generic_actions(void *ctx, struct bpf_map_def *calls)
generic_actions(void *ctx, struct bpf_map_def *calls, bool is_entry)
{
struct selector_arg_filters *arg;
struct selector_action *actions;
struct filter_map_value *fval;
struct msg_generic_kprobe *e;
int actoff, pass, zero = 0;
bool postit;
Expand All @@ -379,10 +381,12 @@ generic_actions(void *ctx, struct bpf_map_def *calls)
if (pass <= 1)
return 0;

f = map_lookup_elem(&filter_map, &e->idx);
if (!f)
fval = map_lookup_elem(&filter_map, &e->idx);
if (!fval)
return 0;

f = filter_map_ptr(fval, is_entry);

asm volatile("%[pass] &= 0x7ff;\n"
: [pass] "+r"(pass)
:);
Expand Down Expand Up @@ -572,12 +576,15 @@ FUNC_INLINE int generic_process_filter(void)

enter = event_find_curr(&ppid, &walker);
if (enter) {
struct filter_map_value *fval;
int selectors, pass;
__u32 *f = map_lookup_elem(&filter_map, &msg->idx);
__u32 *f;

if (!f)
fval = map_lookup_elem(&filter_map, &msg->idx);
if (!fval)
return PFILTER_ERROR;

f = (__u32 *)filter_map_ptr(fval, true);
sel = &msg->sel;
current = &msg->current;

Expand Down Expand Up @@ -615,11 +622,11 @@ FUNC_INLINE int generic_process_filter(void)

FUNC_INLINE int filter_args(struct msg_generic_kprobe *e, int selidx, bool is_entry)
{
__u8 *f;
struct filter_map_value *fval;

/* No filters and no selectors so just accepts */
f = map_lookup_elem(&filter_map, &e->idx);
if (!f)
fval = map_lookup_elem(&filter_map, &e->idx);
if (!fval)
return 1;

/* No selectors, accept by default */
Expand All @@ -634,6 +641,7 @@ FUNC_INLINE int filter_args(struct msg_generic_kprobe *e, int selidx, bool is_en
return filter_args_reject(e->func_id);

if (e->sel.active[selidx]) {
__u8 *f = filter_map_ptr(fval, is_entry);
int pass = selector_arg_offset(f, e, selidx, is_entry);

if (pass)
Expand Down
10 changes: 9 additions & 1 deletion bpf/process/generic_maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#ifndef __GENERIC_MAPS_H__
#define __GENERIC_MAPS_H__

#include <include/compiler.h>
#include "lib/data_msg.h"

struct {
Expand Down Expand Up @@ -37,9 +38,16 @@ struct {
#endif

struct filter_map_value {
unsigned char buf[FILTER_SIZE];
__u8 entry[FILTER_SIZE];
__u8 retrn[FILTER_SIZE];
};

FUNC_INLINE __u8 *
filter_map_ptr(struct filter_map_value *fval, bool is_entry)
{
return is_entry ? &fval->entry[0] : &fval->retrn[0];
}

/* Arrays of size 1 will be rewritten to direct loads in verifier */
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
Expand Down
5 changes: 5 additions & 0 deletions contrib/verify/verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ for obj in "$TETRAGONDIR"/*.o; do
continue
fi

# Session kprobe support is still not widely around, skip the object
if [[ "$B" == bpf_session_* ]]; then
continue
fi

# Skip v6.1 objects check for kernel < 6.1
if [[ "$B" == *61.o && $(echo "$KERNEL < 6.1" | bc) == 1 ]]; then
continue
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/alecthomas/kong v1.6.1
github.com/bombsimon/logrusr/v4 v4.1.0
github.com/cilium/cilium v1.17.0-rc.1
github.com/cilium/ebpf v0.17.1
github.com/cilium/ebpf v0.17.2-0.20250113160858-6d6c5e322573
github.com/cilium/little-vm-helper v0.0.19
github.com/cilium/lumberjack/v2 v2.4.1
github.com/cilium/tetragon/api v0.0.0-00010101000000-000000000000
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/cilium v1.17.0-rc.1 h1:jUiwwJ2qyajW2YY8/sOqJSy8enMhClG4FT1Dq6MELTU=
github.com/cilium/cilium v1.17.0-rc.1/go.mod h1:UAK2rIorqcHHxtkCG33wcQ++jAtDUknXCa42hOvhrR4=
github.com/cilium/ebpf v0.17.1 h1:G8mzU81R2JA1nE5/8SRubzqvBMmAmri2VL8BIZPWvV0=
github.com/cilium/ebpf v0.17.1/go.mod h1:vay2FaYSmIlv3r8dNACd4mW/OCaZLJKJOo+IHBvCIO8=
github.com/cilium/ebpf v0.17.2-0.20250113160858-6d6c5e322573 h1:gj9/PN7T0a/RGgVAYtWH0JrzQU/KALDFuswfSsiReEw=
github.com/cilium/ebpf v0.17.2-0.20250113160858-6d6c5e322573/go.mod h1:9X5VAsIOck/nCAp0+nCSVzub1Q7x+zKXXItTMYfNE+E=
github.com/cilium/hive v0.0.0-20241213121623-605c1412b9b3 h1:RfmUH1ouzj0LzORYJRhp43e1rlGpx6GNv4NIRUakU2w=
github.com/cilium/hive v0.0.0-20241213121623-605c1412b9b3/go.mod h1:pI2GJ1n3SLKIQVFrKF7W6A6gb6BQkZ+3Hp4PAEo5SuI=
github.com/cilium/little-vm-helper v0.0.19 h1:eJeJM/03MGLrLUXXTBDZo2JoX5cIbm5+9iWjoHgpy/M=
Expand Down
Loading
Loading