mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-11-03 06:04:04 +08:00
Make exec image inspection a persistent monitor (#223)
* Rebase lesson 54 as a standalone monitor * docs: preserve lesson 54 introduction * docs: remove design aside from lesson 54 * Simplify lesson 54 to the monitor path --------- Co-authored-by: LinuxDev9002 <i@littlefisher.me>
This commit is contained in:
@@ -16,9 +16,6 @@ char LICENSE[] SEC("license") = "GPL";
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
const volatile __u32 target_tgid;
|
||||
const volatile __u32 probe_offset;
|
||||
|
||||
struct inspector_stats stats;
|
||||
|
||||
struct {
|
||||
@@ -28,14 +25,14 @@ struct {
|
||||
|
||||
struct exec_work {
|
||||
__u64 scheduled_ns;
|
||||
int direct_probe_error;
|
||||
struct bpf_task_work work;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__uint(max_entries, 4096);
|
||||
__type(key, __u64);
|
||||
__type(value, struct exec_work);
|
||||
} pending SEC(".maps");
|
||||
|
||||
@@ -46,36 +43,6 @@ static __u16 read_elf_u16(const unsigned char *header, int offset, __u8 data)
|
||||
return header[offset] | ((__u16)header[offset + 1] << 8);
|
||||
}
|
||||
|
||||
static int probe_file_without_sleep(struct file *file)
|
||||
{
|
||||
unsigned char sample[EXEC_PROBE_LEN];
|
||||
struct bpf_dynptr dynptr;
|
||||
int err;
|
||||
|
||||
if (!probe_offset)
|
||||
return 0;
|
||||
|
||||
__sync_fetch_and_add(&stats.direct_probes, 1);
|
||||
if (!file) {
|
||||
err = -ENOENT;
|
||||
goto record;
|
||||
}
|
||||
|
||||
err = bpf_dynptr_from_file(file, 0, &dynptr);
|
||||
if (err) {
|
||||
bpf_dynptr_file_discard(&dynptr);
|
||||
goto record;
|
||||
}
|
||||
|
||||
err = bpf_dynptr_read(sample, sizeof(sample), &dynptr, probe_offset, 0);
|
||||
bpf_dynptr_file_discard(&dynptr);
|
||||
|
||||
record:
|
||||
if (err)
|
||||
__sync_fetch_and_add(&stats.direct_probe_errors, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int inspect_executable(struct bpf_map *map, void *key, void *value)
|
||||
{
|
||||
unsigned char header[64] = {};
|
||||
@@ -87,16 +54,11 @@ static int inspect_executable(struct bpf_map *map, void *key, void *value)
|
||||
__u64 pid_tgid;
|
||||
int err;
|
||||
|
||||
(void)map;
|
||||
(void)key;
|
||||
__sync_fetch_and_add(&stats.callbacks, 1);
|
||||
|
||||
pid_tgid = bpf_get_current_pid_tgid();
|
||||
event.pid = (__u32)pid_tgid;
|
||||
event.tgid = pid_tgid >> 32;
|
||||
event.latency_ns = bpf_ktime_get_ns() - work->scheduled_ns;
|
||||
event.direct_probe_error = work->direct_probe_error;
|
||||
event.probe_offset = probe_offset;
|
||||
bpf_get_current_comm(event.comm, sizeof(event.comm));
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
@@ -104,11 +66,6 @@ static int inspect_executable(struct bpf_map *map, void *key, void *value)
|
||||
if (!file) {
|
||||
event.header_error = -ENOENT;
|
||||
__sync_fetch_and_add(&stats.header_errors, 1);
|
||||
if (probe_offset) {
|
||||
event.deferred_probe_error = -ENOENT;
|
||||
__sync_fetch_and_add(&stats.deferred_probes, 1);
|
||||
__sync_fetch_and_add(&stats.deferred_probe_errors, 1);
|
||||
}
|
||||
goto emit;
|
||||
}
|
||||
|
||||
@@ -123,11 +80,6 @@ static int inspect_executable(struct bpf_map *map, void *key, void *value)
|
||||
bpf_dynptr_file_discard(&dynptr);
|
||||
event.header_error = err;
|
||||
__sync_fetch_and_add(&stats.header_errors, 1);
|
||||
if (probe_offset) {
|
||||
event.deferred_probe_error = err;
|
||||
__sync_fetch_and_add(&stats.deferred_probes, 1);
|
||||
__sync_fetch_and_add(&stats.deferred_probe_errors, 1);
|
||||
}
|
||||
goto put_file;
|
||||
}
|
||||
|
||||
@@ -136,15 +88,6 @@ static int inspect_executable(struct bpf_map *map, void *key, void *value)
|
||||
event.header_error = err;
|
||||
__sync_fetch_and_add(&stats.header_errors, 1);
|
||||
}
|
||||
|
||||
if (probe_offset) {
|
||||
__sync_fetch_and_add(&stats.deferred_probes, 1);
|
||||
err = bpf_dynptr_read(event.probe_bytes, sizeof(event.probe_bytes),
|
||||
&dynptr, probe_offset, 0);
|
||||
event.deferred_probe_error = err;
|
||||
if (err)
|
||||
__sync_fetch_and_add(&stats.deferred_probe_errors, 1);
|
||||
}
|
||||
bpf_dynptr_file_discard(&dynptr);
|
||||
|
||||
if (!event.header_error && header[0] == 0x7f && header[1] == 'E' &&
|
||||
@@ -161,6 +104,9 @@ put_file:
|
||||
emit:
|
||||
if (bpf_ringbuf_output(&events, &event, sizeof(event), 0))
|
||||
__sync_fetch_and_add(&stats.dropped, 1);
|
||||
if (bpf_map_delete_elem(map, key))
|
||||
__sync_fetch_and_add(&stats.cleanup_errors, 1);
|
||||
__sync_fetch_and_add(&stats.completed, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -168,30 +114,37 @@ SEC("lsm/bprm_committed_creds")
|
||||
void BPF_PROG(schedule_exec_inspection, struct linux_binprm *bprm)
|
||||
{
|
||||
struct task_struct *task;
|
||||
struct exec_work empty_work = {};
|
||||
struct exec_work *work;
|
||||
__u64 pid_tgid;
|
||||
__u32 key = 0, tgid;
|
||||
__u64 key;
|
||||
int err;
|
||||
|
||||
(void)bprm;
|
||||
pid_tgid = bpf_get_current_pid_tgid();
|
||||
tgid = pid_tgid >> 32;
|
||||
if (target_tgid && tgid != target_tgid)
|
||||
return;
|
||||
|
||||
key = pid_tgid;
|
||||
__sync_fetch_and_add(&stats.matched, 1);
|
||||
err = bpf_map_update_elem(&pending, &key, &empty_work, BPF_NOEXIST);
|
||||
if (err) {
|
||||
__sync_fetch_and_add(&stats.schedule_errors, 1);
|
||||
return;
|
||||
}
|
||||
work = bpf_map_lookup_elem(&pending, &key);
|
||||
if (!work) {
|
||||
__sync_fetch_and_add(&stats.schedule_errors, 1);
|
||||
if (bpf_map_delete_elem(&pending, &key))
|
||||
__sync_fetch_and_add(&stats.cleanup_errors, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
work->scheduled_ns = bpf_ktime_get_ns();
|
||||
work->direct_probe_error = probe_file_without_sleep(bprm->file);
|
||||
task = bpf_get_current_task_btf();
|
||||
err = bpf_task_work_schedule_signal(task, &work->work, &pending,
|
||||
inspect_executable);
|
||||
if (err) {
|
||||
__sync_fetch_and_add(&stats.schedule_errors, 1);
|
||||
if (bpf_map_delete_elem(&pending, &key))
|
||||
__sync_fetch_and_add(&stats.cleanup_errors, 1);
|
||||
return;
|
||||
}
|
||||
__sync_fetch_and_add(&stats.scheduled, 1);
|
||||
|
||||
Reference in New Issue
Block a user