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);