Skip to content

Commit 23a1356

Browse files
committed
feat: dynamic length event
Change from a fixed type for events from BPF to a variable length one. This is done by using a helper map in which we can write all the information for a given event, then submit it to the ringbuffer with the bpf_ringbuf_output helper. On the userspace, we get a RingBufItem which can be treated as a slice of bytes we can split to retrieve fields one by one. This change needs to be properly tested for performance, we should use a lot less space for each event in the ringbuffer but serializing and deserializing each event might require more CPU. TODO: Document the format for the serialized event in the ringbuffer. TODO: Add tests for the event::parser module.
1 parent c4ee502 commit 23a1356

15 files changed

Lines changed: 854 additions & 428 deletions

File tree

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ license = "MIT OR Apache-2.0"
1414
aya = { version = "0.13.1", default-features = false }
1515

1616
anyhow = { version = "1", default-features = false, features = ["std", "backtrace"] }
17+
byteorder = "1.5.0"
1718
clap = { version = "4.5.41", features = ["derive", "env"] }
1819
env_logger = { version = "0.11.5", default-features = false, features = ["humantime"] }
1920
glob = "0.3.3"

fact-ebpf/src/bpf/bound_path.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ __always_inline static enum path_append_status_t path_append_dentry(struct bound
7272

7373
path->len += len;
7474
path_write_char(path->path, path->len, '\0');
75+
path->len++;
7576

7677
return 0;
7778
}

fact-ebpf/src/bpf/events.h

Lines changed: 115 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,139 +8,186 @@
88
#include "maps.h"
99
#include "process.h"
1010
#include "types.h"
11+
#include "raw_event.h"
1112

1213
#include <bpf/bpf_helpers.h>
1314
// clang-format on
1415

1516
struct submit_event_args_t {
16-
struct event_t* event;
1717
struct metrics_by_hook_t* metrics;
18-
const char* filename;
18+
struct bound_path_t* filename;
1919
inode_key_t inode;
2020
inode_key_t parent_inode;
2121
monitored_t monitored;
2222
};
2323

24-
__always_inline static bool reserve_event(struct submit_event_args_t* args) {
25-
args->event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0);
26-
if (args->event == NULL) {
24+
__always_inline static long fill_base_event(struct submit_event_args_t* args,
25+
struct raw_event_t* event,
26+
file_activity_type_t type,
27+
bool use_bpf_d_path) {
28+
raw_event_copy_u16(event, type);
29+
raw_event_copy_u64(event, bpf_ktime_get_boot_ns());
30+
31+
int64_t err = process_fill(event, use_bpf_d_path);
32+
if (err) {
33+
bpf_printk("Failed to fill process information: %d", err);
34+
return -1;
35+
}
36+
37+
// File data
38+
raw_event_copy_u8(event, args->monitored);
39+
raw_event_copy_inode(event, &args->inode);
40+
raw_event_copy_inode(event, &args->parent_inode);
41+
raw_event_copy_bound_path(event, args->filename);
42+
43+
return 0;
44+
}
45+
46+
__always_inline static void __submit_event(struct submit_event_args_t* args, struct raw_event_t* event) {
47+
if (bpf_ringbuf_output(&rb, event->buf, event->len, 0) != 0) {
2748
args->metrics->ringbuffer_full++;
28-
return false;
49+
return;
2950
}
30-
return true;
51+
args->metrics->added++;
3152
}
3253

33-
__always_inline static void __submit_event(struct submit_event_args_t* args,
34-
bool use_bpf_d_path) {
35-
struct event_t* event = args->event;
36-
event->timestamp = bpf_ktime_get_boot_ns();
37-
event->monitored = args->monitored;
38-
inode_copy(&event->inode, &args->inode);
39-
inode_copy(&event->parent_inode, &args->parent_inode);
40-
bpf_probe_read_str(event->filename, PATH_MAX, args->filename);
41-
42-
struct helper_t* helper = get_helper();
43-
if (helper == NULL) {
54+
__always_inline static void submit_open_event(struct submit_event_args_t* args,
55+
file_activity_type_t type) {
56+
struct raw_event_t event = INIT_RAW_EVENT();
57+
if (event.buf == NULL) {
4458
goto error;
4559
}
4660

47-
int64_t err = process_fill(&event->process, use_bpf_d_path);
48-
if (err) {
49-
bpf_printk("Failed to fill process information: %d", err);
61+
if (fill_base_event(args, &event, type, true) != 0) {
5062
goto error;
5163
}
5264

53-
args->metrics->added++;
54-
bpf_ringbuf_submit(event, 0);
65+
__submit_event(args, &event);
5566
return;
5667

5768
error:
5869
args->metrics->error++;
59-
bpf_ringbuf_discard(event, 0);
6070
}
6171

62-
__always_inline static void submit_open_event(struct submit_event_args_t* args,
63-
file_activity_type_t event_type) {
64-
if (!reserve_event(args)) {
65-
return;
72+
__always_inline static void submit_unlink_event(struct submit_event_args_t* args) {
73+
struct raw_event_t event = INIT_RAW_EVENT();
74+
if (event.buf == NULL) {
75+
goto error;
6676
}
67-
args->event->type = event_type;
6877

69-
__submit_event(args, true);
70-
}
71-
72-
__always_inline static void submit_unlink_event(struct submit_event_args_t* args) {
73-
if (!reserve_event(args)) {
74-
return;
78+
if (fill_base_event(args, &event, FILE_ACTIVITY_UNLINK, path_hooks_support_bpf_d_path) != 0) {
79+
goto error;
7580
}
76-
args->event->type = FILE_ACTIVITY_UNLINK;
7781

78-
__submit_event(args, path_hooks_support_bpf_d_path);
82+
__submit_event(args, &event);
83+
return;
84+
85+
error:
86+
args->metrics->error++;
7987
}
8088

8189
__always_inline static void submit_mode_event(struct submit_event_args_t* args,
8290
umode_t mode,
8391
umode_t old_mode) {
84-
if (!reserve_event(args)) {
85-
return;
92+
struct raw_event_t event = INIT_RAW_EVENT();
93+
if (event.buf == NULL) {
94+
goto error;
95+
}
96+
97+
if (fill_base_event(args, &event, FILE_ACTIVITY_CHMOD, path_hooks_support_bpf_d_path) != 0) {
98+
goto error;
8699
}
87100

88-
args->event->type = FILE_ACTIVITY_CHMOD;
89-
args->event->chmod.new = mode;
90-
args->event->chmod.old = old_mode;
101+
raw_event_copy_u16(&event, mode);
102+
raw_event_copy_u16(&event, old_mode);
91103

92-
__submit_event(args, path_hooks_support_bpf_d_path);
104+
__submit_event(args, &event);
105+
return;
106+
107+
error:
108+
args->metrics->error++;
93109
}
94110

95111
__always_inline static void submit_ownership_event(struct submit_event_args_t* args,
96112
unsigned long long uid,
97113
unsigned long long gid,
98114
unsigned long long old_uid,
99115
unsigned long long old_gid) {
100-
if (!reserve_event(args)) {
101-
return;
116+
struct raw_event_t event = INIT_RAW_EVENT();
117+
if (event.buf == NULL) {
118+
goto error;
119+
}
120+
121+
if (fill_base_event(args, &event, FILE_ACTIVITY_CHOWN, path_hooks_support_bpf_d_path) != 0) {
122+
goto error;
102123
}
103124

104-
args->event->type = FILE_ACTIVITY_CHOWN;
105-
args->event->chown.new.uid = uid;
106-
args->event->chown.new.gid = gid;
107-
args->event->chown.old.uid = old_uid;
108-
args->event->chown.old.gid = old_gid;
125+
raw_event_copy_u32(&event, uid);
126+
raw_event_copy_u32(&event, gid);
127+
raw_event_copy_u32(&event, old_uid);
128+
raw_event_copy_u32(&event, old_gid);
109129

110-
__submit_event(args, path_hooks_support_bpf_d_path);
130+
__submit_event(args, &event);
131+
return;
132+
133+
error:
134+
args->metrics->error++;
111135
}
112136

113137
__always_inline static void submit_rename_event(struct submit_event_args_t* args,
114-
const char old_filename[PATH_MAX],
138+
const struct bound_path_t* const filename,
115139
inode_key_t* old_inode,
116140
monitored_t old_monitored) {
117-
if (!reserve_event(args)) {
118-
return;
141+
struct raw_event_t event = INIT_RAW_EVENT();
142+
if (event.buf == NULL) {
143+
goto error;
144+
}
145+
146+
if (fill_base_event(args, &event, FILE_ACTIVITY_RENAME, path_hooks_support_bpf_d_path) != 0) {
147+
goto error;
119148
}
120149

121-
args->event->type = FILE_ACTIVITY_RENAME;
122-
bpf_probe_read_str(args->event->rename.filename, PATH_MAX, old_filename);
123-
inode_copy(&args->event->rename.inode, old_inode);
124-
args->event->rename.monitored = old_monitored;
150+
raw_event_copy_u8(&event, old_monitored);
151+
raw_event_copy_inode(&event, old_inode);
152+
raw_event_copy_bound_path(&event, filename);
125153

126-
__submit_event(args, path_hooks_support_bpf_d_path);
154+
__submit_event(args, &event);
155+
return;
156+
157+
error:
158+
args->metrics->error++;
127159
}
128160

129161
__always_inline static void submit_mkdir_event(struct submit_event_args_t* args) {
130-
if (!reserve_event(args)) {
131-
return;
162+
struct raw_event_t event = INIT_RAW_EVENT();
163+
if (event.buf == NULL) {
164+
goto error;
165+
}
166+
167+
if (fill_base_event(args, &event, DIR_ACTIVITY_CREATION, false) != 0) {
168+
goto error;
132169
}
133-
args->event->type = DIR_ACTIVITY_CREATION;
134170

135-
// d_instantiate doesn't support bpf_d_path, so we use false and rely on the stashed path from path_mkdir
136-
__submit_event(args, false);
171+
__submit_event(args, &event);
172+
return;
173+
174+
error:
175+
args->metrics->error++;
137176
}
138177

139178
__always_inline static void submit_rmdir_event(struct submit_event_args_t* args) {
140-
if (!reserve_event(args)) {
141-
return;
179+
struct raw_event_t event = INIT_RAW_EVENT();
180+
if (event.buf == NULL) {
181+
goto error;
182+
}
183+
184+
if (fill_base_event(args, &event, DIR_ACTIVITY_UNLINK, path_hooks_support_bpf_d_path) != 0) {
185+
goto error;
142186
}
143-
args->event->type = DIR_ACTIVITY_UNLINK;
144187

145-
__submit_event(args, path_hooks_support_bpf_d_path);
188+
__submit_event(args, &event);
189+
return;
190+
191+
error:
192+
args->metrics->error++;
146193
}

0 commit comments

Comments
 (0)