feat(go): advance validation sidecar toward production
This commit is contained in:
parent
6a06eba255
commit
f85c2e831a
92 changed files with 8881 additions and 91 deletions
212
go-agent/internal/ebpfsource/bpf/syscall.bpf.c
Normal file
212
go-agent/internal/ebpfsource/bpf/syscall.bpf.c
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#define SEC(name) __attribute__((section(name), used))
|
||||
#define __uint(name, value) int (*name)[value]
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
#define BPF_MAP_TYPE_HASH 1
|
||||
#define BPF_MAP_TYPE_PERF_EVENT_ARRAY 4
|
||||
#define BPF_F_CURRENT_CPU 0xffffffffULL
|
||||
|
||||
struct trace_event_raw_sys_enter {
|
||||
u64 _common;
|
||||
long id;
|
||||
unsigned long args[6];
|
||||
};
|
||||
|
||||
struct trace_event_raw_sys_exit {
|
||||
u64 _common;
|
||||
long id;
|
||||
long ret;
|
||||
};
|
||||
|
||||
struct task_struct {
|
||||
int tgid;
|
||||
struct task_struct *real_parent;
|
||||
} __attribute__((preserve_access_index));
|
||||
|
||||
struct syscall_event {
|
||||
u32 pid;
|
||||
u32 ppid;
|
||||
u32 uid;
|
||||
u32 syscall_id;
|
||||
char comm[16];
|
||||
u64 args[6];
|
||||
char text[80];
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(key_size, sizeof(u64));
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(max_entries, 64);
|
||||
} monitored_syscalls SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(key_size, 16);
|
||||
__uint(value_size, sizeof(u32));
|
||||
__uint(max_entries, 64);
|
||||
} monitored_host_comms SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(key_size, sizeof(u64));
|
||||
__uint(value_size, sizeof(struct syscall_event));
|
||||
__uint(max_entries, 4096);
|
||||
} pending_returns SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(u32));
|
||||
__uint(value_size, sizeof(u32));
|
||||
} syscall_events SEC(".maps");
|
||||
|
||||
static u64 (*bpf_get_current_pid_tgid)(void) = (void *)14;
|
||||
static u64 (*bpf_get_current_uid_gid)(void) = (void *)15;
|
||||
static long (*bpf_get_current_comm)(void *buf, u32 size) = (void *)16;
|
||||
static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *)1;
|
||||
static long (*bpf_map_update_elem)(void *map, const void *key, const void *value, u64 flags) = (void *)2;
|
||||
static long (*bpf_map_delete_elem)(void *map, const void *key) = (void *)3;
|
||||
static long (*bpf_probe_read_user_str)(void *dst, u32 size, const void *unsafe_ptr) = (void *)114;
|
||||
static long (*bpf_probe_read_user)(void *dst, u32 size, const void *unsafe_ptr) = (void *)112;
|
||||
static long (*bpf_probe_read_kernel)(void *dst, u32 size, const void *unsafe_ptr) = (void *)113;
|
||||
static long (*bpf_perf_event_output)(void *ctx, void *map, u64 flags,
|
||||
void *data, u64 size) = (void *)25;
|
||||
static u64 (*bpf_get_current_task)(void) = (void *)35;
|
||||
|
||||
#define bpf_core_read(dst, size, src) \
|
||||
bpf_probe_read_kernel((dst), (size), \
|
||||
(const void *)__builtin_preserve_access_index(src))
|
||||
|
||||
SEC("tracepoint/raw_syscalls/sys_enter")
|
||||
int trace_sys_enter(struct trace_event_raw_sys_enter *ctx)
|
||||
{
|
||||
u64 syscall_number = ctx->id;
|
||||
u32 *syscall_id = bpf_map_lookup_elem(&monitored_syscalls, &syscall_number);
|
||||
struct syscall_event event = {};
|
||||
struct task_struct *task;
|
||||
struct task_struct *parent = 0;
|
||||
|
||||
if (!syscall_id)
|
||||
return 0;
|
||||
|
||||
task = (struct task_struct *)bpf_get_current_task();
|
||||
event.pid = bpf_get_current_pid_tgid() >> 32;
|
||||
event.uid = bpf_get_current_uid_gid();
|
||||
event.syscall_id = *syscall_id;
|
||||
bpf_core_read(&parent, sizeof(parent), &task->real_parent);
|
||||
if (parent)
|
||||
bpf_core_read(&event.ppid, sizeof(event.ppid), &parent->tgid);
|
||||
bpf_get_current_comm(event.comm, sizeof(event.comm));
|
||||
|
||||
// Canonical ID 21 covers write/writev/pwrite variants. Keep the hot path
|
||||
// in-kernel and emit only for process names that can satisfy the
|
||||
// persistence-write host rule.
|
||||
if (*syscall_id >= 21 && *syscall_id <= 26 &&
|
||||
!bpf_map_lookup_elem(&monitored_host_comms, event.comm))
|
||||
return 0;
|
||||
|
||||
// Match the Python BCC transport's semantic argument layout rather than
|
||||
// exposing pointer-only raw ABI slots in alert keys and details.
|
||||
if (*syscall_id == 3) { // memfd_create(name, flags)
|
||||
event.args[0] = ctx->args[1];
|
||||
bpf_probe_read_user_str(event.text, sizeof(event.text),
|
||||
(const void *)ctx->args[0]);
|
||||
} else if (*syscall_id == 7 || *syscall_id == 8) { // process_vm_{readv,writev}
|
||||
event.args[0] = ctx->args[0]; // target pid
|
||||
event.args[1] = ctx->args[2]; // local iovec count
|
||||
event.args[2] = ctx->args[4]; // remote iovec count
|
||||
event.args[3] = ctx->args[5]; // flags
|
||||
} else if (*syscall_id == 14) { // chmod(path, mode)
|
||||
event.args[0] = ctx->args[1];
|
||||
event.args[2] = (u64)-100; // AT_FDCWD
|
||||
bpf_probe_read_user_str(event.text, sizeof(event.text),
|
||||
(const void *)ctx->args[0]);
|
||||
} else if (*syscall_id == 15) { // fchmodat(dirfd, path, mode)
|
||||
event.args[0] = ctx->args[2];
|
||||
event.args[2] = ctx->args[0];
|
||||
bpf_probe_read_user_str(event.text, sizeof(event.text),
|
||||
(const void *)ctx->args[1]);
|
||||
} else if (*syscall_id == 16 || *syscall_id == 17) { // chown/lchown(path, uid, gid)
|
||||
event.args[0] = ctx->args[1];
|
||||
event.args[1] = ctx->args[2];
|
||||
event.args[2] = (u64)-100; // AT_FDCWD
|
||||
bpf_probe_read_user_str(event.text, sizeof(event.text),
|
||||
(const void *)ctx->args[0]);
|
||||
} else if (*syscall_id == 18) { // fchownat(dirfd, path, uid, gid)
|
||||
event.args[0] = ctx->args[2];
|
||||
event.args[1] = ctx->args[3];
|
||||
event.args[2] = ctx->args[0];
|
||||
bpf_probe_read_user_str(event.text, sizeof(event.text),
|
||||
(const void *)ctx->args[1]);
|
||||
} else if (*syscall_id == 19) { // capset(header, data[2])
|
||||
u32 effective_low = 0;
|
||||
u32 effective_high = 0;
|
||||
const char *data = (const char *)ctx->args[1];
|
||||
bpf_probe_read_user(&effective_low, sizeof(effective_low), data);
|
||||
bpf_probe_read_user(&effective_high, sizeof(effective_high), data + 12);
|
||||
event.args[0] = effective_low | ((u64)effective_high << 32);
|
||||
} else if (*syscall_id == 22 || *syscall_id == 23) { // connect/bind(fd, sockaddr, len)
|
||||
const char *address = (const char *)ctx->args[1];
|
||||
u16 family = 0;
|
||||
u16 port = 0;
|
||||
u32 ipv4 = 0;
|
||||
bpf_probe_read_user(&family, sizeof(family), address);
|
||||
bpf_probe_read_user(&port, sizeof(port), address + 2);
|
||||
event.args[0] = family;
|
||||
event.args[3] = ctx->args[0];
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
event.args[1] = __builtin_bswap16(port);
|
||||
#else
|
||||
event.args[1] = port;
|
||||
#endif
|
||||
if (family == 2) {
|
||||
bpf_probe_read_user(&ipv4, sizeof(ipv4), address + 4);
|
||||
event.args[2] = ipv4;
|
||||
} else if (family == 10) {
|
||||
bpf_probe_read_user(event.text, 16, address + 8);
|
||||
}
|
||||
} else if (*syscall_id >= 24 && *syscall_id <= 26) { // listen/accept/accept4
|
||||
event.args[3] = ctx->args[0];
|
||||
} else {
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 6; i++)
|
||||
event.args[i] = ctx->args[i];
|
||||
}
|
||||
|
||||
if (*syscall_id >= 21 && *syscall_id <= 26) {
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
bpf_map_update_elem(&pending_returns, &pid_tgid, &event, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bpf_perf_event_output(ctx, &syscall_events, BPF_F_CURRENT_CPU, &event, sizeof(event));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tracepoint/raw_syscalls/sys_exit")
|
||||
int trace_sys_exit(struct trace_event_raw_sys_exit *ctx)
|
||||
{
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
struct syscall_event *event = bpf_map_lookup_elem(&pending_returns, &pid_tgid);
|
||||
|
||||
if (!event)
|
||||
return 0;
|
||||
if (event->syscall_id == 25 || event->syscall_id == 26)
|
||||
event->args[3] = ctx->ret;
|
||||
// Every write-family syscall returns its byte count, so the shared
|
||||
// canonical event is confirmed only when at least one byte was written.
|
||||
if ((event->syscall_id == 21 && ctx->ret > 0) ||
|
||||
(event->syscall_id >= 22 && event->syscall_id <= 24 && ctx->ret == 0) ||
|
||||
((event->syscall_id == 25 || event->syscall_id == 26) && ctx->ret >= 0))
|
||||
bpf_perf_event_output(ctx, &syscall_events, BPF_F_CURRENT_CPU,
|
||||
event, sizeof(*event));
|
||||
bpf_map_delete_elem(&pending_returns, &pid_tgid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
Loading…
Add table
Add a link
Reference in a new issue