Skip to content

Commit

Permalink
EventProbe: capture file info from inode (#178)
Browse files Browse the repository at this point in the history
* EventProbe: capture file info from inode

* add file info tests

* apply suggestions
  • Loading branch information
mmat11 authored Oct 27, 2023
1 parent 039ceef commit 1e2cf70
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 13 deletions.
33 changes: 30 additions & 3 deletions GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ enum ebpf_varlen_field_type {
EBPF_VL_FIELD_NEW_PATH,
EBPF_VL_FIELD_TTY_OUT,
EBPF_VL_FIELD_PIDS_SS_CGROUP_PATH,
EBPF_VL_FIELD_SYMLINK_TARGET_PATH,
};

// Convenience macro to iterate all the variable length fields in an event
Expand Down Expand Up @@ -117,34 +118,60 @@ struct ebpf_tty_dev {
struct ebpf_tty_termios termios;
} __attribute__((packed));

enum ebpf_file_type {
EBPF_FILE_TYPE_UNKNOWN = 0,
EBPF_FILE_TYPE_FILE = 1,
EBPF_FILE_TYPE_DIR = 2,
EBPF_FILE_TYPE_SYMLINK = 3,
EBPF_FILE_TYPE_CHARACTER_DEVICE = 4,
EBPF_FILE_TYPE_BLOCK_DEVICE = 5,
EBPF_FILE_TYPE_NAMED_PIPE = 6,
EBPF_FILE_TYPE_SOCKET = 7,
};

struct ebpf_file_info {
enum ebpf_file_type type;
uint64_t inode;
uint16_t mode;
uint64_t size;
uint32_t uid;
uint32_t gid;
uint64_t atime;
uint64_t mtime;
uint64_t ctime;
} __attribute__((packed));

// Full events follow
struct ebpf_file_delete_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info pids;
struct ebpf_file_info finfo;
uint32_t mntns;
char comm[TASK_COMM_LEN];

// Variable length fields: path
// Variable length fields: path, symlink_target_path
struct ebpf_varlen_fields_start vl_fields;
} __attribute__((packed));

struct ebpf_file_create_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info pids;
struct ebpf_file_info finfo;
uint32_t mntns;
char comm[TASK_COMM_LEN];

// Variable length fields: path
// Variable length fields: path, symlink_target_path
struct ebpf_varlen_fields_start vl_fields;
} __attribute__((packed));

struct ebpf_file_rename_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info pids;
struct ebpf_file_info finfo;
uint32_t mntns;
char comm[TASK_COMM_LEN];

// Variable length fields: old_path, new_path
// Variable length fields: old_path, new_path, symlink_target_path
struct ebpf_varlen_fields_start vl_fields;
} __attribute__((packed));

Expand Down
75 changes: 75 additions & 0 deletions GPL/Events/File/File.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause

/*
* Copyright (C) 2021 Elasticsearch BV
*
* This software is dual-licensed under the BSD 2-Clause and GPL v2 licenses.
* You may choose either one of them if you use this software.
*/

#ifndef EBPF_EVENTPROBE_FILE_H
#define EBPF_EVENTPROBE_FILE_H

#include "EbpfEventProto.h"

#define PATH_MAX 4096

// include/uapi/linux/stat.h
#define S_IFMT 00170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFIFO 0010000
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000

#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK)
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK)
#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO)
#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK)

#define NANOSECONDS_IN_SECOND 1000000000

static void ebpf_file_info__fill(struct ebpf_file_info *finfo, struct dentry *de)
{
struct inode *ino = BPF_CORE_READ(de, d_inode);

finfo->inode = BPF_CORE_READ(ino, i_ino);
finfo->mode = BPF_CORE_READ(ino, i_mode);
finfo->size = BPF_CORE_READ(ino, i_size);
finfo->uid = BPF_CORE_READ(ino, i_uid.val);
finfo->gid = BPF_CORE_READ(ino, i_gid.val);
finfo->atime = BPF_CORE_READ(ino, i_atime.tv_sec) * NANOSECONDS_IN_SECOND +
BPF_CORE_READ(ino, i_atime.tv_nsec);
finfo->mtime = BPF_CORE_READ(ino, i_mtime.tv_sec) * NANOSECONDS_IN_SECOND +
BPF_CORE_READ(ino, i_mtime.tv_nsec);
finfo->ctime = BPF_CORE_READ(ino, i_ctime.tv_sec) * NANOSECONDS_IN_SECOND +
BPF_CORE_READ(ino, i_ctime.tv_nsec);

if (S_ISREG(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_FILE;
} else if (S_ISDIR(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_DIR;
} else if (S_ISLNK(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_SYMLINK;
} else if (S_ISCHR(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_CHARACTER_DEVICE;
} else if (S_ISBLK(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_BLOCK_DEVICE;
} else if (S_ISFIFO(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_NAMED_PIPE;
} else if (S_ISSOCK(finfo->mode)) {
finfo->type = EBPF_FILE_TYPE_SOCKET;
} else {
finfo->type = EBPF_FILE_TYPE_UNKNOWN;
}
}

#endif // EBPF_EVENTPROBE_FILE_H
32 changes: 30 additions & 2 deletions GPL/Events/File/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#include "File.h"
#include "Helpers.h"
#include "PathResolver.h"
#include "State.h"
Expand Down Expand Up @@ -123,10 +124,11 @@ static int vfs_unlink__exit(int ret)
ebpf_pid_info__fill(&event->pids, task);

struct path p;
p.dentry = state->unlink.de;
p.dentry = &state->unlink.de;
p.mnt = state->unlink.mnt;
event->mntns = mntns(task);
bpf_get_current_comm(event->comm, TASK_COMM_LEN);
ebpf_file_info__fill(&event->finfo, p.dentry);

// Variable length fields
ebpf_vl_fields__init(&event->vl_fields);
Expand All @@ -138,6 +140,12 @@ static int vfs_unlink__exit(int ret)
size = ebpf_resolve_path_to_string(field->data, &p, task);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

// symlink_target_path
field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_SYMLINK_TARGET_PATH);
char *link = BPF_CORE_READ(p.dentry, d_inode, i_link);
size = read_kernel_str_or_empty_str(field->data, PATH_MAX, link);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);

// Certain filesystems (eg. overlayfs) call vfs_unlink twice during the same
Expand Down Expand Up @@ -170,7 +178,10 @@ static int vfs_unlink__enter(struct dentry *de)
goto out;
}

state->unlink.de = de;
if (bpf_core_read(&state->unlink.de, sizeof(struct dentry), de)) {
bpf_printk("vfs_unlink__enter: failed to read dentry\n");
goto out;
}
state->unlink.step = UNLINK_STATE_DENTRY_SET;

out:
Expand Down Expand Up @@ -224,6 +235,7 @@ static int do_filp_open__exit(struct file *f)
ebpf_pid_info__fill(&event->pids, task);
event->mntns = mntns(task);
bpf_get_current_comm(event->comm, TASK_COMM_LEN);
ebpf_file_info__fill(&event->finfo, p.dentry);

// Variable length fields
ebpf_vl_fields__init(&event->vl_fields);
Expand All @@ -235,6 +247,12 @@ static int do_filp_open__exit(struct file *f)
size = ebpf_resolve_path_to_string(field->data, &p, task);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

// symlink_target_path
field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_SYMLINK_TARGET_PATH);
char *link = BPF_CORE_READ(p.dentry, d_inode, i_link);
size = read_kernel_str_or_empty_str(field->data, PATH_MAX, link);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
}

Expand Down Expand Up @@ -316,6 +334,7 @@ static int vfs_rename__enter(struct dentry *old_dentry, struct dentry *new_dentr
ebpf_resolve_path_to_string(ss->rename.new_path, &p, task);

state->rename.step = RENAME_STATE_PATHS_SET;
state->rename.de = old_dentry;

out:
return 0;
Expand Down Expand Up @@ -388,12 +407,15 @@ static int vfs_rename__exit(int ret)
goto out;

struct task_struct *task = (struct task_struct *)bpf_get_current_task();
// NOTE: this temp variable is necessary to keep the verifier happy
struct dentry *de = (struct dentry *)state->rename.de;

event->hdr.type = EBPF_EVENT_FILE_RENAME;
event->hdr.ts = bpf_ktime_get_ns();
ebpf_pid_info__fill(&event->pids, task);
event->mntns = mntns(task);
bpf_get_current_comm(event->comm, TASK_COMM_LEN);
ebpf_file_info__fill(&event->finfo, de);

// Variable length fields
ebpf_vl_fields__init(&event->vl_fields);
Expand All @@ -410,6 +432,12 @@ static int vfs_rename__exit(int ret)
size = read_kernel_str_or_empty_str(field->data, PATH_MAX, ss->rename.new_path);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

// symlink_target_path
field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_SYMLINK_TARGET_PATH);
char *link = BPF_CORE_READ(de, d_inode, i_link);
size = read_kernel_str_or_empty_str(field->data, PATH_MAX, link);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);

// Certain filesystems (eg. overlayfs) call vfs_rename twice during the same
Expand Down
6 changes: 5 additions & 1 deletion GPL/Events/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ enum ebpf_events_unlink_state_step {
struct ebpf_events_unlink_state {
enum ebpf_events_unlink_state_step step;
struct vfsmount *mnt;
struct dentry *de;
// NOTE: for this specific hook, storing a dentry pointer
// doesn't work because the content will be emptied out
// in the exit function.
struct dentry de;
};

enum ebpf_events_rename_state_step {
Expand All @@ -44,6 +47,7 @@ enum ebpf_events_rename_state_step {
struct ebpf_events_rename_state {
enum ebpf_events_rename_state_step step;
struct vfsmount *mnt;
struct dentry *de;
};

struct ebpf_events_tcp_connect_state {
Expand Down
Loading

0 comments on commit 1e2cf70

Please sign in to comment.