From 26f36ed495ffeb8befe73f5c5f152603ab311076 Mon Sep 17 00:00:00 2001 From: Adam_pi3 Date: Wed, 30 Nov 2022 22:53:09 +0000 Subject: [PATCH] Add a kprobe verification functionality Add a new logic to the integrity verification routine verifying if the kprobes are enabled and correctly run. This commit makes kprobe verification functionality as an independent module invoked by integrity verification routine as well as during initialization to make sure kprobes are enabled and run as intended (otherwise, initialization fails). --- Makefile | 1 + .../integrity_timer/p_integrity_timer.c | 6 ++ .../integrity_timer/p_integrity_timer.h | 3 + .../verify_kprobes/p_verify_kprobes.c | 74 +++++++++++++++ .../verify_kprobes/p_verify_kprobes.h | 26 +++++ src/modules/wrap/p_struct_wrap.h | 94 +++++++++++-------- src/p_lkrg_main.c | 24 ++++- 7 files changed, 188 insertions(+), 40 deletions(-) create mode 100644 src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.c create mode 100644 src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.h diff --git a/Makefile b/Makefile index 6bbc398..ce8b35e 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ $(TARGET)-objs += src/modules/ksyms/p_resolve_ksym.o \ src/modules/hashing/p_lkrg_fast_hash.o \ src/modules/comm_channel/p_comm_channel.o \ src/modules/integrity_timer/p_integrity_timer.o \ + src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.o \ src/modules/kmod/p_kmod.o \ src/modules/database/CPU.o \ src/modules/database/arch/x86/p_x86_metadata.o \ diff --git a/src/modules/integrity_timer/p_integrity_timer.c b/src/modules/integrity_timer/p_integrity_timer.c index 3b600f8..9680e24 100644 --- a/src/modules/integrity_timer/p_integrity_timer.c +++ b/src/modules/integrity_timer/p_integrity_timer.c @@ -211,6 +211,12 @@ void p_check_integrity(struct work_struct *p_work) { p_tmp_hash = hash_from_CPU_data(p_tmp_cpus); p_read_cpu_unlock(); + /* Verify kprobes now */ + if (lkrg_verify_kprobes()) { + /* I'm hacked! ;( */ + p_hack_check++; + } + p_text_section_lock(); /* diff --git a/src/modules/integrity_timer/p_integrity_timer.h b/src/modules/integrity_timer/p_integrity_timer.h index a9058c5..6f57baf 100644 --- a/src/modules/integrity_timer/p_integrity_timer.h +++ b/src/modules/integrity_timer/p_integrity_timer.h @@ -18,6 +18,9 @@ #ifndef P_LKRG_INTEGRITY_TIMER_H #define P_LKRG_INTEGRITY_TIMER_H +/* Submodule for verifying kprobes */ +#include "verify_kprobes/p_verify_kprobes.h" + #define p_alloc_offload() kmem_cache_alloc(p_offload_cache, GFP_ATOMIC) #define p_free_offload(name) kmem_cache_free(p_offload_cache, (void *)(name)) diff --git a/src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.c b/src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.c new file mode 100644 index 0000000..73ddd96 --- /dev/null +++ b/src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.c @@ -0,0 +1,74 @@ +/* + * pi3's Linux kernel Runtime Guard + * + * Component: + * - Integrity verification kprobe verification submodule + * + * Notes: + * - Verify if kprobes are enabled and correctly run + * + * Timeline: + * - Created: 30.XI.2022 + * + * Author: + * - Adam 'pi3' Zabrocki (http://pi3.com.pl) + * + */ + +#include "../../../p_lkrg_main.h" + +static int p_lkrg_dummy_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs); +static int p_lkrg_dummy_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs); + +static char p_lkrg_dummy_kretprobe_state = 0; + +static struct kretprobe p_lkrg_dummy_kretprobe = { + .kp.symbol_name = "lkrg_dummy", + .handler = p_lkrg_dummy_ret, + .entry_handler = p_lkrg_dummy_entry, +}; + +__attribute__((optimize(0))) +noinline int lkrg_dummy(int arg) { + + p_debug_log(P_LOG_DEBUG, + "[lkrg_dummy] Argument value: [%d]\n",arg); + + /* + * TODO: + * We can verify integrity of the internal kprobe structures here + */ + + return arg+1; +} + + +int lkrg_verify_kprobes(void) { + + int p_ret = 0, ret = -1; + + /* Verify kprobes now */ + if ( (ret = lkrg_dummy(0)) != 3) { + /* I'm hacked! ;( */ + p_print_log(P_LOG_ALERT, "DETECT: Kprobes: Don't work as intended (disabled?)"); + p_ret = -1; + } + p_print_log(P_LOG_WATCH, "lkrg_dummy returned %d vs. expected 3",ret); + + return p_ret; +} + +static int p_lkrg_dummy_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) { + + p_regs_set_arg1(p_regs, p_regs_get_arg1(p_regs) + 1); + return 0; +} + + +static int p_lkrg_dummy_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) { + + p_regs_set_ret(p_regs, p_regs_get_ret(p_regs) + 1); + return 0; +} + +GENERATE_INSTALL_FUNC(lkrg_dummy) diff --git a/src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.h b/src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.h new file mode 100644 index 0000000..cf87ff7 --- /dev/null +++ b/src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.h @@ -0,0 +1,26 @@ +/* + * pi3's Linux kernel Runtime Guard + * + * Component: + * - Integrity verification kprobe verification submodule + * + * Notes: + * - Verify if kprobes are enabled and correctly run + * + * Timeline: + * - Created: 2.XII.2022 + * + * Author: + * - Adam 'pi3' Zabrocki (http://pi3.com.pl) + * + */ + +#ifndef P_LKRG_INTEGRITY_VERIFY_KPROBES_H +#define P_LKRG_INTEGRITY_VERIFY_KPROBES_H + +int lkrg_verify_kprobes(void); + +int p_install_lkrg_dummy_hook(int p_isra); +void p_uninstall_lkrg_dummy_hook(void); + +#endif diff --git a/src/modules/wrap/p_struct_wrap.h b/src/modules/wrap/p_struct_wrap.h index 8d0a7c4..05dccc9 100644 --- a/src/modules/wrap/p_struct_wrap.h +++ b/src/modules/wrap/p_struct_wrap.h @@ -199,10 +199,11 @@ static inline int p_ddebug_remove_module(const char *p_name) { #ifdef CONFIG_X86 + #if defined(CONFIG_X86_64) + /* * Get */ - #if defined(CONFIG_X86_64) static inline unsigned long p_regs_get_arg1(struct pt_regs *p_regs) { return p_regs->di; } @@ -248,10 +249,51 @@ static inline unsigned long p_syscall_get_arg2(struct pt_regs *p_regs) { #else return p_regs_get_arg2(p_regs); #endif +} + +/* + * Set + */ +static inline void p_regs_set_arg1(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->di = p_val; +} + +static inline void p_regs_set_arg2(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->si = p_val; +} + +static inline void p_regs_set_ip(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->ip = p_val; +} + +static inline void p_regs_set_ret(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->ax = p_val; +} + +/* + * Syscalls + */ +static inline void p_syscall_set_arg1(struct pt_regs *p_regs, unsigned long p_val) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) && defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) + p_regs_set_arg1((struct pt_regs *)p_regs_get_arg1(p_regs), p_val); +#else + p_regs_set_arg1(p_regs, p_val); +#endif +} + +static inline void p_syscall_set_arg2(struct pt_regs *p_regs, unsigned long p_val) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) && defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) + p_regs_set_arg2((struct pt_regs *)p_regs_get_arg1(p_regs), p_val); +#else + p_regs_set_arg2(p_regs, p_val); +#endif } #else +/* + * Get + */ static inline unsigned long p_regs_get_arg1(struct pt_regs *p_regs) { return p_regs->ax; } @@ -303,47 +345,9 @@ static inline unsigned long p_syscall_get_arg2(struct pt_regs *p_regs) { #endif } - #endif - - /* * Set */ - #if defined(CONFIG_X86_64) - -static inline void p_regs_set_arg1(struct pt_regs *p_regs, unsigned long p_val) { - p_regs->di = p_val; -} - -static inline void p_regs_set_arg2(struct pt_regs *p_regs, unsigned long p_val) { - p_regs->si = p_val; -} - -static inline void p_regs_set_ip(struct pt_regs *p_regs, unsigned long p_val) { - p_regs->ip = p_val; -} - -/* - * Syscalls - */ -static inline void p_syscall_set_arg1(struct pt_regs *p_regs, unsigned long p_val) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) && defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) - p_regs_set_arg1((struct pt_regs *)p_regs_get_arg1(p_regs), p_val); -#else - p_regs_set_arg1(p_regs, p_val); -#endif -} - -static inline void p_syscall_set_arg2(struct pt_regs *p_regs, unsigned long p_val) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) && defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) - p_regs_set_arg2((struct pt_regs *)p_regs_get_arg1(p_regs), p_val); -#else - p_regs_set_arg2(p_regs, p_val); -#endif -} - - #else - static inline void p_regs_set_arg1(struct pt_regs *p_regs, unsigned long p_val) { p_regs->ax = p_val; } @@ -360,6 +364,10 @@ static inline void p_regs_set_ip(struct pt_regs *p_regs, unsigned long p_val) { p_regs->ip = p_val; } +static inline void p_regs_set_ret(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->ax = p_val; +} + /* * Syscalls */ @@ -548,6 +556,10 @@ static inline void p_regs_set_ip(struct pt_regs *p_regs, unsigned long p_val) { p_regs->ARM_pc = p_val; } +static inline void p_regs_set_ret(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->ARM_r0 = p_val; +} + /* * Syscalls */ @@ -684,6 +696,10 @@ static inline void p_regs_set_ip(struct pt_regs *p_regs, unsigned long p_val) { p_regs->pc = p_val; } +static inline void p_regs_set_ret(struct pt_regs *p_regs, unsigned long p_val) { + p_regs->regs[0] = p_val; +} + /* * Syscalls */ diff --git a/src/p_lkrg_main.c b/src/p_lkrg_main.c index 3155bff..ad0011f 100644 --- a/src/p_lkrg_main.c +++ b/src/p_lkrg_main.c @@ -409,6 +409,27 @@ static int __init p_lkrg_register(void) { p_parse_module_params(); P_SYM(p_find_me) = THIS_MODULE; + /* + * Verify if kprobes run as intended + */ + + /* Register kprobes hooks necessary to verify kprobes itself */ + if (p_install_lkrg_dummy_hook(0)) { + p_print_log(P_LOG_FATAL, "Can't hook 'lkrg_dummy'"); + return P_LKRG_GENERAL_ERROR; + } + + /* Verify kprobes now */ + if (lkrg_verify_kprobes()) { + /* + * Kprobes does not work as intended. + * LKRG can't function without it, stop initialization! + */ + p_print_log(P_LOG_FATAL, "Can't continue initialization without working kprobes"); + p_uninstall_lkrg_dummy_hook(); + return P_LKRG_GENERAL_ERROR; + } + P_SYM_INIT(freeze_processes, int (*)(void)) P_SYM_INIT(thaw_processes, void (*)(void)) #if defined(CONFIG_X86) && LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) @@ -548,6 +569,7 @@ p_main_error: p_unregister_arch_metadata(); p_offload_cache_delete(); p_deregister_module_notifier(); + p_uninstall_lkrg_dummy_hook(); if (p_db.p_CPU_metadata_array) { p_kzfree(p_db.p_CPU_metadata_array); p_db.p_CPU_metadata_array = NULL; @@ -610,7 +632,7 @@ static void __exit p_lkrg_deregister(void) { p_unregister_arch_metadata(); p_offload_cache_delete(); p_deregister_module_notifier(); - + p_uninstall_lkrg_dummy_hook(); if (p_db.p_CPU_metadata_array) p_kzfree(p_db.p_CPU_metadata_array);