-
Notifications
You must be signed in to change notification settings - Fork 355
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1743 from daemon1024/special-presets
feat: special presets (handle fileless exec)
- Loading branch information
Showing
63 changed files
with
3,027 additions
and
298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// +build ignore | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
/* Copyright 2023 Authors of KubeArmor */ | ||
|
||
#include "shared.h" | ||
|
||
#define PROT_EXEC 0x4 /* page can be executed */ | ||
#define MAP_ANONYMOUS 0x20 | ||
#define MAP_ANON MAP_ANONYMOUS | ||
|
||
#define S_IFIFO 0010000 | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 1 << 24); | ||
} events SEC(".maps"); | ||
|
||
typedef struct { | ||
u64 ts; | ||
|
||
u32 pid_id; | ||
u32 mnt_id; | ||
|
||
u32 host_ppid; | ||
u32 host_pid; | ||
|
||
u32 ppid; | ||
u32 pid; | ||
u32 uid; | ||
|
||
u32 event_id; | ||
s64 retval; | ||
|
||
u8 comm[TASK_COMM_LEN]; | ||
|
||
unsigned long args[6]; | ||
} mmap_event; | ||
|
||
static __always_inline u32 init_mmap_context(mmap_event *event_data) { | ||
struct task_struct *task = (struct task_struct *)bpf_get_current_task(); | ||
|
||
event_data->ts = bpf_ktime_get_ns(); | ||
|
||
event_data->host_ppid = get_task_ppid(task); | ||
event_data->host_pid = bpf_get_current_pid_tgid() >> 32; | ||
|
||
u32 pid = get_task_ns_tgid(task); | ||
if (event_data->host_pid == pid) { // host | ||
event_data->pid_id = 0; | ||
event_data->mnt_id = 0; | ||
|
||
event_data->ppid = get_task_ppid(task); | ||
event_data->pid = bpf_get_current_pid_tgid() >> 32; | ||
} else { // container | ||
event_data->pid_id = get_task_pid_ns_id(task); | ||
event_data->mnt_id = get_task_mnt_ns_id(task); | ||
|
||
event_data->ppid = get_task_ns_ppid(task); | ||
event_data->pid = pid; | ||
} | ||
|
||
event_data->uid = bpf_get_current_uid_gid(); | ||
|
||
// Clearing array to avoid garbage values | ||
__builtin_memset(event_data->comm, 0, sizeof(event_data->comm)); | ||
bpf_get_current_comm(&event_data->comm, sizeof(event_data->comm)); | ||
|
||
return 0; | ||
} | ||
|
||
|
||
// Force emitting struct mmap_event into the ELF. | ||
const mmap_event *unused __attribute__((unused)); | ||
|
||
struct preset_map anon_map_exec_preset_containers SEC(".maps"); | ||
|
||
|
||
SEC("lsm/mmap_file") | ||
int BPF_PROG(enforce_mmap_file, struct file *file, unsigned long reqprot, | ||
unsigned long prot, unsigned long flags){ | ||
|
||
struct task_struct *t = (struct task_struct *)bpf_get_current_task(); | ||
|
||
struct outer_key okey; | ||
get_outer_key(&okey, t); | ||
|
||
u32 *present = bpf_map_lookup_elem(&anon_map_exec_preset_containers, &okey); | ||
|
||
if (!present) { | ||
return 0; | ||
} | ||
|
||
// only if PROT_EXEC is assigned | ||
if (prot & PROT_EXEC) { | ||
if (flags & MAP_ANONYMOUS) { | ||
mmap_event *event_data; | ||
event_data = bpf_ringbuf_reserve(&events, sizeof(mmap_event), 0); | ||
|
||
if (!event_data) { | ||
return 0; | ||
} | ||
|
||
init_mmap_context(event_data); | ||
|
||
__builtin_memset(event_data->args, 0, sizeof(event_data->args)); | ||
|
||
event_data->args[0] = reqprot; | ||
event_data->args[1] = prot; | ||
event_data->args[2] = flags; | ||
event_data->event_id = ANON_MAP_EXEC; | ||
if (*present == BLOCK) { | ||
event_data->retval = -EPERM; | ||
} else { | ||
event_data->retval = 0; | ||
} | ||
bpf_ringbuf_submit(event_data, 0); | ||
// mapping not backed by any file with executable permission, denying mapping | ||
if (*present == BLOCK) { | ||
return -EPERM; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// +build ignore | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
/* Copyright 2023 Authors of KubeArmor */ | ||
|
||
#include "shared.h" | ||
|
||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 1 << 24); | ||
} events SEC(".maps"); | ||
|
||
|
||
// Force emitting struct mmap_event into the ELF. | ||
const event *unused __attribute__((unused)); | ||
|
||
struct preset_map fileless_exec_preset_containers SEC(".maps"); | ||
|
||
#define MEMFD "memfd:" | ||
#define RUN_SHM "/run/shm/" | ||
#define DEV_SHM "/dev/shm/" | ||
|
||
static __always_inline int is_memfd(char *name) { | ||
return string_prefix_match(name, MEMFD, sizeof(MEMFD)); | ||
} | ||
|
||
static __always_inline int is_run_shm(char *name) { | ||
return string_prefix_match(name, RUN_SHM, sizeof(RUN_SHM)); | ||
} | ||
|
||
static __always_inline int is_dev_shm(char *name) { | ||
return string_prefix_match(name, DEV_SHM, sizeof(DEV_SHM)); | ||
} | ||
|
||
struct pathname { | ||
char path[256]; | ||
}; | ||
|
||
SEC("lsm/bprm_check_security") | ||
int BPF_PROG(enforce_bprm_check_security, struct linux_binprm *bprm){ | ||
|
||
struct task_struct *t = (struct task_struct *)bpf_get_current_task(); | ||
|
||
struct outer_key okey; | ||
get_outer_key(&okey, t); | ||
|
||
u32 *present = bpf_map_lookup_elem(&fileless_exec_preset_containers, &okey); | ||
|
||
if (!present) { | ||
return 0; | ||
} | ||
|
||
struct pathname path_data = {}; | ||
|
||
struct file *file = BPF_CORE_READ(bprm, file); | ||
if (file == NULL) | ||
return 0; | ||
|
||
bufs_t *path_buf = get_buf(PATH_BUFFER); | ||
if (path_buf == NULL) | ||
return 0; | ||
|
||
// prepend path is needed to capture /dev/shm and /run/shm paths | ||
if (!prepend_path(&(file->f_path), path_buf)){ | ||
// memfd files have no path in the filesystem -> extract their name | ||
struct dentry *dentry = BPF_CORE_READ(&file->f_path, dentry); | ||
struct qstr d_name = BPF_CORE_READ(dentry, d_name); | ||
bpf_probe_read_kernel_str(path_data.path, MAX_STRING_SIZE, (void *) d_name.name); | ||
} else { | ||
u32 *path_offset = get_buf_off(PATH_BUFFER); | ||
if (path_offset == NULL) | ||
return 0; | ||
|
||
void *path_ptr = &path_buf->buf[*path_offset]; | ||
bpf_probe_read_str(path_data.path, MAX_STRING_SIZE, path_ptr); | ||
} | ||
|
||
const char *filename = BPF_CORE_READ(bprm, filename); | ||
|
||
if (is_memfd(path_data.path) || is_run_shm(path_data.path) || is_dev_shm(path_data.path)) { | ||
event *event_data; | ||
event_data = bpf_ringbuf_reserve(&events, sizeof(event), 0); | ||
|
||
if (!event_data) { | ||
return 0; | ||
} | ||
|
||
__builtin_memset(event_data->data.path, 0, sizeof(event_data->data.path)); | ||
__builtin_memset(event_data->data.source, 0, sizeof(event_data->data.source)); | ||
|
||
bpf_probe_read_str(event_data->data.path, MAX_STRING_SIZE, path_data.path); | ||
bpf_probe_read_str(event_data->data.source, MAX_STRING_SIZE, filename); | ||
|
||
init_context(event_data); | ||
event_data->event_id = FILELESS_EXEC; | ||
|
||
// mapping not backed by any file with executable permission, denying mapping | ||
if (*present == BLOCK) { | ||
event_data->retval = -13; | ||
bpf_ringbuf_submit(event_data, 0); | ||
// bpf_printk("[bprm] fileless execution detected with pid %d, denying execution", event_data->pid); | ||
return -13; | ||
} else { | ||
event_data->retval = 0; | ||
bpf_ringbuf_submit(event_data, 0); | ||
return 0; | ||
} | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// +build ignore | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
/* Copyright 2023 Authors of KubeArmor */ | ||
|
||
#include "shared.h" | ||
|
||
typedef struct { | ||
u32 pid; | ||
u32 pid_ns; | ||
u32 mnt_ns; | ||
char comm[80]; | ||
} pevent; | ||
|
||
const pevent *unused __attribute__((unused)); | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 1 << 24); | ||
} events SEC(".maps"); | ||
|
||
struct preset_map protectenv_preset_containers SEC(".maps"); | ||
|
||
#define DIR_PROC "/proc/" | ||
#define FILE_ENVIRON "/environ" | ||
|
||
static __always_inline int isProcDir(char *path) { | ||
return string_prefix_match(path, DIR_PROC, sizeof(DIR_PROC)); | ||
} | ||
|
||
static __always_inline int isEnviron(char *path) { | ||
return string_prefix_match(path, FILE_ENVIRON, sizeof(FILE_ENVIRON)); | ||
} | ||
|
||
SEC("lsm/file_open") | ||
int BPF_PROG(enforce_file, struct file *file) { | ||
|
||
struct task_struct *t = (struct task_struct *)bpf_get_current_task(); | ||
|
||
struct outer_key okey; | ||
get_outer_key(&okey, t); | ||
|
||
u32 *present = bpf_map_lookup_elem(&protectenv_preset_containers, &okey); | ||
|
||
if (!present) { | ||
return 0; | ||
} | ||
|
||
u64 id = bpf_get_current_pid_tgid(); | ||
u32 tgid = id >> 32; | ||
|
||
char path[80]; | ||
bpf_d_path(&file->f_path, path, 80); | ||
|
||
if (!isProcDir(path)) { | ||
return 0; | ||
} | ||
|
||
long envpid; | ||
int count = bpf_strtol(path + sizeof(DIR_PROC) - 1, 10, 0, &envpid); | ||
if (count < 0) { | ||
return 0; | ||
} | ||
u8 envstart = sizeof(DIR_PROC) + count - 1; | ||
if (envstart < 80 && !isEnviron(path + envstart)) { | ||
return 0; | ||
} | ||
|
||
long pid = get_task_ns_tgid(t); | ||
|
||
if (envpid != pid) { | ||
|
||
pevent *task_info; | ||
|
||
task_info = bpf_ringbuf_reserve(&events, sizeof(pevent), 0); | ||
if (!task_info) { | ||
return 0; | ||
} | ||
task_info->pid = pid; | ||
task_info->pid_ns = okey.pid_ns; | ||
task_info->mnt_ns = okey.mnt_ns; | ||
bpf_ringbuf_submit(task_info, 0); | ||
return -EPERM; | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.