Skip to content

Commit

Permalink
Add a kprobe verification functionality
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
Adam-pi3 authored and solardiz committed Dec 4, 2022
1 parent 7db7483 commit 26f36ed
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 40 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
6 changes: 6 additions & 0 deletions src/modules/integrity_timer/p_integrity_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

/*
Expand Down
3 changes: 3 additions & 0 deletions src/modules/integrity_timer/p_integrity_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
74 changes: 74 additions & 0 deletions src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.c
Original file line number Diff line number Diff line change
@@ -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)
26 changes: 26 additions & 0 deletions src/modules/integrity_timer/verify_kprobes/p_verify_kprobes.h
Original file line number Diff line number Diff line change
@@ -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
94 changes: 55 additions & 39 deletions src/modules/wrap/p_struct_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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
*/
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
*/
Expand Down
24 changes: 23 additions & 1 deletion src/p_lkrg_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -548,6 +569,7 @@ static int __init p_lkrg_register(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);
p_db.p_CPU_metadata_array = NULL;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 26f36ed

Please sign in to comment.