Skip to content
Draft
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
19 changes: 14 additions & 5 deletions bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ PROCESS += bpf_execve_event_v310.o bpf_exit_v310.o bpf_fork_v310.o
PROCESS += bpf_execve_event.o bpf_fork.o bpf_exit.o bpf_execve_bprm_commit_creds.o
# generic probes
PROCESS += bpf_generic_kprobe.o bpf_generic_retkprobe.o bpf_generic_tracepoint.o \
bpf_generic_uprobe.o bpf_generic_rawtp.o bpf_generic_usdt.o
bpf_generic_uprobe.o bpf_generic_rawtp.o bpf_generic_usdt.o \
bpf_generic_fentry.o bpf_generic_fexit.o

# lsm
PROCESS += bpf_generic_lsm_core.o bpf_generic_lsm_output.o
Expand All @@ -57,7 +58,9 @@ PROCESS += bpf_generic_kprobe_v53.o bpf_generic_retkprobe_v53.o \
bpf_multi_kprobe_v53.o bpf_multi_retkprobe_v53.o \
bpf_generic_tracepoint_v53.o bpf_generic_uprobe_v53.o \
bpf_generic_rawtp_v53.o \
bpf_generic_usdt_v53.o
bpf_generic_usdt_v53.o \
bpf_generic_fentry_v53.o \
bpf_generic_fexit_v53.o

# v5.11
# base sensor
Expand All @@ -67,7 +70,9 @@ PROCESS += bpf_generic_kprobe_v511.o bpf_generic_retkprobe_v511.o \
bpf_multi_kprobe_v511.o bpf_multi_retkprobe_v511.o \
bpf_generic_tracepoint_v511.o bpf_generic_uprobe_v511.o \
bpf_generic_rawtp_v511.o \
bpf_generic_usdt_v511.o
bpf_generic_usdt_v511.o \
bpf_generic_fentry_v511.o \
bpf_generic_fexit_v511.o

# lsm
PROCESS += bpf_generic_lsm_core_v511.o bpf_generic_lsm_output_v511.o \
Expand All @@ -83,7 +88,9 @@ PROCESS += bpf_generic_kprobe_v61.o bpf_generic_retkprobe_v61.o \
bpf_multi_uprobe_v61.o \
bpf_generic_rawtp_v61.o \
bpf_generic_usdt_v61.o \
bpf_multi_usdt_v61.o
bpf_multi_usdt_v61.o \
bpf_generic_fentry_v61.o \
bpf_generic_fexit_v61.o

# v6.12
# base sensor
Expand All @@ -95,7 +102,9 @@ PROCESS += bpf_generic_kprobe_v612.o bpf_generic_retkprobe_v612.o \
bpf_multi_uprobe_v612.o \
bpf_generic_rawtp_v612.o \
bpf_generic_usdt_v612.o \
bpf_multi_usdt_v612.o
bpf_multi_usdt_v612.o \
bpf_generic_fentry_v612.o \
bpf_generic_fexit_v612.o

# lsm
PROCESS += bpf_generic_lsm_core_v61.o bpf_generic_lsm_output_v61.o \
Expand Down
4 changes: 4 additions & 0 deletions bpf/include/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ static long BPF_FUNC(ima_inode_hash, struct inode *inode, void *dst, uint32_t si

static int BPF_FUNC(seq_write, struct seq_file *m, const void *data, uint32_t len);

/* Tracing */
static int BPF_FUNC(get_func_arg, void *ctx, __u32 n, __u64 *value);
static int BPF_FUNC(get_func_ret, void *ctx, __u64 *value);

/** LLVM built-ins, mem*() routines work for constant size */

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

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

#define GENERIC_FENTRY

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

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

int generic_fentry_setup_event(void *ctx);
int generic_fentry_process_event(void *ctx);
int generic_fentry_process_filter(void *ctx);
int generic_fentry_filter_arg(void *ctx);
int generic_fentry_actions(void *ctx);
int generic_fentry_output(void *ctx);
int generic_fentry_path(void *ctx);

struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 13);
__type(key, __u32);
__array(values, int(void *));
} fentry_calls SEC(".maps") = {
.values = {
[TAIL_CALL_SETUP] = (void *)&generic_fentry_setup_event,
[TAIL_CALL_PROCESS] = (void *)&generic_fentry_process_event,
[TAIL_CALL_FILTER] = (void *)&generic_fentry_process_filter,
[TAIL_CALL_ARGS] = (void *)&generic_fentry_filter_arg,
[TAIL_CALL_ACTIONS] = (void *)&generic_fentry_actions,
[TAIL_CALL_SEND] = (void *)&generic_fentry_output,
#ifndef __V61_BPF_PROG
[TAIL_CALL_PATH] = (void *)&generic_fentry_path,
#endif
},
};

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

#define SECTION_ENTRY "fentry/generic_fentry"
#define SECTION_TAIL "fentry/generic_fentry_tail"

__attribute__((section((SECTION_ENTRY)), used)) int
generic_fentry_event(struct pt_regs *ctx)
{
return generic_start_process_filter(ctx, (struct bpf_map_def *)&fentry_calls);
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_setup_event(void *ctx)
{
return generic_process_event_and_setup(ctx, (struct bpf_map_def *)&fentry_calls);
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_process_event(void *ctx)
{
return generic_process_event(ctx, (struct bpf_map_def *)&fentry_calls);
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_process_filter(void *ctx)
{
int ret;

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

__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_filter_arg(void *ctx)
{
return generic_filter_arg(ctx, (struct bpf_map_def *)&fentry_calls, true);
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&fentry_calls);
return 0;
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_output(void *ctx)
{
return generic_output(ctx, MSG_OP_GENERIC_KPROBE);
}

#ifndef __V61_BPF_PROG
__attribute__((section(SECTION_TAIL), used)) int
generic_fentry_path(void *ctx)
{
return generic_path(ctx, (struct bpf_map_def *)&fentry_calls);
}
#endif
72 changes: 72 additions & 0 deletions bpf/process/bpf_generic_fexit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright Authors of Cilium */

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

#define GENERIC_FEXIT

#include "compiler.h"
#include "bpf_tracing.h"
#include "bpf_event.h"
#include "bpf_task.h"
#include "retprobe_map.h"
#include "types/basic.h"

#define MAX_FILENAME 8096

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

int generic_fexit_filter_arg(void *ctx);
int generic_fexit_actions(void *ctx);
int generic_fexit_output(void *ctx);

struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 6);
__type(key, __u32);
__array(values, int(struct pt_regs *));
} fexit_calls SEC(".maps") = {
.values = {
[TAIL_CALL_ARGS] = (void *)&generic_fexit_filter_arg,
[TAIL_CALL_ACTIONS] = (void *)&generic_fexit_actions,
[TAIL_CALL_SEND] = (void *)&generic_fexit_output,
},
};

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

#define SECTION_ENTRY "fexit/generic_fexit"
#define SECTION_TAIL "fexit/generic_fexit_tail"

__attribute__((section(SECTION_ENTRY), used)) int
generic_fexit_event(void *ctx)
{
__u64 ret;

get_func_ret(ctx, &ret);
generic_retkprobe(ctx, (struct bpf_map_def *)&fexit_calls, ret);
return 0;
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fexit_filter_arg(void *ctx)
{
generic_filter_arg(ctx, (struct bpf_map_def *)&fexit_calls, false);
return 0;
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fexit_actions(void *ctx)
{
generic_actions(ctx, (struct bpf_map_def *)&fexit_calls);
return 0;
}

__attribute__((section(SECTION_TAIL), used)) int
generic_fexit_output(void *ctx)
{
generic_output(ctx, MSG_OP_GENERIC_KPROBE);
return 0;
}
31 changes: 31 additions & 0 deletions bpf/process/generic_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,37 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal
retprobe_map_set(e->func_id, e->retprobe_id, e->common.ktime, 1);
#endif

#ifdef GENERIC_FENTRY
struct bpf_raw_tracepoint_args *raw_args = (struct bpf_raw_tracepoint_args *)ctx;

if (config->syscall) {
struct pt_regs *_ctx = (struct pt_regs *)BPF_CORE_READ(raw_args, args[0]);

if (!_ctx)
return 0;
e->a0 = PT_REGS_PARM1_CORE_SYSCALL(_ctx);
e->a1 = PT_REGS_PARM2_CORE_SYSCALL(_ctx);
e->a2 = PT_REGS_PARM3_CORE_SYSCALL(_ctx);
e->a3 = PT_REGS_PARM4_CORE_SYSCALL(_ctx);
e->a4 = PT_REGS_PARM5_CORE_SYSCALL(_ctx);
} else {
e->a0 = BPF_CORE_READ(raw_args, args[0]);
e->a1 = BPF_CORE_READ(raw_args, args[1]);
e->a2 = BPF_CORE_READ(raw_args, args[2]);
e->a3 = BPF_CORE_READ(raw_args, args[3]);
e->a4 = BPF_CORE_READ(raw_args, args[4]);
}

generic_process_init(e, MSG_OP_GENERIC_KPROBE, config);

e->retprobe_id = retprobe_map_get_key(ctx);

/* If return arg is needed mark retprobe */
ty = config->argreturn;
if (ty > 0)
retprobe_map_set(e->func_id, e->retprobe_id, e->common.ktime, 1);
#endif

#ifdef GENERIC_LSM
struct bpf_raw_tracepoint_args *raw_args = (struct bpf_raw_tracepoint_args *)ctx;

Expand Down
6 changes: 6 additions & 0 deletions contrib/verify/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ func TestVerifyTetragonPrograms(t *testing.T) {
continue
}

// Can't load fentry/fext objects without loader setup
if strings.HasPrefix(fileName, "bpf_generic_fentry") ||
strings.HasPrefix(fileName, "bpf_generic_fexit") {
continue
}

// Skip v6.1 objects check for kernel < 6.1
if strings.HasSuffix(fileName, "61.o") && !kernels.MinKernelVersion("6.1") {
continue
Expand Down
46 changes: 44 additions & 2 deletions pkg/bpf/detect_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var (
missedStatsKprobeMulti Feature
batchUpdate Feature
uprobeRefCtrOffset Feature
getFuncRetHelper Feature
)

func HasOverrideHelper() bool {
Expand All @@ -57,6 +58,10 @@ func HasSignalHelper() bool {
return features.HaveProgramHelper(ebpf.Kprobe, asm.FnSendSignal) == nil
}

func HasFentryProgram() bool {
return features.HaveProgramType(ebpf.Tracing) == nil
}

func detectKprobeMulti() bool {
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
Name: "probe_bpf_kprobe_multi_link",
Expand Down Expand Up @@ -508,14 +513,51 @@ func HasUprobeRefCtrOffset() bool {
return uprobeRefCtrOffset.detected
}

func detectGetFuncRetHelper() bool {
sysGetcpu, err := arch.AddSyscallPrefix("sys_getcpu")
if err != nil {
return false
}
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
Name: "probe_get_func_ret",
Type: ebpf.Tracing,
AttachType: ebpf.AttachTraceFExit,
Instructions: asm.Instructions{
asm.Mov.Reg(asm.R2, asm.R10),
asm.Add.Imm(asm.R2, -8),
asm.FnGetFuncRet.Call(),
asm.Mov.Imm(asm.R0, 0),
asm.Return(),
},
License: "GPL",
AttachTo: sysGetcpu,
})
if err != nil {
return false
}
prog.Close()
return true
}

func detectGetFuncRetHelperOnce() {
getFuncRetHelper.init.Do(func() {
getFuncRetHelper.detected = detectGetFuncRetHelper()
})
}

func HasGetFuncRetHelper() bool {
detectGetFuncRetHelperOnce()
return getFuncRetHelper.detected
}

func LogFeatures() string {
// once we have detected all features, flush the BTF spec
// we cache all values so calling again a Has* function will
// not load the BTF again
defer ebtf.FlushKernelSpec()
return fmt.Sprintf("override_return: %t, buildid: %t, kprobe_multi: %t, uprobe_multi %t, fmodret: %t, fmodret_syscall: %t, signal: %t, large: %t, link_pin: %t, lsm: %t, missed_stats_kprobe_multi: %t, missed_stats_kprobe: %t, batch_update: %t, uprobe_refctroff: %t",
return fmt.Sprintf("override_return: %t, buildid: %t, kprobe_multi: %t, uprobe_multi %t, fmodret: %t, fmodret_syscall: %t, signal: %t, large: %t, link_pin: %t, lsm: %t, missed_stats_kprobe_multi: %t, missed_stats_kprobe: %t, batch_update: %t, uprobe_refctroff: %t, fentry %t, get_func_ret %t",
HasOverrideHelper(), HasBuildId(), HasKprobeMulti(), HasUprobeMulti(),
HasModifyReturn(), HasModifyReturnSyscall(), HasSignalHelper(), HasProgramLargeSize(),
HasLinkPin(), HasLSMPrograms(), HasMissedStatsKprobeMulti(), HasMissedStatsPerfEvent(),
HasBatchAPI(), HasUprobeRefCtrOffset())
HasBatchAPI(), HasUprobeRefCtrOffset(), HasFentryProgram(), HasGetFuncRetHelper())
}
13 changes: 13 additions & 0 deletions pkg/config/config_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ func GenericKprobeObjs(multi bool) (string, string) {
return "bpf_generic_kprobe.o", "bpf_generic_retkprobe.o"
}

func GenericTracingObjs() (string, string) {
if EnableV612Progs() {
return "bpf_generic_fentry_v612.o", "bpf_generic_fexit_v612.o"
} else if EnableV61Progs() {
return "bpf_generic_fentry_v61.o", "bpf_generic_fexit_v61.o"
} else if kernels.MinKernelVersion("5.11") {
return "bpf_generic_fentry_v511.o", "bpf_generic_fexit_v511.o"
} else if EnableLargeProgs() {
return "bpf_generic_fentry_v53.o", "bpf_generic_fexit_v53.o"
}
return "bpf_generic_fentry.o", "bpf_generic_fexit.o"
}

func GenericUprobeObjs(multi bool) string {
if multi {
if EnableV612Progs() {
Expand Down
Loading
Loading