Rework the logic supporting OverlayFS/docker

The original logic was hooking 'ovl_create_or_link' function but it could be
inlined. This commit changes it by hooking 'ovl_dentry_is_whiteout' when
possible.

Fixes #215
This commit is contained in:
Adam_pi3 2022-07-27 04:56:26 +00:00 committed by Solar Designer
parent dfb60a6eb2
commit 6f3627e32c
9 changed files with 206 additions and 134 deletions

View File

@ -82,7 +82,7 @@ $(TARGET)-objs += src/modules/ksyms/p_resolve_ksym.o \
src/modules/exploit_detection/syscalls/__x32/p_x32_sys_keyctl/p_x32_sys_keyctl.o \
src/modules/exploit_detection/syscalls/override/p_override_creds/p_override_creds.o \
src/modules/exploit_detection/syscalls/override/p_revert_creds/p_revert_creds.o \
src/modules/exploit_detection/syscalls/override/overlayfs/p_ovl_create_or_link/p_ovl_create_or_link.o \
src/modules/exploit_detection/syscalls/override/overlayfs/p_ovl_override_sync/p_ovl_override_sync.o \
src/modules/exploit_detection/syscalls/pCFI/p_mark_inode_dirty/p_mark_inode_dirty.o \
src/modules/exploit_detection/syscalls/pCFI/p_schedule/p_schedule.o \
src/modules/exploit_detection/syscalls/pCFI/p___queue_work/p___queue_work.o \

View File

@ -298,19 +298,38 @@ static const struct p_functions_hooks {
NULL,
0
},
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
/* OverlayFS
*
* OverlayFS might not be installed in that system - it is not critical
* scenario. If OverlayFS is installed, used but not found (unlikely)
* in worst case, we might have FP. Continue...
*/
{ "ovl_create_or_link",
p_install_ovl_create_or_link_hook,
p_uninstall_ovl_create_or_link_hook,
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
"ovl_dentry_is_whiteout",
#else
/* Between the kernels 4.7 and 4.9, the 'ovl_dentry_is_whiteout' function does not exist */
"ovl_create_or_link",
#endif
p_install_ovl_override_sync_hook,
p_uninstall_ovl_override_sync_hook,
0,
"Can't hook 'ovl_create_or_link' function. This is expected when OverlayFS is not used.",
"Can't hook '"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
"ovl_dentry_is_whiteout"
#else
/* Between the kernels 4.7 and 4.9, the 'ovl_dentry_is_whiteout' function does not exist */
"ovl_create_or_link"
#endif
"' function. This is expected when OverlayFS is not used.",
1
},
#endif
/* pCFI */
{ "pcfi_mark_inode_dirty",
p_install_pcfi_mark_inode_dirty_hook,
@ -593,7 +612,7 @@ struct p_lkrg_debug_off_flag_callers {
{ 27, "p_sys_keyctl_ret" },
{ 28, "p_sys_request_key_entry" },
{ 29, "p_sys_request_key_ret" },
{ 30, "p_ovl_create_or_link_ret" },
{ 30, "p_ovl_override_sync_ret" },
{ 31, "p_override_creds_entry" },
{ 32, "p_revert_creds_ret" },
{ 33, "p_seccomp_entry" },
@ -977,14 +996,21 @@ inline void p_validate_off_flag(struct p_ed_process *p_source, long p_val, int *
p_ed_is_off_off(p_source, p_val, p_ret);
}
notrace int p_verify_ovl_create_or_link(struct p_ed_process *p_source) {
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
notrace int p_verify_ovl_override_sync(struct p_ed_process *p_source) {
register unsigned long p_off = p_source->p_ed_task.p_off ^ p_global_off_cookie; // Decode
p_validate_off_flag(p_source,p_off,NULL); // Validate
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
return p_off == 3 * p_global_cnt_cookie;
#else
return p_off == 2 * p_global_cnt_cookie;
#endif
}
#endif
notrace void p_ed_is_off_off_wrap(struct p_ed_process *p_source) {

View File

@ -362,7 +362,7 @@ struct p_ed_global_variables {
/* Namespaces */
#include "syscalls/p_sys_setns/p_sys_setns.h"
/* OverlayFS */
#include "syscalls/override/overlayfs/p_ovl_create_or_link/p_ovl_create_or_link.h"
#include "syscalls/override/overlayfs/p_ovl_override_sync/p_ovl_override_sync.h"
/* pCFI */
#include "syscalls/pCFI/p_mark_inode_dirty/p_mark_inode_dirty.h"
#include "syscalls/pCFI/p_schedule/p_schedule.h"
@ -388,8 +388,10 @@ void p_ed_validate_off_flag_wrap(struct p_ed_process *p_source);
void p_set_ed_process_override_on(struct p_ed_process *p_source);
void p_set_ed_process_override_off(struct p_ed_process *p_source);
void p_reset_ed_flags(struct p_ed_process *p_source);
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
/* For OverlayFS */
int p_verify_ovl_create_or_link(struct p_ed_process *p_source);
int p_verify_ovl_override_sync(struct p_ed_process *p_source);
#endif
int p_validate_task_f(void *p_arg);

View File

@ -1,78 +0,0 @@
/*
* pi3's Linux kernel Runtime Guard
*
* Component:
* - Intercept 'ovl_create_or_link' function
*
* Notes:
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
* When process calls 'ovl_create_or_link', we need to correctly handle
* this situation and adjust 'off' flag
*
* Caveats:
* - None
*
* Timeline:
* - Created: 28.III.2019
*
* Author:
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
*
*/
#include "../../../../../../p_lkrg_main.h"
char p_ovl_create_or_link_kretprobe_state = 0;
static struct kretprobe p_ovl_create_or_link_kretprobe = {
.kp.symbol_name = "ovl_create_or_link",
.handler = p_ovl_create_or_link_ret,
.entry_handler = p_ovl_create_or_link_entry,
.data_size = sizeof(struct p_ovl_create_or_link_data),
/* Probe up to 40 instances concurrently. */
.maxactive = 40,
};
void p_reinit_ovl_create_or_link_kretprobe(void) {
memset(&p_ovl_create_or_link_kretprobe,0x0,sizeof(struct kretprobe));
p_ovl_create_or_link_kretprobe.kp.symbol_name = "ovl_create_or_link";
p_ovl_create_or_link_kretprobe.handler = p_ovl_create_or_link_ret;
p_ovl_create_or_link_kretprobe.entry_handler = p_ovl_create_or_link_entry;
p_ovl_create_or_link_kretprobe.data_size = sizeof(struct p_ovl_create_or_link_data);
p_ovl_create_or_link_kretprobe.maxactive = 40;
}
int p_ovl_create_or_link_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
return 0;
}
notrace int p_ovl_create_or_link_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
struct p_ed_process *p_tmp;
unsigned long p_flags;
if (p_is_ed_task(current)) {
// Update process
p_tasks_write_lock(&p_flags);
if ( (p_tmp = p_find_ed_by_pid(task_pid_nr(current))) != NULL) {
if (p_verify_ovl_create_or_link(p_tmp)) {
#ifdef P_LKRG_TASK_OFF_DEBUG
p_debug_off_flag_override_on(p_tmp, 30, p_regs);
#endif
p_set_ed_process_override_on(p_tmp);
}
}
p_ed_validate_current();
p_ed_enforce_pcfi(current, p_tmp, p_regs);
p_tasks_write_unlock(&p_flags);
}
return 0;
}
GENERATE_INSTALL_FUNC(ovl_create_or_link)

View File

@ -1,39 +0,0 @@
/*
* pi3's Linux kernel Runtime Guard
*
* Component:
* - Intercept 'ovl_create_or_link' function
*
* Notes:
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
* When process calls 'ovl_create_or_link', we need to correctly handle
* this situation and adjust 'off' flag
*
* Caveats:
* - None
*
* Timeline:
* - Created: 28.III.2019
*
* Author:
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
*
*/
#ifndef P_LKRG_EXPLOIT_DETECTION_OVL_CREATE_OR_LINK_H
#define P_LKRG_EXPLOIT_DETECTION_OVL_CREATE_OR_LINK_H
/* per-instance private data */
struct p_ovl_create_or_link_data {
ktime_t entry_stamp;
};
extern char p_ovl_create_or_link_kretprobe_state;
int p_ovl_create_or_link_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
int p_ovl_create_or_link_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
int p_install_ovl_create_or_link_hook(int p_isra);
void p_uninstall_ovl_create_or_link_hook(void);
void p_reinit_ovl_create_or_link_kretprobe(void);
#endif

View File

@ -0,0 +1,99 @@
/*
* pi3's Linux kernel Runtime Guard
*
* Component:
* - Intercept 'ovl_dentry_is_whiteout' function which is called by
* 'ovl_create_or_link'.
*
* Notes:
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
* When process calls 'ovl_create_or_link', we need to correctly handle
* this situation and adjust 'off' flag
*
* Caveats:
* - Originally, 'ovl_create_or_link' function was hooked.
* Due the fact it is declared with 'static' keyword, it may be inlined.
*
* Timeline:
* - Modified: 27.VII.2022
* - Created: 28.III.2019
*
* Author:
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
*
*/
#include "../../../../../../p_lkrg_main.h"
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
char p_ovl_override_sync_kretprobe_state = 0;
static struct kretprobe p_ovl_override_sync_kretprobe = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
.kp.symbol_name = "ovl_dentry_is_whiteout",
#else
/* Between the kernels 4.7 and 4.9, the 'ovl_dentry_is_whiteout' function does not exist */
.kp.symbol_name = "ovl_create_or_link",
#endif
.handler = p_ovl_override_sync_ret,
.entry_handler = p_ovl_override_sync_entry,
.data_size = sizeof(struct p_ovl_override_sync_data),
/* Probe up to 40 instances concurrently. */
.maxactive = 40,
};
void p_reinit_ovl_override_sync_kretprobe(void) {
memset(&p_ovl_override_sync_kretprobe,0x0,sizeof(struct kretprobe));
p_ovl_override_sync_kretprobe.kp.symbol_name = "ovl_override_sync";
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
p_ovl_override_sync_kretprobe.kp.symbol_name = "ovl_dentry_is_whiteout",
#else
/* Between the kernels 4.7 and 4.9, the 'ovl_dentry_is_whiteout' function does not exist */
p_ovl_override_sync_kretprobe.kp.symbol_name = "ovl_create_or_link",
#endif
p_ovl_override_sync_kretprobe.handler = p_ovl_override_sync_ret;
p_ovl_override_sync_kretprobe.entry_handler = p_ovl_override_sync_entry;
p_ovl_override_sync_kretprobe.data_size = sizeof(struct p_ovl_override_sync_data);
p_ovl_override_sync_kretprobe.maxactive = 40;
}
int p_ovl_override_sync_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
return 0;
}
notrace int p_ovl_override_sync_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
struct p_ed_process *p_tmp;
unsigned long p_flags;
if (p_is_ed_task(current)) {
// Update process
p_tasks_write_lock(&p_flags);
if ( (p_tmp = p_find_ed_by_pid(task_pid_nr(current))) != NULL) {
if (p_verify_ovl_override_sync(p_tmp)) {
#ifdef P_LKRG_TASK_OFF_DEBUG
p_debug_off_flag_override_on(p_tmp, 30, p_regs);
#endif
p_set_ed_process_override_on(p_tmp);
}
}
p_ed_validate_current();
p_ed_enforce_pcfi(current, p_tmp, p_regs);
p_tasks_write_unlock(&p_flags);
}
return 0;
}
GENERATE_INSTALL_FUNC(ovl_override_sync)
#endif

View File

@ -0,0 +1,47 @@
/*
* pi3's Linux kernel Runtime Guard
*
* Component:
* - Intercept 'ovl_dentry_is_whiteout' function which is called by
* 'ovl_create_or_link'.
*
* Notes:
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
* When process calls 'ovl_create_or_link', we need to correctly handle
* this situation and adjust 'off' flag
*
* Caveats:
* - Originally, 'ovl_create_or_link' function was hooked.
* Due the fact it is declared with 'static' keyword, it may be inlined.
*
* Timeline:
* - Modified: 27.VII.2022
* - Created: 28.III.2019
*
* Author:
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
*
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
#ifndef P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H
#define P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H
/* per-instance private data */
struct p_ovl_override_sync_data {
ktime_t entry_stamp;
};
extern char p_ovl_override_sync_kretprobe_state;
int p_ovl_override_sync_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
int p_ovl_override_sync_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
int p_install_ovl_override_sync_hook(int p_isra);
void p_uninstall_ovl_override_sync_hook(void);
void p_reinit_ovl_override_sync_kretprobe(void);
#endif
#endif

View File

@ -249,7 +249,8 @@ p_module_event_notifier_activity_out:
void p_verify_module_live(struct module *p_mod) {
if (p_ovl_create_or_link_kretprobe_state) {
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
if (p_ovl_override_sync_kretprobe_state) {
/* We do not need to do anything for now */
return;
}
@ -268,9 +269,17 @@ void p_verify_module_live(struct module *p_mod) {
P_CTRL(p_kint_validate) = 0;
p_lkrg_close_rw();
/* Try to install the hook */
if (p_install_ovl_create_or_link_hook(1)) {
if (p_install_ovl_override_sync_hook(1)) {
p_print_log(P_LOG_FAULT,
"OverlayFS is being loaded but LKRG can't hook 'ovl_create_or_link' function. "
"OverlayFS is being loaded but LKRG can't hook '"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 179) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) || \
(defined(RHEL_RELEASE_CODE) && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 4))
"ovl_dentry_is_whiteout' function. "
#else
/* Between the kernels 4.7 and 4.9, the 'ovl_dentry_is_whiteout' function does not exist */
"ovl_create_or_link' function. "
#endif
"It is very likely that LKRG will produce false positives. Please reload LKRG.");
}
/* Done */
@ -278,11 +287,13 @@ void p_verify_module_live(struct module *p_mod) {
P_CTRL(p_kint_validate) = p_tmp_val;
p_lkrg_close_rw();
}
#endif
}
void p_verify_module_going(struct module *p_mod) {
if (!p_ovl_create_or_link_kretprobe_state) {
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
if (!p_ovl_override_sync_kretprobe_state) {
/* We do not need to do anything for now */
return;
}
@ -300,13 +311,15 @@ void p_verify_module_going(struct module *p_mod) {
P_CTRL(p_kint_validate) = 0;
p_lkrg_close_rw();
/* Try to uninstall the hook */
p_uninstall_ovl_create_or_link_hook();
p_reinit_ovl_create_or_link_kretprobe();
p_uninstall_ovl_override_sync_hook();
p_reinit_ovl_override_sync_kretprobe();
/* Done */
p_lkrg_open_rw();
P_CTRL(p_kint_validate) = p_tmp_val;
p_lkrg_close_rw();
}
#endif
}
void p_register_module_notifier(void) {

View File

@ -123,7 +123,9 @@ static struct p_addr_name {
P_LKRG_DEBUG_RULE_KPROBE(p_sys_setfsgid),
P_LKRG_DEBUG_RULE_KPROBE(p_call_usermodehelper_exec),
P_LKRG_DEBUG_RULE_KPROBE(p_set_current_groups),
P_LKRG_DEBUG_RULE_KPROBE(p_ovl_create_or_link),
#if defined(P_LKRG_EXPLOIT_DETECTION_OVL_OVERRIDE_SYNC_H)
P_LKRG_DEBUG_RULE_KPROBE(p_ovl_override_sync),
#endif
P_LKRG_DEBUG_RULE_KPROBE(p_revert_creds),
P_LKRG_DEBUG_RULE_KPROBE(p_override_creds),
P_LKRG_DEBUG_RULE_KPROBE(p_security_bprm_committing_creds),