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).
This commit is contained in:
Adam_pi3 2022-11-30 22:53:09 +00:00 committed by Solar Designer
parent 7db7483880
commit 26f36ed495
7 changed files with 188 additions and 40 deletions

View file

@ -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 \

View file

@ -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();
/*

View file

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

View file

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

View file

@ -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

View file

@ -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
*/

View file

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