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:
云微
2026-07-22 12:29:09 -07:00
committed by GitHub
parent 237fab199f
commit 90e93e05f6
8 changed files with 343 additions and 1889 deletions

View File

@@ -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);