Skip to content

Commit 8c80535

Browse files
ROX-33218: Instrument inode tracking on directory being deleted (#530)
1 parent 47f1c08 commit 8c80535

9 files changed

Lines changed: 484 additions & 6 deletions

File tree

fact-ebpf/src/bpf/events.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,12 @@ __always_inline static void submit_mkdir_event(struct submit_event_args_t* args)
131131
// d_instantiate doesn't support bpf_d_path, so we use false and rely on the stashed path from path_mkdir
132132
__submit_event(args, false);
133133
}
134+
135+
__always_inline static void submit_rmdir_event(struct submit_event_args_t* args) {
136+
if (!reserve_event(args)) {
137+
return;
138+
}
139+
args->event->type = DIR_ACTIVITY_UNLINK;
140+
141+
__submit_event(args, path_hooks_support_bpf_d_path);
142+
}

fact-ebpf/src/bpf/main.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,34 @@ int BPF_PROG(trace_d_instantiate, struct dentry* dentry, struct inode* inode) {
326326
bpf_map_delete_elem(&mkdir_context, &pid_tgid);
327327
return 0;
328328
}
329+
330+
SEC("lsm/path_rmdir")
331+
int BPF_PROG(trace_path_rmdir, struct path* dir, struct dentry* dentry) {
332+
struct metrics_t* m = get_metrics();
333+
if (m == NULL) {
334+
return 0;
335+
}
336+
struct submit_event_args_t args = {.metrics = &m->path_rmdir};
337+
338+
args.metrics->total++;
339+
340+
struct bound_path_t* path = path_read_append_d_entry(dir, dentry);
341+
if (path == NULL) {
342+
bpf_printk("Failed to read directory path");
343+
m->path_rmdir.error++;
344+
return 0;
345+
}
346+
args.filename = path->path;
347+
348+
args.inode = inode_to_key(dentry->d_inode);
349+
350+
if (is_monitored(&args.inode, path, NULL) == NOT_MONITORED) {
351+
m->path_rmdir.ignored++;
352+
return 0;
353+
}
354+
355+
inode_remove(&args.inode);
356+
357+
submit_rmdir_event(&args);
358+
return 0;
359+
}

fact-ebpf/src/bpf/types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ typedef enum file_activity_type_t {
5656
FILE_ACTIVITY_CHOWN,
5757
FILE_ACTIVITY_RENAME,
5858
DIR_ACTIVITY_CREATION,
59+
DIR_ACTIVITY_UNLINK,
5960
} file_activity_type_t;
6061

6162
struct event_t {
@@ -120,4 +121,5 @@ struct metrics_t {
120121
struct metrics_by_hook_t path_rename;
121122
struct metrics_by_hook_t path_mkdir;
122123
struct metrics_by_hook_t d_instantiate;
124+
struct metrics_by_hook_t path_rmdir;
123125
};

fact-ebpf/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ impl metrics_t {
126126
m.path_chown = m.path_chown.accumulate(&other.path_chown);
127127
m.path_rename = m.path_rename.accumulate(&other.path_rename);
128128
m.path_mkdir = m.path_mkdir.accumulate(&other.path_mkdir);
129+
m.path_rmdir = m.path_rmdir.accumulate(&other.path_rmdir);
129130
m.d_instantiate = m.d_instantiate.accumulate(&other.d_instantiate);
130131
m
131132
}

fact/src/event/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,12 @@ impl Event {
134134
matches!(self.file, FileData::MkDir(_))
135135
}
136136

137-
pub fn is_unlink(&self) -> bool {
138-
matches!(self.file, FileData::Unlink(_))
137+
pub fn is_rmdir(&self) -> bool {
138+
matches!(self.file, FileData::RmDir(_))
139+
}
140+
141+
pub fn is_deletion(&self) -> bool {
142+
matches!(self.file, FileData::Unlink(_) | FileData::RmDir(_))
139143
}
140144

141145
/// Unwrap the inner FileData and return the inode that triggered
@@ -148,6 +152,7 @@ impl Event {
148152
FileData::Open(data) => &data.inode,
149153
FileData::Creation(data) => &data.inode,
150154
FileData::MkDir(data) => &data.inode,
155+
FileData::RmDir(data) => &data.inode,
151156
FileData::Unlink(data) => &data.inode,
152157
FileData::Chmod(data) => &data.inner.inode,
153158
FileData::Chown(data) => &data.inner.inode,
@@ -161,6 +166,7 @@ impl Event {
161166
FileData::Open(data) => &data.parent_inode,
162167
FileData::Creation(data) => &data.parent_inode,
163168
FileData::MkDir(data) => &data.parent_inode,
169+
FileData::RmDir(data) => &data.parent_inode,
164170
FileData::Unlink(data) => &data.parent_inode,
165171
FileData::Chmod(data) => &data.inner.parent_inode,
166172
FileData::Chown(data) => &data.inner.parent_inode,
@@ -183,6 +189,7 @@ impl Event {
183189
FileData::Open(data) => &data.filename,
184190
FileData::Creation(data) => &data.filename,
185191
FileData::MkDir(data) => &data.filename,
192+
FileData::RmDir(data) => &data.filename,
186193
FileData::Unlink(data) => &data.filename,
187194
FileData::Chmod(data) => &data.inner.filename,
188195
FileData::Chown(data) => &data.inner.filename,
@@ -202,6 +209,7 @@ impl Event {
202209
FileData::Open(data) => &data.host_file,
203210
FileData::Creation(data) => &data.host_file,
204211
FileData::MkDir(data) => &data.host_file,
212+
FileData::RmDir(data) => &data.host_file,
205213
FileData::Unlink(data) => &data.host_file,
206214
FileData::Chmod(data) => &data.inner.host_file,
207215
FileData::Chown(data) => &data.inner.host_file,
@@ -218,6 +226,7 @@ impl Event {
218226
FileData::Open(data) => data.host_file = host_path,
219227
FileData::Creation(data) => data.host_file = host_path,
220228
FileData::MkDir(data) => data.host_file = host_path,
229+
FileData::RmDir(data) => data.host_file = host_path,
221230
FileData::Unlink(data) => data.host_file = host_path,
222231
FileData::Chmod(data) => data.inner.host_file = host_path,
223232
FileData::Chown(data) => data.inner.host_file = host_path,
@@ -303,6 +312,7 @@ pub enum FileData {
303312
Open(BaseFileData),
304313
Creation(BaseFileData),
305314
MkDir(BaseFileData),
315+
RmDir(BaseFileData),
306316
Unlink(BaseFileData),
307317
Chmod(ChmodFileData),
308318
Chown(ChownFileData),
@@ -322,6 +332,7 @@ impl FileData {
322332
file_activity_type_t::FILE_ACTIVITY_OPEN => FileData::Open(inner),
323333
file_activity_type_t::FILE_ACTIVITY_CREATION => FileData::Creation(inner),
324334
file_activity_type_t::DIR_ACTIVITY_CREATION => FileData::MkDir(inner),
335+
file_activity_type_t::DIR_ACTIVITY_UNLINK => FileData::RmDir(inner),
325336
file_activity_type_t::FILE_ACTIVITY_UNLINK => FileData::Unlink(inner),
326337
file_activity_type_t::FILE_ACTIVITY_CHMOD => {
327338
let data = ChmodFileData {
@@ -373,6 +384,9 @@ impl From<FileData> for fact_api::file_activity::File {
373384
FileData::MkDir(_) => {
374385
unreachable!("MkDir event reached protobuf conversion");
375386
}
387+
FileData::RmDir(_) => {
388+
unreachable!("RmDir event reached protobuf conversion");
389+
}
376390
FileData::Unlink(event) => {
377391
let activity = Some(fact_api::FileActivityBase::from(event));
378392
let f_act = fact_api::FileUnlink { activity };
@@ -401,6 +415,7 @@ impl PartialEq for FileData {
401415
(FileData::Open(this), FileData::Open(other)) => this == other,
402416
(FileData::Creation(this), FileData::Creation(other)) => this == other,
403417
(FileData::MkDir(this), FileData::MkDir(other)) => this == other,
418+
(FileData::RmDir(this), FileData::RmDir(other)) => this == other,
404419
(FileData::Unlink(this), FileData::Unlink(other)) => this == other,
405420
(FileData::Chmod(this), FileData::Chmod(other)) => this == other,
406421
(FileData::Rename(this), FileData::Rename(other)) => this == other,

fact/src/host_scanner.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,12 @@ impl HostScanner {
291291
}
292292

293293
// Remove inode from the map
294-
if event.is_unlink() {
294+
if event.is_deletion() {
295295
self.handle_unlink_event(&event);
296296
}
297297

298-
// Skip directory creation events - we track them internally but don't send to sensor
299-
if event.is_mkdir() {
298+
// Skip directory creation and deletion events - we track them internally but don't send to sensor
299+
if event.is_mkdir() || event.is_rmdir() {
300300
continue;
301301
}
302302

fact/src/metrics/kernel_metrics.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub struct KernelMetrics {
1414
path_chown: EventCounter,
1515
path_rename: EventCounter,
1616
path_mkdir: EventCounter,
17+
path_rmdir: EventCounter,
1718
d_instantiate: EventCounter,
1819
map: PerCpuArray<MapData, metrics_t>,
1920
}
@@ -50,6 +51,11 @@ impl KernelMetrics {
5051
"Events processed by the path_mkdir LSM hook",
5152
&[], // Labels are not needed since `collect` will add them all
5253
);
54+
let path_rmdir = EventCounter::new(
55+
"kernel_path_rmdir_events",
56+
"Events processed by the path_rmdir LSM hook",
57+
&[], // Labels are not needed since `collect` will add them all
58+
);
5359
let d_instantiate = EventCounter::new(
5460
"kernel_d_instantiate_events",
5561
"Events processed by the d_instantiate LSM hook",
@@ -62,6 +68,7 @@ impl KernelMetrics {
6268
path_chown.register(reg);
6369
path_rename.register(reg);
6470
path_mkdir.register(reg);
71+
path_rmdir.register(reg);
6572
d_instantiate.register(reg);
6673

6774
KernelMetrics {
@@ -71,6 +78,7 @@ impl KernelMetrics {
7178
path_chown,
7279
path_rename,
7380
path_mkdir,
81+
path_rmdir,
7482
d_instantiate,
7583
map: kernel_metrics,
7684
}
@@ -122,6 +130,7 @@ impl KernelMetrics {
122130
KernelMetrics::refresh_labels(&self.path_chown, &metrics.path_chown);
123131
KernelMetrics::refresh_labels(&self.path_rename, &metrics.path_rename);
124132
KernelMetrics::refresh_labels(&self.path_mkdir, &metrics.path_mkdir);
133+
KernelMetrics::refresh_labels(&self.path_rmdir, &metrics.path_rmdir);
125134
KernelMetrics::refresh_labels(&self.d_instantiate, &metrics.d_instantiate);
126135

127136
Ok(())

0 commit comments

Comments
 (0)