diff --git a/pkg/audit/mount/audit.go b/pkg/audit/mount/audit.go index e4d268f54766adec33dcb36b56f78964e41b6e6a..a5f6b1057d42abc20f546334ab47041c8075f255 100644 --- a/pkg/audit/mount/audit.go +++ b/pkg/audit/mount/audit.go @@ -31,6 +31,7 @@ const ( type auditLog struct { CGroupID uint64 PID uint32 + UID uint32 Ret int32 Nodename [NEW_UTS_LEN + 1]byte Command [TASK_COMM_LEN]byte diff --git a/pkg/bpf/c/common_structs.h b/pkg/bpf/c/common_structs.h index f51ac34b8872143eba9489fd19d95a327ebf9673..39d00f3be46432713f6c1e95e5e0c8e05d3267cc 100644 --- a/pkg/bpf/c/common_structs.h +++ b/pkg/bpf/c/common_structs.h @@ -7,6 +7,16 @@ #define AUDIT_EVENTS_RING_SIZE (4 * 4096) #define TASK_COMM_LEN 16 #define NEW_UTS_LEN 64 +#define NAME_MAX 255 +#define LOOP_NAME 80 +#define MAX_PATH_SIZE 4096 // PATH_MAX from +#define LIMIT_PATH_SIZE(x) ((x) & (MAX_PATH_SIZE - 1)) +#define MAX_PATH_COMPONENTS 20 + +#define MAX_PERCPU_ARRAY_SIZE (1 << 15) +#define HALF_PERCPU_ARRAY_SIZE (MAX_PERCPU_ARRAY_SIZE >> 1) +#define LIMIT_PERCPU_ARRAY_SIZE(x) ((x) & (MAX_PERCPU_ARRAY_SIZE - 1)) +#define LIMIT_HALF_PERCPU_ARRAY_SIZE(x) ((x) & (HALF_PERCPU_ARRAY_SIZE - 1)) #define VERSION_5_10 KERNEL_VERSION(5,10,0) #define NULL ((void *)0) @@ -45,6 +55,51 @@ enum lsm_hook_point SENDMSG // Not implemented yet. }; +struct file_path { + unsigned char path[NAME_MAX]; +}; + +struct callback_ctx { + unsigned char *path; + bool found; +}; + +struct file_open_audit_event { + u64 cgroup; + u32 pid; + u32 uid; + int ret; + char nodename[NEW_UTS_LEN + 1]; + char task[TASK_COMM_LEN]; + char parent_task[TASK_COMM_LEN]; + unsigned char path[NAME_MAX]; +}; //512 stack size restrict, now [479 - 64(cgroup) + 32(uid)] + other_stack + +struct fileopen_safeguard_config { + u32 mode; + u32 target; +}; + +struct mount_audit_event { + u64 cgroup; + u32 pid; + u32 uid; + int ret; + char nodename[NEW_UTS_LEN + 1]; + char task[TASK_COMM_LEN]; + char parent_task[TASK_COMM_LEN]; + unsigned char path[NAME_MAX]; +}; + +struct mount_safeguard_config { + u32 mode; + u32 target; +}; + +struct buffer { + u8 data[MAX_PERCPU_ARRAY_SIZE]; +}; + static inline int _is_host_mntns() { struct task_struct *current_task; @@ -96,3 +151,100 @@ static __always_inline int strlen(const unsigned char *s, size_t max_len) return i; } + +static long get_path_str_from_path(u_char **path_str, const struct path *path, struct buffer *out_buf, struct dentry *append) { + long ret; + struct dentry *dentry, *dentry_parent, *dentry_mnt; + struct vfsmount *vfsmnt; + struct mount *mnt, *mnt_parent; + const u_char *name; + size_t name_len; + + dentry = BPF_CORE_READ(path, dentry); + vfsmnt = BPF_CORE_READ(path, mnt); + mnt = container_of(vfsmnt, struct mount, mnt); + mnt_parent = BPF_CORE_READ(mnt, mnt_parent); + + size_t buf_off = HALF_PERCPU_ARRAY_SIZE - 1; + +#pragma unroll + for (int i = 0; i < MAX_PATH_COMPONENTS; i++) { + + dentry_mnt = BPF_CORE_READ(vfsmnt, mnt_root); + dentry_parent = BPF_CORE_READ(dentry, d_parent); + + if (dentry == dentry_mnt || dentry == dentry_parent) { + if (dentry != dentry_mnt) { + // We reached root, but not mount root - escaped? + break; + } + if (mnt != mnt_parent) { + // We reached root, but not global root - continue with mount point path + dentry = BPF_CORE_READ(mnt, mnt_mountpoint); + mnt_parent = BPF_CORE_READ(mnt, mnt_parent); + vfsmnt = __builtin_preserve_access_index(&mnt->mnt); + continue; + } + // Global root - path fully parsed + break; + } + + // Add this dentry name to path + name_len = LIMIT_PATH_SIZE(BPF_CORE_READ(dentry, d_name.len)); + name = BPF_CORE_READ(dentry, d_name.name); + + name_len = name_len + 1; + // Is string buffer big enough for dentry name? + if (name_len > buf_off) { break; } + volatile size_t new_buff_offset = buf_off - name_len; // satisfy verifier + ret = bpf_probe_read_kernel_str( + &(out_buf->data[LIMIT_HALF_PERCPU_ARRAY_SIZE(new_buff_offset)]),// satisfy verifie + name_len, name); + + if (ret < 0) { return ret; } + + if (ret > 1) { + buf_off -= 1; // remove null byte termination with slash sign + buf_off = LIMIT_HALF_PERCPU_ARRAY_SIZE(buf_off); // satisfy verifier + out_buf->data[buf_off] = '/'; + buf_off -= ret - 1; + buf_off = LIMIT_HALF_PERCPU_ARRAY_SIZE(buf_off); // satisfy verifier + } else { + // If sz is 0 or 1 we have an error (path can't be null nor an empty string) + break; + } + dentry = dentry_parent; + } + + // Is string buffer big enough for slash? + if (buf_off != 0) { + // Add leading slash + buf_off -= 1; + buf_off = LIMIT_HALF_PERCPU_ARRAY_SIZE(buf_off); // satisfy verifier + out_buf->data[buf_off] = '/'; + } + + // Null terminate the path string + out_buf->data[HALF_PERCPU_ARRAY_SIZE - 1] = 0; + *path_str = &out_buf->data[buf_off]; + + if (append) { + name_len = LIMIT_PATH_SIZE(BPF_CORE_READ(append, d_name.len)); + name = BPF_CORE_READ(append, d_name.name); + + ret = bpf_probe_read_kernel_str(&(out_buf->data[HALF_PERCPU_ARRAY_SIZE - 1]), name_len + 1, name); + } else { + out_buf->data[HALF_PERCPU_ARRAY_SIZE - 1 - 1] = 0; + } + + return HALF_PERCPU_ARRAY_SIZE - buf_off - 1; +} + +static u64 cb_check_path(struct bpf_map *map, u32 *key, struct file_path *map_path, struct callback_ctx *ctx) { + size_t size = strlen(map_path->path, NAME_MAX); + if (strcmp(map_path->path, ctx->path, size) == 0) { + ctx->found = true; + } + + return 0; +} diff --git a/pkg/bpf/c/restricted-file.bpf.c b/pkg/bpf/c/restricted-file.bpf.c index 67c9d41d27242606779c056d673cac51ab944e87..2c167539065d64bb741401e8eb932316ce044884 100644 --- a/pkg/bpf/c/restricted-file.bpf.c +++ b/pkg/bpf/c/restricted-file.bpf.c @@ -8,34 +8,6 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; -#define NAME_MAX 255 -#define LOOP_NAME 80 - -struct file_path { - unsigned char path[NAME_MAX]; -}; - -struct callback_ctx { - unsigned char *path; - bool found; -}; - -struct file_open_audit_event { - u64 cgroup; - u32 pid; - u32 uid; - int ret; - char nodename[NEW_UTS_LEN + 1]; - char task[TASK_COMM_LEN]; - char parent_task[TASK_COMM_LEN]; - unsigned char path[NAME_MAX]; -}; //512 stack size restrict, now [479 - 64(cgroup) + 32(uid)] + other_stack - -struct fileopen_safeguard_config { - u32 mode; - u32 target; -}; - struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __uint(key_size, sizeof(u32)); @@ -46,21 +18,6 @@ BPF_HASH(fileopen_safeguard_config_map, u32, struct fileopen_safeguard_config, 2 BPF_HASH(allowed_access_files, u32, struct file_path, 256); BPF_HASH(denied_access_files, u32, struct file_path, 256); - - -#define MAX_PATH_SIZE 4096 // PATH_MAX from -#define LIMIT_PATH_SIZE(x) ((x) & (MAX_PATH_SIZE - 1)) -#define MAX_PATH_COMPONENTS 20 - -#define MAX_PERCPU_ARRAY_SIZE (1 << 15) -#define HALF_PERCPU_ARRAY_SIZE (MAX_PERCPU_ARRAY_SIZE >> 1) -#define LIMIT_PERCPU_ARRAY_SIZE(x) ((x) & (MAX_PERCPU_ARRAY_SIZE - 1)) -#define LIMIT_HALF_PERCPU_ARRAY_SIZE(x) ((x) & (HALF_PERCPU_ARRAY_SIZE - 1)) - -struct buffer { - u8 data[MAX_PERCPU_ARRAY_SIZE]; -}; - struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __type(key, u32); @@ -73,103 +30,6 @@ static struct buffer *get_buffer() { return (struct buffer *)bpf_map_lookup_elem(&heaps_map, &zero); } -static long get_path_str_from_path(u_char **path_str, const struct path *path, struct buffer *out_buf, struct dentry *append) { - long ret; - struct dentry *dentry, *dentry_parent, *dentry_mnt; - struct vfsmount *vfsmnt; - struct mount *mnt, *mnt_parent; - const u_char *name; - size_t name_len; - - dentry = BPF_CORE_READ(path, dentry); - vfsmnt = BPF_CORE_READ(path, mnt); - mnt = container_of(vfsmnt, struct mount, mnt); - mnt_parent = BPF_CORE_READ(mnt, mnt_parent); - - size_t buf_off = HALF_PERCPU_ARRAY_SIZE - 1; - -#pragma unroll - for (int i = 0; i < MAX_PATH_COMPONENTS; i++) { - - dentry_mnt = BPF_CORE_READ(vfsmnt, mnt_root); - dentry_parent = BPF_CORE_READ(dentry, d_parent); - - if (dentry == dentry_mnt || dentry == dentry_parent) { - if (dentry != dentry_mnt) { - // We reached root, but not mount root - escaped? - break; - } - if (mnt != mnt_parent) { - // We reached root, but not global root - continue with mount point path - dentry = BPF_CORE_READ(mnt, mnt_mountpoint); - mnt_parent = BPF_CORE_READ(mnt, mnt_parent); - vfsmnt = __builtin_preserve_access_index(&mnt->mnt); - continue; - } - // Global root - path fully parsed - break; - } - - // Add this dentry name to path - name_len = LIMIT_PATH_SIZE(BPF_CORE_READ(dentry, d_name.len)); - name = BPF_CORE_READ(dentry, d_name.name); - - name_len = name_len + 1; - // Is string buffer big enough for dentry name? - if (name_len > buf_off) { break; } - volatile size_t new_buff_offset = buf_off - name_len; // satisfy verifier - ret = bpf_probe_read_kernel_str( - &(out_buf->data[LIMIT_HALF_PERCPU_ARRAY_SIZE(new_buff_offset)]),// satisfy verifie - name_len, name); - - if (ret < 0) { return ret; } - - if (ret > 1) { - buf_off -= 1; // remove null byte termination with slash sign - buf_off = LIMIT_HALF_PERCPU_ARRAY_SIZE(buf_off); // satisfy verifier - out_buf->data[buf_off] = '/'; - buf_off -= ret - 1; - buf_off = LIMIT_HALF_PERCPU_ARRAY_SIZE(buf_off); // satisfy verifier - } else { - // If sz is 0 or 1 we have an error (path can't be null nor an empty string) - break; - } - dentry = dentry_parent; - } - - // Is string buffer big enough for slash? - if (buf_off != 0) { - // Add leading slash - buf_off -= 1; - buf_off = LIMIT_HALF_PERCPU_ARRAY_SIZE(buf_off); // satisfy verifier - out_buf->data[buf_off] = '/'; - } - - // Null terminate the path string - out_buf->data[HALF_PERCPU_ARRAY_SIZE - 1] = 0; - *path_str = &out_buf->data[buf_off]; - - if (append) { - name_len = LIMIT_PATH_SIZE(BPF_CORE_READ(append, d_name.len)); - name = BPF_CORE_READ(append, d_name.name); - - ret = bpf_probe_read_kernel_str(&(out_buf->data[HALF_PERCPU_ARRAY_SIZE - 1]), name_len + 1, name); - } else { - out_buf->data[HALF_PERCPU_ARRAY_SIZE - 1 - 1] = 0; - } - - return HALF_PERCPU_ARRAY_SIZE - buf_off - 1; -} - -static u64 cb_check_path(struct bpf_map *map, u32 *key, struct file_path *map_path, struct callback_ctx *ctx) { - size_t size = strlen(map_path->path, NAME_MAX); - if (strcmp(map_path->path, ctx->path, size) == 0) { - ctx->found = true; - } - - return 0; -} - static inline void get_file_info(struct file_open_audit_event *event){ struct uts_namespace *uts_ns; struct mnt_namespace *mnt_ns; diff --git a/pkg/bpf/c/restricted-mount.bpf.c b/pkg/bpf/c/restricted-mount.bpf.c index 0b7c443fc10518aa7a65e6312dd4fb7abdc7d2e8..ff635ab4a9289e8f583617f00de69b42795ea7d7 100644 --- a/pkg/bpf/c/restricted-mount.bpf.c +++ b/pkg/bpf/c/restricted-mount.bpf.c @@ -8,34 +8,6 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; -#define NAME_MAX 255 -#define LOOP_NAME 70 - -struct file_path { - unsigned char path[NAME_MAX]; -}; - -struct callback_ctx { - unsigned char *path; - bool found; -}; - -struct mount_audit_event { - u64 cgroup; - u32 pid; - u32 uid; - unsigned int inum; - char nodename[NEW_UTS_LEN + 1]; - char task[TASK_COMM_LEN]; - char parent_task[TASK_COMM_LEN]; - unsigned char path[NAME_MAX]; -}; - -struct mount_safeguard_config { - u32 mode; - u32 target; -}; - struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __uint(key_size, sizeof(u32)); @@ -45,31 +17,18 @@ struct { BPF_HASH(mount_safeguard_config_map, u32, struct mount_safeguard_config, 256); BPF_HASH(mount_denied_source_list, u32, struct file_path, 256); -static u64 cb_check_path(struct bpf_map *map, u32 *key, struct file_path *map_path, struct callback_ctx *ctx) -{ - size_t size = strlen(map_path->path, NAME_MAX); - if (strcmp(map_path->path, ctx->path, size) == 0) { - ctx->found = 1; - } - - return 0; -} - /* static inline void get_info(struct mount_audit_event *event, const char *dev_name) { - unsigned int inum; - struct task_struct *current_task, *parent_task; struct uts_namespace *uts_ns; struct mnt_namespace *mnt_ns; struct nsproxy *nsproxy; - current_task = (struct task_struct *)bpf_get_current_task(); - parent_task = BPF_CORE_READ(current_task, real_parent); + struct task_struct *current_task = (struct task_struct *)bpf_get_current_task(); + struct task_struct *parent_task = BPF_CORE_READ(current_task, real_parent); - BPF_CORE_READ_INTO(&event.nodename, current_task, nsproxy, uts_ns, name.nodename); - BPF_CORE_READ_INTO(&inum, current_task, nsproxy, mnt_ns, ns.inum); + BPF_CORE_READ_INTO(&event->nodename, current_task, nsproxy, uts_ns, name.nodename); + //BPF_CORE_READ_INTO(&inum, current_task, nsproxy, mnt_ns, ns.inum); - event->inum = inum; event->cgroup = bpf_get_current_cgroup_id(); event->pid = (u32)(bpf_get_current_pid_tgid() >> 32); bpf_get_current_comm(&event->task, sizeof(event->task)); @@ -79,32 +38,31 @@ static inline void get_info(struct mount_audit_event *event, const char *dev_nam event->uid = uid_gid & 0xFFFFFFFF; } -static inline int get_perm(struct mount_audit_event *event){ - volatile int ret = 0; - volatile bool find = false; - int index = 0; - struct mount_safeguard_config *config = (struct mount_safeguard_config *)bpf_map_lookup_elem(&mount_safeguard_config_map, &index); +static int get_perm(struct mount_audit_event *event){ + int ret = -1, findex = 0, inum; + struct mount_safeguard_config *config = (struct mount_safeguard_config *)bpf_map_lookup_elem(&mount_safeguard_config_map, &findex); + struct task_struct *current_task = (struct task_struct *)bpf_get_current_task(); + BPF_CORE_READ_INTO(&inum, current_task, nsproxy, mnt_ns, ns.inum); -#if LINUX_VERSION_CODE > VERSION_5_10 +#if 0 && LINUX_VERSION_CODE > VERSION_5_10 struct callback_ctx cb = { .path = event->path, .found = false }; bpf_for_each_map_elem(&mount_denied_source_list, cb_check_path, &cb, 0); if (cb.found) { bpf_printk("Mount Denied: %s", cb.path); - find = true; ret = -EPERM; } #else - unsigned int key = 0; + int i = 0; + int j = 0; + int key = 0; struct file_path *paths; paths = (struct file_path *)bpf_map_lookup_elem(&mount_denied_source_list, &key); if (paths == NULL) { return 0; } - bpf_printk("Mount event: %s", paths->path); - bpf_printk("Mount Denied: %s", event->path); - unsigned int i = 0; - unsigned int j = 0; + //bpf_printk("Mount event: %s", paths->path); + //bpf_printk("Mount Denied: %s", event->path); #pragma unroll for (i = 0; i < LOOP_NAME; i++) { @@ -122,7 +80,6 @@ static inline int get_perm(struct mount_audit_event *event){ } if (paths->path[i+1] == '\0' || paths->path[i+1] == '|') { if (event->path[j] == '\0' || event->path[j] == '/') { - find = true; ret = -EPERM; break; } else { @@ -130,13 +87,14 @@ static inline int get_perm(struct mount_audit_event *event){ } } } + #endif - if (config && config->target == TARGET_CONTAINER && event->inum == 0xF0000000) { + if (config && config->target == TARGET_CONTAINER && inum == 0xF0000000) { return 0; } - if (find && config && config->mode == MODE_MONITOR) { + if (ret == -EPERM && config && config->mode == MODE_MONITOR) { ret = 1; } @@ -145,8 +103,11 @@ static inline int get_perm(struct mount_audit_event *event){ SEC("lsm/sb_mount") int BPF_PROG(restricted_mount, const char *dev_name, const struct path *path) { + int ret = 0; + struct mount_audit_event event = {}; get_info(&event, dev_name); ret = get_perm(&event); + event.ret = ret; if (ret != 0) bpf_perf_event_output((void *)ctx, &mount_events, BPF_F_CURRENT_CPU, &event, sizeof(event)); if(ret > 0) ret = 0; @@ -155,18 +116,14 @@ int BPF_PROG(restricted_mount, const char *dev_name, const struct path *path) { */ SEC("lsm/sb_mount") -int BPF_PROG(restricted_mount, const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data, int ret_prev) +int BPF_PROG(restricted_mount, const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data) { + //this does work until now. according to testing ret must -1 and find must be true int ret = -1; - int index = 0; - unsigned int inum; - bool find = false; + bool find = true; + int inum = 0, index = 0; struct task_struct *current_task; struct mount_audit_event event = {}; - struct uts_namespace *uts_ns; - struct mnt_namespace *mnt_ns; - struct nsproxy *nsproxy; struct mount_safeguard_config *config = (struct mount_safeguard_config *)bpf_map_lookup_elem(&mount_safeguard_config_map, &index); current_task = (struct task_struct *)bpf_get_current_task(); @@ -181,7 +138,7 @@ int BPF_PROG(restricted_mount, const char *dev_name, const struct path *path, bpf_probe_read_kernel_str(&event.parent_task, sizeof(event.parent_task), &parent_task->comm); bpf_probe_read_kernel_str(&event.path, sizeof(event.path), dev_name); -#if LINUX_VERSION_CODE > VERSION_5_10 +#if 0 && LINUX_VERSION_CODE > VERSION_5_10 struct callback_ctx cb = { .path = event.path, .found = false }; bpf_for_each_map_elem(&mount_denied_source_list, cb_check_path, &cb, 0); if (cb.found) { @@ -191,16 +148,14 @@ int BPF_PROG(restricted_mount, const char *dev_name, const struct path *path, goto out; } #else + unsigned int i = 0; + unsigned int j = 0; unsigned int key = 0; - struct file_path *paths; - paths = (struct file_path *)bpf_map_lookup_elem(&mount_denied_source_list, &key); + struct file_path *paths= (struct file_path *)bpf_map_lookup_elem(&mount_denied_source_list, &key); if (paths == NULL) { return 0; } - unsigned int i = 0; - unsigned int j = 0; - #pragma unroll for (i = 0; i < LOOP_NAME; i++) { if (paths->path[i] == '\0') { @@ -232,10 +187,12 @@ out: return 0; } - if (config && config->mode == MODE_MONITOR) { - ret = 0; + if (find && config && config->mode == MODE_MONITOR) { + ret = 1; } - - bpf_perf_event_output((void *)ctx, &mount_events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return ret; + event.ret = ret; + if(ret != 0) + bpf_perf_event_output((void *)ctx, &mount_events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + if(ret >0) ret = 0; + return 0; }