Skip to content

Commit

Permalink
[Seccomp] Switch to refcount logic for kernels >= 5.9
Browse files Browse the repository at this point in the history
Starting from kernel 5.9+ function 'put_seccomp_filter' has been inlined
and unavailble for hooking. However, internal not-inline function was used
to mitigate the problem. Unfortunately, there is no equivalent counter-part
function for new hook and the old one looks incompatible which we overlooked.
This patch is switching the logic for kernels 5.9+ to custom implementation
of refcount logic and it should address the issue reported as #338
  • Loading branch information
Adam-pi3 authored and solardiz committed Aug 11, 2024
1 parent b144a0e commit 38b3b11
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 20 deletions.
33 changes: 13 additions & 20 deletions src/modules/exploit_detection/p_exploit_detection.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ static notrace void p_dump_creds(struct p_cred *p_where, const struct cred *p_fr
#if defined(CONFIG_SECCOMP)
static notrace void p_dump_seccomp(struct p_seccomp *p_sec, struct task_struct *p_task, char p_force) {

P_SYM(p_get_seccomp_filter)(p_task);
p_lkrg_seccomp_filter_get(p_task);
p_sec->sec.mode = p_task->seccomp.mode; // Mode
p_sec->sec.filter = p_task->seccomp.filter; // Filter
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,11,0)
Expand All @@ -437,12 +437,7 @@ static notrace void p_dump_seccomp(struct p_seccomp *p_sec, struct task_struct *
p_sec->flag = 0;
if (p_force)
p_sec->flag_sync_thread = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
P_SYM(p_put_seccomp_filter)(p_task->seccomp.filter);
#else
P_SYM(p_put_seccomp_filter)(p_task);
#endif

p_lkrg_seccomp_filter_put(p_task);
}
#endif

Expand Down Expand Up @@ -1373,8 +1368,12 @@ static int p_cmp_tasks(struct p_ed_process *p_orig, struct task_struct *p_curren

#if defined(CONFIG_SECCOMP)
/* Seccomp */
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
if (p_orig->p_ed_task.p_sec.flag) { // SECCOMP was enabled so it make sense to compare...
P_SYM(p_get_seccomp_filter)(p_current);
#else
if (p_orig->p_ed_task.p_sec.flag && current == p_current) { // SECCOMP was enabled so it make sense to compare...
#endif
p_lkrg_seccomp_filter_get(p_current);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,11,0)
if (test_task_syscall_work(p_current,SECCOMP) != p_orig->p_ed_task.p_sec.flag) {
Expand Down Expand Up @@ -1408,11 +1407,7 @@ static int p_cmp_tasks(struct p_ed_process *p_orig, struct task_struct *p_curren

P_CMP_PTR(p_orig->p_ed_task.p_sec.sec.filter, p_current->seccomp.filter, "seccomp filter")

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
P_SYM(p_put_seccomp_filter)(p_current->seccomp.filter);
#else
P_SYM(p_put_seccomp_filter)(p_current);
#endif
p_lkrg_seccomp_filter_put(p_current);
}
#endif

Expand Down Expand Up @@ -1980,13 +1975,11 @@ int p_exploit_detection_init(void) {
P_SYM_INIT(__kernel_text_address)
P_SYM_INIT(mm_find_pmd)
#if defined(CONFIG_SECCOMP)
P_SYM_INIT(get_seccomp_filter)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
#define p___put_seccomp_filter p_put_seccomp_filter
P_SYM_INIT(__put_seccomp_filter)
#else
P_SYM_INIT(put_seccomp_filter)
#endif
if (P_LKRG_SUCCESS != p_lkrg_seccomp_init()) {
p_print_log(P_LOG_FATAL, "Can't initialize seccomp() logic");
p_ret = P_LKRG_GENERAL_ERROR;
goto p_exploit_detection_init_out;
}
#endif

#ifdef CONFIG_SECURITY_SELINUX
Expand Down
37 changes: 37 additions & 0 deletions src/modules/exploit_detection/syscalls/p_seccomp/p_seccomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,43 @@ static struct kretprobe p_seccomp_kretprobe = {
.data_size = sizeof(struct p_seccomp_data),
};

int p_lkrg_seccomp_init(void) {

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
P_SYM_INIT(get_seccomp_filter)
P_SYM_INIT(put_seccomp_filter)
#endif

return P_LKRG_SUCCESS;

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
p_sym_error:
return P_LKRG_GENERAL_ERROR;
#endif
}

void p_lkrg_seccomp_filter_get(struct task_struct *p_task) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
P_SYM(p_get_seccomp_filter)(p_task);
#else
struct p_fake_seccomp_filter *p_filter = (struct p_fake_seccomp_filter *)p_task->seccomp.filter;

if (p_filter)
refcount_inc(&p_filter->refs);
#endif
}

void p_lkrg_seccomp_filter_put(struct task_struct *p_task) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
P_SYM(p_put_seccomp_filter)(p_task);
#else
struct p_fake_seccomp_filter *p_filter = (struct p_fake_seccomp_filter *)p_task->seccomp.filter;

if (p_filter)
refcount_dec(&p_filter->refs);
#endif
}

/*
* x86-64 syscall ABI:
* *rax - syscall_number
Expand Down
9 changes: 9 additions & 0 deletions src/modules/exploit_detection/syscalls/p_seccomp/p_seccomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ struct p_seccomp_data {
ktime_t entry_stamp;
};

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
struct p_fake_seccomp_filter {
refcount_t refs;
};
#endif

int p_lkrg_seccomp_init(void);
void p_lkrg_seccomp_filter_get(struct task_struct *p_task);
void p_lkrg_seccomp_filter_put(struct task_struct *p_task);

int p_seccomp_ret(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
int p_seccomp_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
Expand Down

0 comments on commit 38b3b11

Please sign in to comment.