mirror of https://github.com/openwall/lkrg.git
Initial LKRG-main
This commit is contained in:
commit
45cf3846d0
|
@ -0,0 +1,64 @@
|
|||
##
|
||||
# Makefile for p_lkrg
|
||||
#
|
||||
# Author:
|
||||
# - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
##
|
||||
|
||||
export CFLAGS="$CFLAGS"
|
||||
|
||||
P_OUTPUT = "output"
|
||||
|
||||
P_CLI_CMD = "p_lkrg-client"
|
||||
P_CLI_KMOD = "p_lkrg_kmod_cli.ko"
|
||||
|
||||
obj-m += p_lkrg.o
|
||||
p_lkrg-objs += src/modules/ksyms/p_resolve_ksym.o \
|
||||
src/modules/hashing/p_super_fast_hash.o \
|
||||
src/modules/comm_channel/p_comm_channel.o \
|
||||
src/modules/wrap/p_struct_wrap.o \
|
||||
src/modules/hashing/p_crypto_sha1.o \
|
||||
src/modules/integrity_timer/p_integrity_timer.o \
|
||||
src/modules/kmod/p_kmod.o \
|
||||
src/modules/database/CPU.o \
|
||||
src/modules/database/arch/x86/IDT_MSR_CRx.o \
|
||||
src/modules/database/p_database.o \
|
||||
src/modules/notifiers/p_notifiers.o \
|
||||
src/modules/self-defense/hiding/p_hiding.o \
|
||||
src/modules/exploit_detection/p_rb_ed_trees/p_rb_ed_pids/p_rb_ed_pids_tree.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_execve/p_sys_execve.o \
|
||||
src/modules/exploit_detection/syscalls/p_do_exit/p_do_exit.o \
|
||||
src/modules/exploit_detection/syscalls/p_do_fork/p_do_fork.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setuid/p_sys_setuid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setreuid/p_sys_setreuid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setresuid/p_sys_setresuid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setfsuid/p_sys_setfsuid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setgid/p_sys_setgid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setregid/p_sys_setregid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setresgid/p_sys_setresgid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setfsgid/p_sys_setfsgid.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_setgroups/p_sys_setgroups.o \
|
||||
src/modules/exploit_detection/syscalls/p_do_init_module/p_do_init_module.o \
|
||||
src/modules/exploit_detection/syscalls/p_sys_delete_module/p_sys_delete_module.o \
|
||||
src/modules/exploit_detection/syscalls/p_may_open/p_may_open.o \
|
||||
src/modules/exploit_detection/p_exploit_detection.o \
|
||||
src/p_lkrg_main.o
|
||||
|
||||
|
||||
all:
|
||||
# $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
mkdir -p $(P_OUTPUT)
|
||||
mv $(PWD)/p_lkrg.ko $(P_OUTPUT)
|
||||
|
||||
install:
|
||||
mkdir -p /lib/modules/`uname -r`/kernel/arch/x86/kernel/
|
||||
cp p_krd.ko /lib/modules/`uname -r`/kernel/arch/x86/kernel/p_krd.ko
|
||||
depmod /lib/modules/`uname -r`/kernel/arch/x86/kernel/p_krd.ko
|
||||
|
||||
clean:
|
||||
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
$(RM) Module.markers modules.order
|
||||
$(RM) $(PWD)/src/modules/kmod/client/kmod/Module.markers
|
||||
$(RM) $(PWD)/src/modules/kmod/client/kmod/modules.order
|
||||
$(RM) -rf $(P_OUTPUT)
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Communication channel - sysctl interface
|
||||
*
|
||||
* Notes:
|
||||
* - Allow administrator of the system to interact with LKRG via sysctl interface
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 26.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
|
||||
static struct ctl_table_header *p_sysctl_handle;
|
||||
|
||||
static int p_timestamp_min = 0x5;
|
||||
static int p_timestamp_max = 0x708; // 1800
|
||||
|
||||
static int p_log_level_min = P_LOG_LEVEL_NONE;
|
||||
static int p_log_level_max = P_LOG_LEVEL_MAX - 1;
|
||||
|
||||
static int p_block_module_min = 0x0;
|
||||
static int p_block_module_max = 0x1;
|
||||
|
||||
static int p_force_run_min = 0x0;
|
||||
static int p_force_run_max = 0x1;
|
||||
|
||||
#ifdef P_LKRG_UNHIDE
|
||||
static int p_unhide_module_min = 0x0;
|
||||
static int p_unhide_module_max = 0x1;
|
||||
#endif
|
||||
|
||||
static int p_sysctl_force_run(struct ctl_table *p_table, int p_write,
|
||||
void __user *p_buffer, size_t *p_len, loff_t *p_pos);
|
||||
#ifdef P_LKRG_UNHIDE
|
||||
static int p_sysctl_unhide(struct ctl_table *p_table, int p_write,
|
||||
void __user *p_buffer, size_t *p_len, loff_t *p_pos);
|
||||
#endif
|
||||
|
||||
struct ctl_table p_lkrg_sysctl_base[] = {
|
||||
{
|
||||
.procname = "LKRG",
|
||||
.mode = 0600,
|
||||
.child = p_lkrg_sysctl_table,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ctl_table p_lkrg_sysctl_table[] = {
|
||||
{
|
||||
.procname = "timestamp",
|
||||
.data = &p_lkrg_global_ctrl.p_timestamp,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0600,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &p_timestamp_min,
|
||||
.extra2 = &p_timestamp_max,
|
||||
},
|
||||
{
|
||||
.procname = "block_modules",
|
||||
.data = &p_lkrg_global_ctrl.p_block_modules,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0600,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &p_block_module_min,
|
||||
.extra2 = &p_block_module_max,
|
||||
},
|
||||
{
|
||||
.procname = "log_level",
|
||||
.data = &p_lkrg_global_ctrl.p_log_level,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0600,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &p_log_level_min,
|
||||
.extra2 = &p_log_level_max,
|
||||
},
|
||||
{
|
||||
.procname = "force_run",
|
||||
.data = &p_lkrg_global_ctrl.p_force_run,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0600,
|
||||
.proc_handler = p_sysctl_force_run,
|
||||
.extra1 = &p_force_run_min,
|
||||
.extra2 = &p_force_run_max,
|
||||
},
|
||||
#ifdef P_LKRG_UNHIDE
|
||||
{
|
||||
.procname = "unhide",
|
||||
.data = &p_lkrg_global_ctrl.p_unhide_module,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0600,
|
||||
.proc_handler = p_sysctl_unhide,
|
||||
.extra1 = &p_unhide_module_min,
|
||||
.extra2 = &p_unhide_module_max,
|
||||
},
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
static int p_sysctl_force_run(struct ctl_table *p_table, int p_write,
|
||||
void __user *p_buffer, size_t *p_len, loff_t *p_pos) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_sysctl_force_run>\n");
|
||||
|
||||
if ( (p_ret = proc_dointvec_minmax(p_table, p_write, p_buffer, p_len, p_pos)) == 0 && p_write) {
|
||||
if (p_lkrg_global_ctrl.p_force_run) {
|
||||
p_offload_work(0); // run integrity check!
|
||||
p_lkrg_global_ctrl.p_force_run = 0x0; // Restore 0 value - user only sees that value!
|
||||
}
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_sysctl_force_run>\n");
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
#ifdef P_LKRG_UNHIDE
|
||||
static int p_sysctl_unhide(struct ctl_table *p_table, int p_write,
|
||||
void __user *p_buffer, size_t *p_len, loff_t *p_pos) {
|
||||
|
||||
int p_ret;
|
||||
unsigned int p_tmp;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_sysctl_unhide>\n");
|
||||
|
||||
p_tmp = p_lkrg_global_ctrl.p_unhide_module;
|
||||
if ( (p_ret = proc_dointvec_minmax(p_table, p_write, p_buffer, p_len, p_pos)) == 0 && p_write) {
|
||||
if (p_lkrg_global_ctrl.p_unhide_module) {
|
||||
p_lkrg_global_ctrl.p_unhide_module = p_tmp; // Restore previous state - for sync
|
||||
p_unhide_itself(); // Unhide module!
|
||||
} else {
|
||||
p_lkrg_global_ctrl.p_unhide_module = p_tmp; // Restore previous state - for sync
|
||||
p_hide_itself(); // Hide module!
|
||||
}
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_sysctl_unhide>\n");
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int p_register_comm_channel(void) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_register_comm_channel>\n");
|
||||
|
||||
if ( (p_sysctl_handle = register_sysctl_table(p_lkrg_sysctl_base)) == NULL) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"Communication channel error! Can't register 'sysctl' table :( Exiting...\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_register_comm_channel_out;
|
||||
}
|
||||
|
||||
|
||||
p_register_comm_channel_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_register_comm_channel>\n");
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
void p_deregister_comm_channel(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_deregister_comm_channel>\n");
|
||||
|
||||
unregister_sysctl_table(p_sysctl_handle);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_deregister_comm_channel>\n");
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Communication channel - sysctl interface
|
||||
*
|
||||
* Notes:
|
||||
* - Allow administrator of the system to interact with LKRG via sysctl interface
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 26.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_COMM_CHANNEL_SYSCTL_H
|
||||
#define P_LKRG_COMM_CHANNEL_SYSCTL_H
|
||||
|
||||
extern struct ctl_table p_lkrg_sysctl_base[];
|
||||
extern struct ctl_table p_lkrg_sysctl_table[];
|
||||
|
||||
int p_register_comm_channel(void);
|
||||
void p_deregister_comm_channel(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Database module
|
||||
* => submodule for checking system configuration regarding CPUs
|
||||
*
|
||||
* Notes:
|
||||
* - Some of the critical data may exists per logical CPU (core)
|
||||
* and need to be independently verified / checked.
|
||||
* Additionally, it is strongly dependend from the architecture.
|
||||
* Linux kernel defines different types of CPUs:
|
||||
* => online CPUs
|
||||
* => possible CPUs
|
||||
* => present CPUs
|
||||
* => active CPUs
|
||||
*
|
||||
* This module will keep information about how many 'active CPUs',
|
||||
* 'online CPUs' and 'present CPUs' exists in the current system.
|
||||
* Additionally Linux kernel exports global CPU id count ('nr_cpu_ids')
|
||||
* which is initialized per boot time. If over the time any of the
|
||||
* CPU will be hot plugged / activated this information will be
|
||||
* visible for us!
|
||||
*
|
||||
* - x86 (and amd64) arch: following informations are critical and need
|
||||
* to be verified (checking integrity):
|
||||
* => IDT base and/or entire table
|
||||
* => MSRs
|
||||
*
|
||||
* - Since Linux 4.10 there isn't CPU_[ONLINE/DEAD] notifiers :(
|
||||
* Hot CPU plug[in/out] notification logic has completaly changed. More information
|
||||
* Can be found here:
|
||||
* => https://patchwork.kernel.org/patch/9448577/
|
||||
* On new kernel (4.10.+) we use modern hot CPU plug[in/out] logic.
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 28.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
/*
|
||||
* #define get_cpu() ({ preempt_disable(); smp_processor_id(); })
|
||||
* #define put_cpu() preempt_enable()
|
||||
*/
|
||||
|
||||
void p_get_cpus(p_cpu_info *p_arg) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_get_cpus>\n");
|
||||
|
||||
memset(p_arg,0x0,sizeof(p_cpu_info));
|
||||
|
||||
p_arg->online_CPUs = num_online_cpus();
|
||||
p_arg->possible_CPUs = num_possible_cpus();
|
||||
p_arg->present_CPUs = num_present_cpus();
|
||||
p_arg->active_CPUs = num_active_cpus();
|
||||
|
||||
p_arg->p_nr_cpu_ids = nr_cpu_ids;
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"<p_get_cpus> online[%d] possible[%d] present[%d] active[%d] nr_cpu_ids[%d]\n",
|
||||
p_arg->online_CPUs,p_arg->possible_CPUs,p_arg->present_CPUs,p_arg->active_CPUs,
|
||||
p_arg->p_nr_cpu_ids);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_get_cpus>\n");
|
||||
|
||||
}
|
||||
|
||||
int p_cmp_cpus(p_cpu_info *p_arg1, p_cpu_info *p_arg2) {
|
||||
|
||||
int p_flag = 0x0;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_cmp_cpus>\n");
|
||||
|
||||
if (p_arg1->online_CPUs != p_arg2->online_CPUs) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"ALERT !!! NUMBER OF ONLINE CPUs IS DIFFERENT !!!\n");
|
||||
p_flag++;
|
||||
}
|
||||
if (p_arg1->possible_CPUs != p_arg2->possible_CPUs) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"ALERT !!! NUMBER OF POSSIBLE CPUs IS DIFFERENT !!!\n");
|
||||
p_flag++;
|
||||
}
|
||||
if (p_arg1->present_CPUs != p_arg2->present_CPUs) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"ALERT !!! NUMBER OF PRESENT CPUs IS DIFFERENT !!!\n");
|
||||
p_flag++;
|
||||
}
|
||||
if (p_arg1->active_CPUs != p_arg2->active_CPUs) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"ALERT !!! NUMBER OF ACTIVE CPUs IS DIFFERENT !!!\n");
|
||||
p_flag++;
|
||||
}
|
||||
if (p_arg1->p_nr_cpu_ids != p_arg2->p_nr_cpu_ids) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"ALERT !!! VARIABLE 'nr_cpu_ids' IS DIFFERENT !!!\n");
|
||||
p_flag++;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_cmp_cpus>\n");
|
||||
|
||||
return p_flag;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
/*
|
||||
* Notification routine when new CPU is online or become offline.
|
||||
* It may be critical from the security point of view, because new per-CPU
|
||||
* metadata must be set-up. We must write them down and verify it.
|
||||
*/
|
||||
int p_cpu_callback(struct notifier_block *p_block, unsigned long p_action, void *p_hcpu) {
|
||||
|
||||
unsigned int p_cpu = (unsigned long)p_hcpu;
|
||||
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_cpu_callback>\n");
|
||||
|
||||
// TODO: lock db
|
||||
// lock is done in the individual action function
|
||||
// to reduce locking/starving time
|
||||
|
||||
switch (p_action) {
|
||||
|
||||
case CPU_ONLINE:
|
||||
case CPU_ONLINE_FROZEN:
|
||||
p_cpu_online_action(p_cpu);
|
||||
break;
|
||||
|
||||
case CPU_DEAD:
|
||||
case CPU_DEAD_FROZEN:
|
||||
p_cpu_dead_action(p_cpu);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: unlock db
|
||||
// lock is done in the individual action function
|
||||
// to reduce locking/starving time
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_cpu_callback>\n");
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int p_cpu_online_action(unsigned int p_cpu) {
|
||||
|
||||
int tmp_online_CPUs = p_db.p_cpu.online_CPUs;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Entering function <p_cpu_online_action>\n");
|
||||
|
||||
/* We are heavly consuming module list here - take 'module_mutex' */
|
||||
mutex_lock(&module_mutex);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* Hacky way of 'stopping' KOBJs activities */
|
||||
mutex_lock(p_kernfs_mutex);
|
||||
#endif
|
||||
|
||||
spin_lock(&p_db_lock);
|
||||
|
||||
smp_call_function_single(p_cpu,p_dump_IDT_MSR_CRx,p_db.p_IDT_MSR_CRx_array,true);
|
||||
|
||||
/* Let's play... God mode on ;) */
|
||||
// spin_lock_irqsave(&p_db_lock,p_db_flags);
|
||||
|
||||
p_get_cpus(&p_db.p_cpu);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
|
||||
p_db.p_cpu.active_CPUs++;
|
||||
#endif
|
||||
p_db.p_IDT_MSR_CRx_hashes = hash_from_CPU_data(p_db.p_IDT_MSR_CRx_array);
|
||||
|
||||
/* UP kernel became SMP one! we need to do more work ;/ */
|
||||
if (tmp_online_CPUs == 1 && p_db.p_cpu.online_CPUs > 1) {
|
||||
/* First recalculate _STEXT and other critical kernel's data - now is SMPbooted! */
|
||||
if (hash_from_ex_table() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU ONLINE ERROR: CANNOT GET HASH FROM EXCEPTION TABLE!\n");
|
||||
}
|
||||
if (hash_from_kernel_stext() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU ONLINE ERROR: CANNOT GET HASH FROM _STEXT!\n");
|
||||
}
|
||||
if (hash_from_kernel_rodata() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU ONLINE ERROR: CANNOT GET HASH FROM _RODATA!\n");
|
||||
}
|
||||
if (hash_from_iommu_table() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU ONLINE ERROR: CANNOT GET HASH FROM IOMMU TABLE!\n");
|
||||
}
|
||||
/* Now recalculate modules, again some macros are different now ! */
|
||||
/* First free currently used memory! */
|
||||
if (p_db.p_module_list_array)
|
||||
kzfree(p_db.p_module_list_array);
|
||||
if (p_db.p_module_kobj_array)
|
||||
kzfree(p_db.p_module_kobj_array);
|
||||
/* OK, now recalculate hashes again! */
|
||||
|
||||
while(p_kmod_hash(&p_db.p_module_list_nr,&p_db.p_module_list_array,
|
||||
&p_db.p_module_kobj_nr,&p_db.p_module_kobj_array) != P_LKRG_SUCCESS);
|
||||
|
||||
/* Update global module list/kobj hash */
|
||||
p_db.p_module_list_hash = p_super_fast_hash((unsigned char *)p_db.p_module_list_array,
|
||||
(unsigned int)p_db.p_module_list_nr * sizeof(p_module_list_mem));
|
||||
p_db.p_module_kobj_hash = p_super_fast_hash((unsigned char *)p_db.p_module_kobj_array,
|
||||
(unsigned int)p_db.p_module_kobj_nr * sizeof(p_module_kobj_mem));
|
||||
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module list' => [0x%x]\n",p_db.p_module_list_hash);
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module kobj(s)' => [0x%x]\n",p_db.p_module_kobj_hash);
|
||||
|
||||
/* We should be fine now! */
|
||||
}
|
||||
|
||||
/* God mode off ;) */
|
||||
// spin_unlock_irqrestore(&p_db_lock,p_db_flags);
|
||||
spin_unlock(&p_db_lock);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* unlock KOBJ activities */
|
||||
mutex_unlock(p_kernfs_mutex);
|
||||
#endif
|
||||
/* Release the 'module_mutex' */
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Leaving function <p_cpu_online_action>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
int p_cpu_dead_action(unsigned int p_cpu) {
|
||||
|
||||
int tmp_online_CPUs = p_db.p_cpu.online_CPUs;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Entering function <p_cpu_dead_action>\n");
|
||||
|
||||
/* We are heavly consuming module list here - take 'module_mutex' */
|
||||
mutex_lock(&module_mutex);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* Hacky way of 'stopping' KOBJs activities */
|
||||
mutex_lock(p_kernfs_mutex);
|
||||
#endif
|
||||
|
||||
spin_lock(&p_db_lock);
|
||||
|
||||
p_db.p_IDT_MSR_CRx_array[p_cpu].p_cpu_online = P_CPU_OFFLINE;
|
||||
|
||||
/* Update database */
|
||||
|
||||
/* Let's play... God mode on ;) */
|
||||
// spin_lock_irqsave(&p_db_lock,p_db_flags);
|
||||
|
||||
p_get_cpus(&p_db.p_cpu);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
|
||||
p_db.p_cpu.online_CPUs--;
|
||||
#endif
|
||||
p_db.p_IDT_MSR_CRx_hashes = hash_from_CPU_data(p_db.p_IDT_MSR_CRx_array);
|
||||
|
||||
/*
|
||||
* SMP kernel might became UP one! Never had a chance to test it ;/
|
||||
* In case when UP kernel starting to be SMP one, some critical macros
|
||||
* are changed and hashes from TEXT section of kernel core AND modules
|
||||
* are changing so we recalculating them. It is possible we should follow
|
||||
* the same scenario in this situation...
|
||||
*/
|
||||
if (tmp_online_CPUs > 1 && p_db.p_cpu.online_CPUs == 1) {
|
||||
/* First recalculate _STEXT and other critical kernel's data - now is not SMPbooted! */
|
||||
if (hash_from_ex_table() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU OFFLINE ERROR: CANNOT GET HASH FROM EXCEPTION TABLE!\n");
|
||||
}
|
||||
if (hash_from_kernel_stext() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU OFFLINE ERROR: CANNOT GET HASH FROM _STEXT!\n");
|
||||
}
|
||||
if (hash_from_kernel_rodata() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU OFFLINE ERROR: CANNOT GET HASH FROM _RODATA!\n");
|
||||
}
|
||||
if (hash_from_iommu_table() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CPU OFFLINE ERROR: CANNOT GET HASH FROM IOMMU TABLE!\n");
|
||||
}
|
||||
/* Now recalculate modules, again some macros are different now ! */
|
||||
/* First free currently used memory! */
|
||||
if (p_db.p_module_list_array)
|
||||
kzfree(p_db.p_module_list_array);
|
||||
if (p_db.p_module_kobj_array)
|
||||
kzfree(p_db.p_module_kobj_array);
|
||||
/* OK, now recalculate hashes again! */
|
||||
|
||||
while(p_kmod_hash(&p_db.p_module_list_nr,&p_db.p_module_list_array,
|
||||
&p_db.p_module_kobj_nr,&p_db.p_module_kobj_array) != P_LKRG_SUCCESS);
|
||||
|
||||
/* Update global module list/kobj hash */
|
||||
p_db.p_module_list_hash = p_super_fast_hash((unsigned char *)p_db.p_module_list_array,
|
||||
(unsigned int)p_db.p_module_list_nr * sizeof(p_module_list_mem));
|
||||
p_db.p_module_kobj_hash = p_super_fast_hash((unsigned char *)p_db.p_module_kobj_array,
|
||||
(unsigned int)p_db.p_module_kobj_nr * sizeof(p_module_kobj_mem));
|
||||
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module list' => [0x%x]\n",p_db.p_module_list_hash);
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module kobj(s)' => [0x%x]\n",p_db.p_module_kobj_hash);
|
||||
|
||||
/* We should be fine now! */
|
||||
}
|
||||
|
||||
/* God mode off ;) */
|
||||
// spin_unlock_irqrestore(&p_db_lock,p_db_flags);
|
||||
spin_unlock(&p_db_lock);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* unlock KOBJ activities */
|
||||
mutex_unlock(p_kernfs_mutex);
|
||||
#endif
|
||||
/* Release the 'module_mutex' */
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Leaving function <p_cpu_dead_action>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
struct notifier_block p_cpu_notifier =
|
||||
{
|
||||
.notifier_call = p_cpu_callback,
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Database module
|
||||
* => Submodule - X86/AMD64 IDT specific structures
|
||||
*
|
||||
* Notes:
|
||||
* - X86/AMD64 IDT specific structures
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 28.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_IDT_H
|
||||
#define P_LKRG_IDT_H
|
||||
|
||||
/*
|
||||
* IDT descriptor
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
typedef struct p_idt_descriptor {
|
||||
|
||||
unsigned short off_low;
|
||||
unsigned short sel;
|
||||
unsigned char none, flags;
|
||||
unsigned short off_midl;
|
||||
unsigned int off_high;
|
||||
unsigned int padding;
|
||||
|
||||
} p_idt_descriptor;
|
||||
#else
|
||||
typedef struct p_idt_descriptor {
|
||||
|
||||
unsigned short off_low;
|
||||
unsigned short sel;
|
||||
unsigned char none, flags;
|
||||
unsigned short off_high;
|
||||
|
||||
} p_idt_descriptor;
|
||||
#endif
|
||||
|
||||
#define P_X86_MAX_IDT 256
|
||||
|
||||
/*
|
||||
* Each CPU in the system independetly dump own critical data and save it using
|
||||
* following structure - it includes:
|
||||
* - IDT base
|
||||
* - IDT size
|
||||
* - hash from the entire IDT
|
||||
* - MSR (Model Specific Registers)
|
||||
*/
|
||||
typedef struct p_IDT_MSR_CRx_hash_mem {
|
||||
|
||||
/*
|
||||
* Some information about CPU to support hot-plug[in/out]
|
||||
*/
|
||||
int p_cpu_id;
|
||||
char p_cpu_online; // 1 - online, 0 - offline
|
||||
|
||||
/*
|
||||
* IDT information
|
||||
*/
|
||||
long p_base; // IDT base from IDTR
|
||||
short p_size; // IDT size from IDTR
|
||||
uint32_t p_hash; // hash from entire IDT table:
|
||||
// p_base * P_X86_MAX_IDT
|
||||
|
||||
/*
|
||||
* Now MSRs...
|
||||
*/
|
||||
|
||||
/* x86 critical MSRs */
|
||||
u64 p_MSR_IA32_SYSENTER_CS; // 0x00000174
|
||||
u64 p_MSR_IA32_SYSENTER_ESP; // 0x00000175
|
||||
u64 p_MSR_IA32_SYSENTER_EIP; // 0x00000176
|
||||
|
||||
/* MSR PAT */
|
||||
u64 p_MSR_IA32_CR_PAT; // 0x00000277
|
||||
|
||||
/* MSR APIC */
|
||||
u64 p_MSR_IA32_APICBASE; // 0x0000001b
|
||||
|
||||
/* MSR EFER - extended feature register */
|
||||
u64 p_MSR_EFER; // 0xc0000080
|
||||
|
||||
|
||||
/* AMD64 critical MSRs */
|
||||
|
||||
/* MSR STAR - legacy mode SYSCALL target */
|
||||
u64 p_MSR_STAR; // 0xc0000081
|
||||
|
||||
/*
|
||||
* From: "arch/x86/kernel/cpu/common.c"
|
||||
*
|
||||
* AMD64 syscalls:
|
||||
* wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
|
||||
*
|
||||
*/
|
||||
/* MSR LSTAR - long mode SYSCALL target */
|
||||
u64 p_MSR_LSTAR; // 0xc0000082
|
||||
|
||||
/* MSR CSTAR - compat mode SYSCALL target */
|
||||
u64 p_MSR_CSTAR; // 0xc0000083
|
||||
|
||||
/* MSR SYSCALL_MASK - EFLAGS mask for syscall */
|
||||
u64 p_MSR_SYSCALL_MASK; // 0xc0000084
|
||||
|
||||
/* MSR KERNEL_GS_BASE - SwapGS GS shadow */
|
||||
// u64 p_MSR_KERNEL_GS_BASE; // 0xc0000102 <- more research needed,
|
||||
// saw some user mode code which might
|
||||
// change that - arch prctl
|
||||
|
||||
/*
|
||||
* ... MORE MSRs ... ;)
|
||||
*/
|
||||
|
||||
} p_IDT_MSR_CRx_hash_mem;
|
||||
|
||||
|
||||
void p_dump_IDT_MSR_CRx(void *_p_arg);
|
||||
//void p_dump_IDT_MSR_CRx(p_IDT_MSR_CRx_hash_mem *p_arg);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Database module
|
||||
* => submodule for dumping IDT
|
||||
*
|
||||
* Notes:
|
||||
* - IDT can be different per CPU which makes it quite complicated...
|
||||
* we need to run 'dumping' IDT on each CPU to be sure everything
|
||||
* is clear.
|
||||
*
|
||||
* - Linux kernel defines different types of CPUs:
|
||||
* => online CPUs
|
||||
* => possible CPUs
|
||||
* => present CPUs
|
||||
* => active CPUs
|
||||
*
|
||||
* We are going to run procedure only on 'active CPUs' and different
|
||||
* procedure is checking if number of active CPUs changes over time...
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 27.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
u64 p_read_msr(/*int p_cpu, */u32 p_arg) {
|
||||
|
||||
u32 p_low;
|
||||
u32 p_high;
|
||||
u64 p_val;
|
||||
// int p_err;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_read_msr>\n");
|
||||
|
||||
p_low = p_high = p_val = 0x0;
|
||||
|
||||
__asm__("rdmsr": P_MSR_ASM_READ(p_val,p_low,p_high)
|
||||
: "c"(p_arg)
|
||||
: );
|
||||
|
||||
// Sometime may generate OOPS ;/
|
||||
/*
|
||||
if ( (p_err = rdmsr_safe_on_cpu(p_cpu,p_arg,&p_low,&p_high))) {
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_read_msr> rdmsr_safe_on_cpu() error! - shouldn't happend [err=0x%x]!\n",p_err);
|
||||
return 0x0;
|
||||
}
|
||||
p_val = (u64 )p_high << 32 | p_low;
|
||||
*/
|
||||
|
||||
p_val = P_MSR_ASM_RET(p_val,p_low,p_high);
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"<p_read_msr[%d]> MSR arg[0x%x] value[%llx]\n",smp_processor_id(),p_arg,p_val);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_read_msr>\n");
|
||||
|
||||
return p_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is independetly executed by each active CPU.
|
||||
* IDT is individual per logical CPU (same as MSRs, etc).
|
||||
*/
|
||||
void p_dump_IDT_MSR_CRx(void *_p_arg) {
|
||||
|
||||
p_IDT_MSR_CRx_hash_mem *p_arg = _p_arg;
|
||||
/*
|
||||
* IDTR register
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
unsigned char p_idtr[0xA];
|
||||
#else
|
||||
unsigned char p_idtr[0x6];
|
||||
#endif
|
||||
|
||||
int p_curr_cpu = 0xFFFFFFFF;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_dump_IDT_MSR_CRx>\n");
|
||||
|
||||
/*
|
||||
* Get ID and lock - no preemtion.
|
||||
*/
|
||||
// p_curr_cpu = get_cpu();
|
||||
p_curr_cpu = smp_processor_id();
|
||||
|
||||
/*
|
||||
* To avoid multpile access to the same page from all CPUs
|
||||
* memory will be already zero'd
|
||||
*/
|
||||
// memset(&p_arg[p_curr_cpu],0x0,sizeof(p_IDT_MSR_CRx_hash_mem));
|
||||
|
||||
/*
|
||||
* First fill information about current CPU
|
||||
*/
|
||||
p_arg[p_curr_cpu].p_cpu_id = p_curr_cpu;
|
||||
p_arg[p_curr_cpu].p_cpu_online = P_CPU_ONLINE;
|
||||
|
||||
/*
|
||||
* IDT...
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
__asm__("sidt %0\n"
|
||||
"movq %3, %%rax\n"
|
||||
"movq %%rax,%1\n"
|
||||
"movw %4,%%ax\n"
|
||||
"movw %%ax,%2\n":"=m"(p_idtr),"=m"(p_arg[p_curr_cpu].p_base),"=m"(p_arg[p_curr_cpu].p_size)
|
||||
:"m"(p_idtr[2]),"m"(p_idtr[0])
|
||||
:"%rax");
|
||||
#else
|
||||
__asm__("sidt %0\n"
|
||||
"movl %3, %%eax\n"
|
||||
"movl %%eax,%1\n"
|
||||
"movw %4,%%ax\n"
|
||||
"movw %%ax,%2\n":"=m"(p_idtr),"=m"(p_arg[p_curr_cpu].p_base),"=m"(p_arg[p_curr_cpu].p_size)
|
||||
:"m"(p_idtr[2]),"m"(p_idtr[0])
|
||||
:"%eax");
|
||||
#endif
|
||||
|
||||
p_arg[p_curr_cpu].p_hash = p_super_fast_hash((unsigned char *)p_arg[p_curr_cpu].p_base,
|
||||
(unsigned int)sizeof(p_idt_descriptor) * P_X86_MAX_IDT);
|
||||
|
||||
// DEBUG
|
||||
#ifdef P_LKRG_DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] IDT => base[0x%lx] size[0x%x] hash[0x%x]\n",
|
||||
p_arg[p_curr_cpu].p_cpu_id,p_arg[p_curr_cpu].p_base,p_arg[p_curr_cpu].p_size,p_arg[p_curr_cpu].p_hash);
|
||||
|
||||
do {
|
||||
p_idt_descriptor *p_test;
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"Reading IDT 1 to verify data:");
|
||||
p_test = (p_idt_descriptor *)(p_arg[p_curr_cpu].p_base+(sizeof(p_idt_descriptor)*1));
|
||||
#ifdef CONFIG_X86_64
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"off_low[0x%x]"
|
||||
"sel[0x%x]"
|
||||
"none[0x%x]"
|
||||
"flags[0x%x]"
|
||||
"off_midl[0x%x]"
|
||||
"off_high[0x%x]"
|
||||
"padding[0x%x]\n",
|
||||
p_test->off_low,
|
||||
p_test->sel,
|
||||
p_test->none,
|
||||
p_test->flags,
|
||||
p_test->off_midl,
|
||||
p_test->off_high,
|
||||
p_test->padding
|
||||
);
|
||||
#else
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"off_low[0x%x]"
|
||||
"sel[0x%x]"
|
||||
"none[0x%x]"
|
||||
"flags[0x%x]"
|
||||
"off_high[0x%x]\n",
|
||||
p_test->off_low,
|
||||
p_test->sel,
|
||||
p_test->none,
|
||||
p_test->flags,
|
||||
p_test->off_high
|
||||
);
|
||||
#endif
|
||||
} while(0);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now MSRs...
|
||||
*/
|
||||
|
||||
/* MSR_IA32_SYSENTER_CS */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_CS,MSR_IA32_SYSENTER_CS);
|
||||
// p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_CS = p_read_msr(p_curr_cpu,MSR_IA32_SYSENTER_CS);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_CS) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR IA32_SYSENTER_CS offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_IA32_SYSENTER_CS,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_IA32_SYSENTER_CS[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_CS,&p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_CS);
|
||||
|
||||
|
||||
/* MSR_IA32_SYSENTER_ESP */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_ESP,MSR_IA32_SYSENTER_ESP);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_ESP) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR IA32_SYSENTER_ESP offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_IA32_SYSENTER_ESP,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_IA32_SYSENTER_ESP[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_ESP,&p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_ESP);
|
||||
|
||||
|
||||
/* MSR_IA32_SYSENTER_EIP */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_EIP,MSR_IA32_SYSENTER_EIP);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_EIP) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR IA32_SYSENTER_EIP offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_IA32_SYSENTER_EIP,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_IA32_SYSENTER_EIP[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_EIP,&p_arg[p_curr_cpu].p_MSR_IA32_SYSENTER_EIP);
|
||||
|
||||
|
||||
/* MSR_IA32_CR_PAT */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_IA32_CR_PAT,MSR_IA32_CR_PAT);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_IA32_CR_PAT) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR IA32_CR_PAT offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_IA32_CR_PAT,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_IA32_CR_PAT[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_IA32_CR_PAT,&p_arg[p_curr_cpu].p_MSR_IA32_CR_PAT);
|
||||
|
||||
|
||||
/* MSR_IA32_APICBASE */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_IA32_APICBASE,MSR_IA32_APICBASE);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_IA32_APICBASE) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR IA32_APICBASE offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_IA32_APICBASE,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_IA32_APICBASE[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_IA32_APICBASE,&p_arg[p_curr_cpu].p_MSR_IA32_APICBASE);
|
||||
|
||||
|
||||
/* MSR_EFER */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_EFER,MSR_EFER);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_EFER) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR EFER offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_EFER,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_EFER[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_EFER,&p_arg[p_curr_cpu].p_MSR_EFER);
|
||||
|
||||
|
||||
/* MSR_STAR */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_STAR,MSR_STAR);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_STAR) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR STAR offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_STAR,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_STAR[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_STAR,&p_arg[p_curr_cpu].p_MSR_STAR);
|
||||
|
||||
|
||||
/* MSR_LSTAR */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_LSTAR,MSR_LSTAR);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_LSTAR) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR LSTAR offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_LSTAR,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_LSTAR[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_LSTAR,&p_arg[p_curr_cpu].p_MSR_LSTAR);
|
||||
|
||||
|
||||
/* MSR_CSTAR */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_CSTAR,MSR_CSTAR);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_CSTAR) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR CSTAR offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_CSTAR,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_CSTAR[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_CSTAR,&p_arg[p_curr_cpu].p_MSR_CSTAR);
|
||||
|
||||
|
||||
/* MSR_SYSCALL_MASK */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_SYSCALL_MASK,MSR_SYSCALL_MASK);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_SYSCALL_MASK) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR SYSCALL_MASK offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_SYSCALL_MASK,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_SYSCALL_MASK[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_SYSCALL_MASK,&p_arg[p_curr_cpu].p_MSR_SYSCALL_MASK);
|
||||
|
||||
|
||||
/* p_MSR_KERNEL_GS_BASE */
|
||||
// Try reading at least 3 times before give up in case of error...
|
||||
/*
|
||||
P_MSR_READ_COUNT(3,p_arg[p_curr_cpu].p_MSR_KERNEL_GS_BASE,MSR_KERNEL_GS_BASE);
|
||||
|
||||
if (!p_arg[p_curr_cpu].p_MSR_KERNEL_GS_BASE) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"MSR KERNEL_GS_BASE offset 0x%x on CPU:[%d] is not set!\n",
|
||||
MSR_KERNEL_GS_BASE,p_curr_cpu);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_dump_IDT_MSR> CPU:[%d] MSR: MSR_KERNEL_GS_BASE[0x%llx] address in db[%p]\n",
|
||||
p_curr_cpu,p_arg[p_curr_cpu].p_MSR_KERNEL_GS_BASE,&p_arg[p_curr_cpu].p_MSR_KERNEL_GS_BASE);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now Control Registers
|
||||
*/
|
||||
|
||||
// TODO...
|
||||
|
||||
/*
|
||||
* Unlock preemtion.
|
||||
*/
|
||||
// put_cpu();
|
||||
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_dump_IDT_MSR_CRx>\n");
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Database module
|
||||
* => Submodule - X86/AMD64 MSR specific data
|
||||
*
|
||||
* Notes:
|
||||
* - X86/AMD64 MSR specific data
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 28.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_MSR_H
|
||||
#define P_LKRG_MSR_H
|
||||
|
||||
u64 p_read_msr(/*int p_cpu, */u32 p_arg);
|
||||
|
||||
#define P_MSR_READ_COUNT(x,y,z) \
|
||||
do { \
|
||||
char p_tmp = x-1; \
|
||||
do { \
|
||||
y = p_read_msr(z); \
|
||||
} while(!y && p_tmp--); \
|
||||
} while(0)
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define P_MSR_ASM_RET(val, low, high) (((u64)(high) << 32) | (low))
|
||||
#define P_MSR_ASM_READ(val, low, high) "=a" (low), "=d" (high)
|
||||
#else
|
||||
#define P_MSR_ASM_RET(val, low, high) (val)
|
||||
#define P_MSR_ASM_READ(val, low, high) "=A" (val)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Database module
|
||||
*
|
||||
* Notes:
|
||||
* - Let's create database - calculate hashes
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
p_hash_database p_db;
|
||||
|
||||
|
||||
int hash_from_ex_table(void) {
|
||||
|
||||
unsigned long p_tmp = 0x0;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <hash_from_ex_table>\n");
|
||||
|
||||
p_db.kernel_ex_table.p_addr = (unsigned long *)p_kallsyms_lookup_name("__start___ex_table");
|
||||
p_tmp = (unsigned long)p_kallsyms_lookup_name("__stop___ex_table");
|
||||
|
||||
if (!p_db.kernel_ex_table.p_addr || !p_tmp || p_tmp < (unsigned long)p_db.kernel_ex_table.p_addr) {
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto hash_from_ex_table_out;
|
||||
}
|
||||
|
||||
p_db.kernel_ex_table.p_size = (unsigned long)(p_tmp - (unsigned long)p_db.kernel_ex_table.p_addr);
|
||||
|
||||
p_db.kernel_ex_table.p_hash = p_super_fast_hash((unsigned char *)p_db.kernel_ex_table.p_addr,
|
||||
(unsigned int)p_db.kernel_ex_table.p_size);
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"hash [0x%x] ___ex_table start [0x%lx] size [0x%lx]\n",(int)p_db.kernel_ex_table.p_hash,
|
||||
(long)p_db.kernel_ex_table.p_addr,
|
||||
(long)p_db.kernel_ex_table.p_size);
|
||||
|
||||
hash_from_ex_table_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <hash_from_ex_table> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int hash_from_kernel_stext(void) {
|
||||
|
||||
unsigned long p_tmp = 0x0;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <hash_from_kernel_stext>\n");
|
||||
|
||||
p_db.kernel_stext.p_addr = (unsigned long *)p_kallsyms_lookup_name("_stext");
|
||||
p_tmp = (unsigned long)p_kallsyms_lookup_name("_etext");
|
||||
|
||||
if (!p_db.kernel_stext.p_addr || !p_tmp || p_tmp < (unsigned long)p_db.kernel_stext.p_addr) {
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto hash_from_kernel_stext_out;
|
||||
}
|
||||
|
||||
p_db.kernel_stext.p_size = (unsigned long)(p_tmp - (unsigned long)p_db.kernel_stext.p_addr);
|
||||
|
||||
p_db.kernel_stext.p_hash = p_super_fast_hash((unsigned char *)p_db.kernel_stext.p_addr,
|
||||
(unsigned int)p_db.kernel_stext.p_size);
|
||||
|
||||
/* It is NOT only for debugging... *_JMP_LABEL sux! */
|
||||
if ( (p_db.kernel_stext_copy.p_addr = vmalloc(p_db.kernel_stext.p_size+1)) == NULL) {
|
||||
/*
|
||||
* I should NEVER be here!
|
||||
*/
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"hash_from_kernel_stext(): kzalloc() error! Can't allocate memory [size %ld:0x%lx] ;[\n",
|
||||
p_db.kernel_stext.p_size+1,p_db.kernel_stext.p_size+1);
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto hash_from_kernel_stext_out;
|
||||
}
|
||||
|
||||
// memset(p_db.kernel_stext_copy.p_addr,0x0,p_db.kernel_stext.p_size+1);
|
||||
*((char *)p_db.kernel_stext_copy.p_addr + p_db.kernel_stext.p_size) = 0x0;
|
||||
memcpy(p_db.kernel_stext_copy.p_addr,p_db.kernel_stext.p_addr,p_db.kernel_stext.p_size);
|
||||
p_db.kernel_stext_copy.p_size = p_db.kernel_stext.p_size;
|
||||
|
||||
p_db.kernel_stext_copy.p_hash = p_super_fast_hash((unsigned char *)p_db.kernel_stext_copy.p_addr,
|
||||
(unsigned int)p_db.kernel_stext_copy.p_size);
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"hash [0x%x] _stext start [0x%lx] size [0x%lx]\n",(int)p_db.kernel_stext.p_hash,
|
||||
(long)p_db.kernel_stext.p_addr,
|
||||
(long)p_db.kernel_stext.p_size);
|
||||
|
||||
hash_from_kernel_stext_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <hash_from_kernel_stext> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int hash_from_kernel_rodata(void) {
|
||||
|
||||
unsigned long p_tmp = 0x0;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <hash_from_kernel_rodata>\n");
|
||||
|
||||
p_db.kernel_rodata.p_addr = (unsigned long *)p_kallsyms_lookup_name("__start_rodata");
|
||||
p_tmp = (unsigned long)p_kallsyms_lookup_name("__end_rodata");
|
||||
|
||||
if (!p_db.kernel_rodata.p_addr || !p_tmp || p_tmp < (unsigned long)p_db.kernel_rodata.p_addr) {
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto hash_from_kernel_rodata_out;
|
||||
}
|
||||
|
||||
p_db.kernel_rodata.p_size = (unsigned long)(p_tmp - (unsigned long)p_db.kernel_rodata.p_addr);
|
||||
|
||||
p_db.kernel_rodata.p_hash = p_super_fast_hash((unsigned char *)p_db.kernel_rodata.p_addr,
|
||||
(unsigned int)p_db.kernel_rodata.p_size);
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"hash [0x%x] _rodata start [0x%lx] size [0x%lx]\n",(int)p_db.kernel_rodata.p_hash,
|
||||
(long)p_db.kernel_rodata.p_addr,
|
||||
(long)p_db.kernel_rodata.p_size);
|
||||
|
||||
hash_from_kernel_rodata_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <hash_from_kernel_rodata> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int hash_from_iommu_table(void) {
|
||||
|
||||
unsigned long p_tmp = 0x0;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <hash_from_iommu_table>\n");
|
||||
|
||||
p_db.kernel_iommu_table.p_addr = (unsigned long *)p_kallsyms_lookup_name("__iommu_table");
|
||||
p_tmp = (unsigned long)p_kallsyms_lookup_name("__iommu_table_end");
|
||||
|
||||
if (!p_db.kernel_iommu_table.p_addr || !p_tmp || p_tmp < (unsigned long)p_db.kernel_iommu_table.p_addr) {
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto hash_from_iommu_table_out;
|
||||
}
|
||||
|
||||
p_db.kernel_iommu_table.p_size = (unsigned long)(p_tmp - (unsigned long)p_db.kernel_iommu_table.p_addr);
|
||||
|
||||
|
||||
#ifdef P_LKRG_IOMMU_HASH_ENABLED
|
||||
p_db.kernel_iommu_table.p_hash = p_super_fast_hash((unsigned char *)p_db.kernel_iommu_table.p_addr,
|
||||
(unsigned int)p_db.kernel_iommu_table.p_size);
|
||||
#else
|
||||
// Static value - might change in normal system...
|
||||
p_db.kernel_iommu_table.p_hash = 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"hash [0x%x] __iommu_table start [0x%lx] size [0x%lx]\n",(int)p_db.kernel_iommu_table.p_hash,
|
||||
(long)p_db.kernel_iommu_table.p_addr,
|
||||
(long)p_db.kernel_iommu_table.p_size);
|
||||
|
||||
hash_from_iommu_table_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <hash_from_iommu_table> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
uint32_t hash_from_CPU_data(p_IDT_MSR_CRx_hash_mem *p_arg) {
|
||||
|
||||
int p_tmp = 0x0;
|
||||
uint32_t p_hash = 0x0;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <hash_from_CPU_data>\n");
|
||||
|
||||
for_each_present_cpu(p_tmp) {
|
||||
if (p_arg[p_tmp].p_cpu_online == P_CPU_ONLINE) {
|
||||
if (cpu_online(p_tmp)) {
|
||||
p_hash ^= p_super_fast_hash((unsigned char *)&p_arg[p_tmp],
|
||||
(unsigned int)sizeof(p_IDT_MSR_CRx_hash_mem));
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"<hash_from_CPU_data> Hash for cpu id %i total_hash[0x%x]\n",p_tmp,p_hash);
|
||||
} else {
|
||||
// WTF?! I should never be here
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"WTF?! DB corrupted?");
|
||||
}
|
||||
} else {
|
||||
// Skip offline CPUs
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"<hash_from_CPU_data> Offline cpu id %i total_hash[0x%x]\n",p_tmp,p_hash);
|
||||
}
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <hash_from_CPU_data>\n");
|
||||
|
||||
return p_hash;
|
||||
}
|
||||
|
||||
|
||||
int p_create_database(void) {
|
||||
|
||||
int p_tmp;
|
||||
// int p_tmp_cpu;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_create_database>\n");
|
||||
|
||||
memset(&p_db,0x0,sizeof(p_hash_database));
|
||||
|
||||
/*
|
||||
* First gather information about CPUs in the system - CRITICAL !!!
|
||||
*/
|
||||
p_get_cpus(&p_db.p_cpu);
|
||||
|
||||
/*
|
||||
* OK, we now know what is the maximum number of supported CPUs
|
||||
* in this kernel, let's allocate data here...
|
||||
*/
|
||||
/*
|
||||
* This is one-shot function not in the time-critical context/section. We can sleep here so
|
||||
* we are allowed to make 'slowpath' memory allocation - don't need to use emergency pools.
|
||||
*
|
||||
* __GFP_NOFAIL flag will always generate slowpath warn because developers
|
||||
* decided to depreciate this flag ;/
|
||||
*/
|
||||
if ( (p_db.p_IDT_MSR_CRx_array = kzalloc(sizeof(p_IDT_MSR_CRx_hash_mem)*p_db.p_cpu.p_nr_cpu_ids,
|
||||
GFP_KERNEL | __GFP_REPEAT)) == NULL) {
|
||||
/*
|
||||
* I should NEVER be here!
|
||||
*/
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CREATING DATABASE: kzalloc() error! Can't allocate memory ;[\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_create_database_out;
|
||||
}
|
||||
// STRONG_DEBUG
|
||||
else {
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_create_database> p_db.p_IDT_MSR_CRx_array[%p] with requested size[%d] "
|
||||
"= sizeof(p_IDT_MSR_CRx_hash_mem)[%d] * p_db.p_cpu.p_nr_cpu_ids[%d]\n",
|
||||
p_db.p_IDT_MSR_CRx_array,(int)(sizeof(p_IDT_MSR_CRx_hash_mem)*p_db.p_cpu.p_nr_cpu_ids),
|
||||
(int)sizeof(p_IDT_MSR_CRx_hash_mem),p_db.p_cpu.p_nr_cpu_ids);
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we have prepared all necessary memory. Let's try X86 specific
|
||||
* function
|
||||
*/
|
||||
|
||||
// p_tmp_cpu = get_cpu();
|
||||
|
||||
/*
|
||||
* Sometime this function has problems and do not run on every requested CPU:
|
||||
* smp_call_function_many(cpu_present_mask, ...);
|
||||
*
|
||||
* that's why we do it manually now:
|
||||
*/
|
||||
for_each_present_cpu(p_tmp) {
|
||||
if (cpu_online(p_tmp)) {
|
||||
// if (p_tmp_cpu != p_tmp) {
|
||||
// p_dump_IDT_MSR_CRx(p_db.p_IDT_MSR_CRx_array);
|
||||
|
||||
/*
|
||||
* There is an undesirable situation in SMP Linux machines when sending
|
||||
* IPI via the smp_call_function_single() API...
|
||||
*
|
||||
* ... more technical details about it can be found here:
|
||||
* *) http://blog.pi3.com.pl/?p=549
|
||||
* *) http://lkml.iu.edu/hypermail/linux/kernel/1609.2/03265.html
|
||||
*/
|
||||
smp_call_function_single(p_tmp,p_dump_IDT_MSR_CRx,p_db.p_IDT_MSR_CRx_array,true);
|
||||
// }
|
||||
} else {
|
||||
p_print_log(P_LKRG_WARN,
|
||||
"!!! WARNING !!! CPU ID:%d is offline !!!\n",p_tmp);
|
||||
// "Let's try to run on it anyway...",p_tmp);
|
||||
// p_dump_IDT_MSR_CRx(p_db.p_IDT_MSR_CRx_array);
|
||||
// smp_call_function_single(p_tmp,p_dump_IDT_MSR_CRx,p_db.p_IDT_MSR_CRx_array,true);
|
||||
}
|
||||
}
|
||||
// put_cpu();
|
||||
// smp_call_function_single(p_tmp_cpu,p_dump_IDT_MSR_CRx,p_db.p_IDT_MSR_CRx_array,true);
|
||||
|
||||
p_db.p_IDT_MSR_CRx_hashes = hash_from_CPU_data(p_db.p_IDT_MSR_CRx_array);
|
||||
|
||||
if (hash_from_ex_table() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CREATING DATABASE ERROR: EXCEPTION TABLE CAN\'T BE FOUND (skipping it)!\n");
|
||||
p_db.kernel_ex_table.p_hash = p_db.kernel_ex_table.p_size = 0x0;
|
||||
p_db.kernel_ex_table.p_addr = NULL;
|
||||
}
|
||||
|
||||
if (hash_from_kernel_stext() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CREATING DATABASE ERROR: HASH FROM _STEXT!\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_create_database_out;
|
||||
}
|
||||
|
||||
if (hash_from_kernel_rodata() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CREATING DATABASE ERROR: _RODATA CAN\'T BE FOUND (skipping it)!\n");
|
||||
p_db.kernel_rodata.p_hash = p_db.kernel_rodata.p_size = 0x0;
|
||||
p_db.kernel_rodata.p_addr = NULL;
|
||||
}
|
||||
|
||||
if (hash_from_iommu_table() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"CREATING DATABASE ERROR: IOMMU TABLE CAN\'T BE FOUND (skipping it)!\n");
|
||||
p_db.kernel_iommu_table.p_hash = p_db.kernel_iommu_table.p_size = 0x0;
|
||||
p_db.kernel_iommu_table.p_addr = NULL;
|
||||
}
|
||||
|
||||
/* We are heavly consuming module list here - take 'module_mutex' */
|
||||
mutex_lock(&module_mutex);
|
||||
|
||||
/*
|
||||
* Memory allocation may fail... let's loop here!
|
||||
*/
|
||||
while(p_kmod_hash(&p_db.p_module_list_nr,&p_db.p_module_list_array,
|
||||
&p_db.p_module_kobj_nr,&p_db.p_module_kobj_array) != P_LKRG_SUCCESS);
|
||||
|
||||
/* Release the 'module_mutex' */
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
p_db.p_module_list_hash = p_super_fast_hash((unsigned char *)p_db.p_module_list_array,
|
||||
(unsigned int)p_db.p_module_list_nr * sizeof(p_module_list_mem));
|
||||
p_db.p_module_kobj_hash = p_super_fast_hash((unsigned char *)p_db.p_module_kobj_array,
|
||||
(unsigned int)p_db.p_module_kobj_nr * sizeof(p_module_kobj_mem));
|
||||
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"p_module_list_hash => [0x%x]\np_module_kobj_hash => [0x%x]\n",
|
||||
p_db.p_module_list_hash,p_db.p_module_kobj_hash);
|
||||
|
||||
p_create_database_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_create_database> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Database module
|
||||
*
|
||||
* Notes:
|
||||
* - Let's create database - calculate hashes
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_DATABASE_H
|
||||
#define P_LKRG_DATABASE_H
|
||||
|
||||
/*
|
||||
* Memory block hash
|
||||
*/
|
||||
typedef struct p_hash_mem_block {
|
||||
|
||||
long *p_addr;
|
||||
unsigned long p_size;
|
||||
uint32_t p_hash;
|
||||
|
||||
} p_hash_mem_block;
|
||||
|
||||
/*
|
||||
* CPU info structure:
|
||||
*
|
||||
* Keep track 'online/possible/present/active' CPUs.
|
||||
* Linux kernel keeps those data in CPU bitmask structure
|
||||
* which is extracet via following function:
|
||||
*
|
||||
* static inline int cpumask_test_cpu(int cpu, const struct cpumask *cpumask)
|
||||
*
|
||||
* That's why all variables have 'int' type
|
||||
*/
|
||||
typedef struct p_cpu_info {
|
||||
|
||||
int online_CPUs; // Might be active (because it's online) but it is NOT
|
||||
// yet, so does NOT execute any task
|
||||
int possible_CPUs; // Physically possible CPUs handled by this kernel
|
||||
int present_CPUs; // Currently availble CPUs, but doesn't need to be used
|
||||
// by kernel at this time. Value is dynamically updated
|
||||
// when CPU is hotplug
|
||||
int active_CPUs; // Currently active CPUs - can execute tasks
|
||||
|
||||
/*
|
||||
* "include/linux/cpumask.h"
|
||||
* ...
|
||||
* 34 #if NR_CPUS == 1
|
||||
* 35 #define nr_cpu_ids 1
|
||||
* 36 #else
|
||||
* 37 extern int nr_cpu_ids;
|
||||
* 38 #endif
|
||||
* ...
|
||||
*/
|
||||
|
||||
int p_nr_cpu_ids; // Should be the same as possible_CPUs
|
||||
|
||||
} p_cpu_info;
|
||||
|
||||
#define P_CPU_OFFLINE 0
|
||||
#define P_CPU_ONLINE 1
|
||||
|
||||
/*
|
||||
* x86/amd64 CPU specific data
|
||||
*/
|
||||
#include "arch/x86/IDT.h"
|
||||
#include "arch/x86/MSR.h"
|
||||
|
||||
/*
|
||||
* Linux Kernel Module's specific structures...
|
||||
*/
|
||||
#include "../kmod/p_kmod.h"
|
||||
|
||||
/*
|
||||
* Main database structure conatining:
|
||||
* - memory hashes
|
||||
* - Critical addresses
|
||||
* - CPU specific information
|
||||
*/
|
||||
typedef struct p_hash_database {
|
||||
|
||||
/*
|
||||
* Information about CPUs in the system - CRITICAL !!!
|
||||
* Should be filled first.
|
||||
*/
|
||||
p_cpu_info p_cpu;
|
||||
|
||||
/*
|
||||
* Pointer to the dynamically allocated array - we don't know
|
||||
* how much memory do we need until we discover how many CPUs
|
||||
* do we have.
|
||||
*
|
||||
* Btw. our procedure must handle hot CPUs plug[in/out] as well !!!
|
||||
*/
|
||||
p_IDT_MSR_CRx_hash_mem *p_IDT_MSR_CRx_array;
|
||||
|
||||
/*
|
||||
* Hash from the all 'p_IDT_MSR_CRx_hash_mem' structures
|
||||
*/
|
||||
uint32_t p_IDT_MSR_CRx_hashes;
|
||||
|
||||
|
||||
/*
|
||||
* Linux Kernel Modules in the system
|
||||
*/
|
||||
unsigned int p_module_list_nr; // Count via walking through the list first
|
||||
unsigned int p_module_kobj_nr; // Count via walking through the KOBJs first
|
||||
|
||||
/*
|
||||
* Linux Kernel Modules integrity
|
||||
*/
|
||||
p_module_list_mem *p_module_list_array;
|
||||
uint32_t p_module_list_hash;
|
||||
p_module_kobj_mem *p_module_kobj_array;
|
||||
uint32_t p_module_kobj_hash;
|
||||
|
||||
|
||||
p_hash_mem_block kernel_stext; // .text
|
||||
p_hash_mem_block kernel_stext_copy; // copy of entire kernel's .text secgment
|
||||
// - needed to deal with *_JMP_LABEL shit ;/
|
||||
p_hash_mem_block kernel_rodata; // .rodata
|
||||
p_hash_mem_block kernel_iommu_table; // IOMMU table
|
||||
p_hash_mem_block kernel_ex_table; // Exception tale
|
||||
|
||||
|
||||
} p_hash_database;
|
||||
|
||||
extern p_hash_database p_db;
|
||||
extern struct notifier_block p_cpu_notifier;
|
||||
|
||||
int hash_from_ex_table(void);
|
||||
int hash_from_kernel_stext(void);
|
||||
int hash_from_kernel_rodata(void);
|
||||
int hash_from_iommu_table(void);
|
||||
|
||||
int p_create_database(void);
|
||||
void p_get_cpus(p_cpu_info *p_arg);
|
||||
int p_cmp_cpus(p_cpu_info *p_arg1, p_cpu_info *p_arg2);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
int p_cpu_callback(struct notifier_block *p_block, unsigned long p_action, void *p_hcpu);
|
||||
#endif
|
||||
int p_cpu_online_action(unsigned int p_cpu);
|
||||
int p_cpu_dead_action(unsigned int p_cpu);
|
||||
uint32_t hash_from_CPU_data(p_IDT_MSR_CRx_hash_mem *p_arg);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Exploit detection main module
|
||||
*
|
||||
* Notes:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 06.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
void p_dump_creds(struct p_cred *p_where, const struct cred *p_from) {
|
||||
|
||||
/* Track process's capabilities */
|
||||
memcpy(&p_where->cap_inheritable, &p_from->cap_inheritable, sizeof(kernel_cap_t));
|
||||
memcpy(&p_where->cap_permitted, &p_from->cap_permitted, sizeof(kernel_cap_t));
|
||||
memcpy(&p_where->cap_effective, &p_from->cap_effective, sizeof(kernel_cap_t));
|
||||
memcpy(&p_where->cap_bset, &p_from->cap_bset, sizeof(kernel_cap_t));
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||
memcpy(&p_where->cap_ambient, &p_from->cap_ambient, sizeof(kernel_cap_t));
|
||||
#endif
|
||||
|
||||
/* Track process's IDs */
|
||||
p_set_uid(&p_where->uid, p_get_uid(&p_from->uid));
|
||||
p_set_gid(&p_where->gid, p_get_gid(&p_from->gid));
|
||||
p_set_uid(&p_where->suid, p_get_uid(&p_from->suid));
|
||||
p_set_gid(&p_where->sgid, p_get_gid(&p_from->sgid));
|
||||
p_set_uid(&p_where->euid, p_get_uid(&p_from->euid));
|
||||
p_set_gid(&p_where->egid, p_get_gid(&p_from->egid));
|
||||
p_set_uid(&p_where->fsuid, p_get_uid(&p_from->fsuid));
|
||||
p_set_gid(&p_where->fsgid, p_get_gid(&p_from->fsgid));
|
||||
|
||||
/* Track process's securebits - TODO: research */
|
||||
p_where->securebits = p_from->securebits;
|
||||
|
||||
/* Track process's critical pointers */
|
||||
p_where->user = p_from->user;
|
||||
p_where->user_ns = p_from->user_ns;
|
||||
|
||||
}
|
||||
|
||||
void p_update_ed_process(struct p_ed_process *p_source, struct task_struct *p_task) {
|
||||
|
||||
/* Track process's metadata */
|
||||
p_source->p_ed_task.p_task = p_task;
|
||||
p_source->p_ed_task.p_pid = p_task->pid;
|
||||
p_source->p_ed_task.p_cred_ptr = p_task->cred;
|
||||
p_source->p_ed_task.p_real_cred_ptr = p_task->real_cred;
|
||||
p_dump_creds(&p_source->p_ed_task.p_cred, p_task->cred);
|
||||
p_dump_creds(&p_source->p_ed_task.p_real_cred, p_task->real_cred);
|
||||
strncpy(p_source->p_ed_task.p_comm, p_task->comm, TASK_COMM_LEN);
|
||||
p_source->p_ed_task.p_comm[TASK_COMM_LEN] = 0x0;
|
||||
|
||||
}
|
||||
|
||||
void p_set_ed_process_on(struct p_ed_process *p_source) {
|
||||
|
||||
p_source->p_ed_task.p_off = 0x0;
|
||||
p_source->p_ed_task.p_off_count = 0x0;
|
||||
|
||||
}
|
||||
|
||||
void p_set_ed_process_off(struct p_ed_process *p_source) {
|
||||
|
||||
p_source->p_ed_task.p_off = 0x1;
|
||||
|
||||
}
|
||||
|
||||
int p_print_task_f(void *p_arg) {
|
||||
|
||||
struct task_struct *p_task = (struct task_struct *)p_arg;
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"%s [%d]\n", p_task->comm, task_pid_nr(p_task));
|
||||
|
||||
return P_LKRG_SUCCESS;
|
||||
}
|
||||
|
||||
int p_dump_task_f(void *p_arg) {
|
||||
|
||||
struct task_struct *p_task = (struct task_struct *)p_arg;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_dump_task_f>\n");
|
||||
|
||||
if ( (p_tmp = p_alloc_ed_pids()) == NULL) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"p_alloc_ed_pids() returned NULL for pid %d :(\n",p_task->pid);
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_dump_task_f_out;
|
||||
}
|
||||
|
||||
p_update_ed_process(p_tmp, p_task);
|
||||
p_set_ed_process_on(p_tmp);
|
||||
|
||||
p_rb_init_ed_pid_node(&p_tmp->p_rb);
|
||||
if (p_rb_add_ed_pid(&p_global_ed_pids_root, p_task->pid, p_tmp)) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"pid => %d, is already inserted!\n",p_task->pid);
|
||||
p_free_ed_pids(p_tmp);
|
||||
p_ret = 0x1;
|
||||
goto p_dump_task_f_out;
|
||||
} else {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"Inserting pid => %d\n", p_task->pid);
|
||||
}
|
||||
|
||||
p_dump_task_f_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_dump_task_f> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int p_remove_task_pid_f(pid_t p_arg) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_remove_task_pid_f>\n");
|
||||
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, p_arg)) == NULL) {
|
||||
// This process is not on the list!
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_remove_task_pid_f_out;
|
||||
}
|
||||
|
||||
p_rb_del_ed_pid(&p_global_ed_pids_root, p_tmp);
|
||||
p_print_log(P_LKRG_INFO, "Removing ED pid => %d\n", p_arg);
|
||||
|
||||
p_remove_task_pid_f_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_remove_task_pid_f> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int p_iterate_processes(int (*p_func)(void *)) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
struct task_struct *p_ptmp, *p_tmp;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_iterate_processes>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
rcu_read_lock();
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
||||
for_each_process_thread(p_ptmp, p_tmp) {
|
||||
#else
|
||||
// tasklist_lock
|
||||
do_each_thread(p_ptmp, p_tmp) {
|
||||
#endif
|
||||
/* do not touch kernel threads or the global init */
|
||||
if (p_tmp->flags & PF_KTHREAD || is_global_init(p_tmp))
|
||||
continue;
|
||||
|
||||
task_lock(p_tmp);
|
||||
if ( (p_ret = p_func(p_tmp)) != 0) {
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"<Exploit Detection> Error[%d] during process[%d |%s] iteration!\n",
|
||||
p_ret, task_pid_nr(p_tmp), p_tmp->comm);
|
||||
}
|
||||
task_unlock(p_tmp);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
||||
}
|
||||
#else
|
||||
// tasklist_unlock
|
||||
} while_each_thread(p_ptmp, p_tmp);
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_iterate_processes> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int p_cmp_creds(struct p_ed_process_task *p_task, struct task_struct *p_current, char p_opt) {
|
||||
|
||||
int p_ret = 0x0;
|
||||
|
||||
/* *UID */
|
||||
if (uid_gt(p_task->p_cred.uid, p_current->cred->uid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different UID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_uid(&p_task->p_cred.uid), p_get_uid(&p_current->cred->uid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (uid_gt(p_task->p_cred.euid, p_current->cred->euid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different EUID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_uid(&p_task->p_cred.euid), p_get_uid(&p_current->cred->euid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (uid_gt(p_task->p_cred.suid, p_current->cred->suid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different SUID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_uid(&p_task->p_cred.suid), p_get_uid(&p_current->cred->suid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (uid_gt(p_task->p_cred.fsuid, p_current->cred->fsuid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different FSUID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_uid(&p_task->p_cred.fsuid), p_get_uid(&p_current->cred->fsuid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
/* *GID */
|
||||
if (gid_gt(p_task->p_cred.gid, p_current->cred->gid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different GID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_gid(&p_task->p_cred.gid), p_get_gid(&p_current->cred->gid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (gid_gt(p_task->p_cred.egid, p_current->cred->egid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different EGID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_gid(&p_task->p_cred.egid), p_get_gid(&p_current->cred->egid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (gid_gt(p_task->p_cred.sgid, p_current->cred->sgid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different SGID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_gid(&p_task->p_cred.sgid), p_get_gid(&p_current->cred->sgid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (gid_gt(p_task->p_cred.fsgid, p_current->cred->fsgid)) {
|
||||
if (p_opt) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different FSGID! [%d vs %d :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_get_gid(&p_task->p_cred.fsgid), p_get_gid(&p_current->cred->fsgid));
|
||||
}
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int p_cmp_tasks(struct p_ed_process *p_orig, struct task_struct *p_current) {
|
||||
|
||||
int p_ret = 0x0;
|
||||
|
||||
if (p_orig->p_ed_task.p_task != p_current) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> process[%d | %s] has different 'task_struct\' pointer [0x%p vs 0x%p] :(\n",
|
||||
task_pid_nr(p_current), p_current->comm,p_orig->p_ed_task.p_task,p_current);
|
||||
p_ret++;
|
||||
}
|
||||
|
||||
if (p_orig->p_ed_task.p_off) {
|
||||
p_orig->p_ed_task.p_off_count++;
|
||||
if (p_orig->p_ed_task.p_off_count > 6) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Detected data corruption attack! "
|
||||
"process[%d | %s] has been disabled form checking %d times! :(\n",
|
||||
task_pid_nr(p_current), p_current->comm, p_orig->p_ed_task.p_off_count);
|
||||
p_ret++;
|
||||
} else
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
if (p_orig->p_ed_task.p_cred_ptr != p_current->cred) {
|
||||
if (p_cmp_creds(&p_orig->p_ed_task, p_current, 0x0)) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Detected pointer swapping attack!"
|
||||
"process[%d | %s] has different 'cred\' pointer [0x%p vs 0x%p] :(\n",
|
||||
task_pid_nr(p_current), p_current->comm,p_orig->p_ed_task.p_cred_ptr,p_current->cred);
|
||||
p_ret++;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_orig->p_ed_task.p_real_cred_ptr != p_current->real_cred) {
|
||||
if (p_cmp_creds(&p_orig->p_ed_task, p_current, 0x0)) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Detected pointer swapping attack!"
|
||||
"process[%d | %s] has different 'real_cred\' pointer [0x%p vs 0x%p] :(\n",
|
||||
task_pid_nr(p_current), p_current->comm,p_orig->p_ed_task.p_real_cred_ptr,p_current->real_cred);
|
||||
p_ret++;
|
||||
}
|
||||
}
|
||||
|
||||
p_ret += p_cmp_creds(&p_orig->p_ed_task, p_current, 0x1);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int p_validate_task_f(void *p_arg) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
struct p_ed_process *p_tmp;
|
||||
struct task_struct *p_task = (struct task_struct *)p_arg;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_validate_task_f>\n");
|
||||
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(p_task))) == NULL) {
|
||||
// This process is not on the list!
|
||||
if (p_task->state != TASK_DEAD) {
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
p_print_log(P_LKRG_INFO,
|
||||
"<Exploit Detection> Can\'t find process[%d |%s] in internal tracking list!\n",
|
||||
task_pid_nr(p_task), p_task->comm);
|
||||
}
|
||||
goto p_validate_task_out;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
if (p_cmp_tasks(p_tmp, p_task)) {
|
||||
// kill this process!
|
||||
p_ed_kill_task_by_task(p_task);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
p_validate_task_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_validate_task_f> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
int p_exploit_detection_init(void) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_exploit_detection_init>\n");
|
||||
|
||||
if (p_init_rb_ed_pids()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t initialize ED pids cache and red-black tree :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_out;
|
||||
}
|
||||
|
||||
p_iterate_processes(p_dump_task_f);
|
||||
|
||||
if (p_install_sys_execve_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook execve syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_do_fork_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook fork syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_do_exit_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook exit syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setuid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setuid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setreuid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setreuid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setresuid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setresuid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setfsuid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setfsuid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setgid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setgid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setregid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setregid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setresgid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setresgid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setfsgid_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setfsgid syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_setgroups_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook setgroups syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_do_init_module_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook do_init_module function :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_sys_delete_module_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook delete_module syscall :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
if (p_install_may_open_hook()) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"ERROR: Can\'t hook may_open function :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_exploit_detection_init_err;
|
||||
}
|
||||
|
||||
goto p_exploit_detection_init_out;
|
||||
|
||||
p_exploit_detection_init_err:
|
||||
|
||||
p_exploit_detection_exit();
|
||||
|
||||
p_exploit_detection_init_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_exploit_detection_init> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_exploit_detection_exit(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_exploit_detection_exit>\n");
|
||||
|
||||
p_uninstall_sys_execve_hook();
|
||||
p_uninstall_do_fork_hook();
|
||||
p_uninstall_do_exit_hook();
|
||||
p_uninstall_sys_setuid_hook();
|
||||
p_uninstall_sys_setreuid_hook();
|
||||
p_uninstall_sys_setresuid_hook();
|
||||
p_uninstall_sys_setfsuid_hook();
|
||||
p_uninstall_sys_setgid_hook();
|
||||
p_uninstall_sys_setregid_hook();
|
||||
p_uninstall_sys_setresgid_hook();
|
||||
p_uninstall_sys_setfsgid_hook();
|
||||
p_uninstall_sys_setgroups_hook();
|
||||
p_uninstall_do_init_module_hook();
|
||||
p_uninstall_sys_delete_module_hook();
|
||||
p_uninstall_may_open_hook();
|
||||
|
||||
/* Before deleting cache i should clean each entry! */
|
||||
p_delete_rb_ed_pids();
|
||||
p_print_log(P_LKRG_INFO, "kmem_cache \"p_ed_pids\" destroyed!\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_exploit_detection_exit>\n");
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Exploit detection main module
|
||||
*
|
||||
* Notes:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 06.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_EXPLOIT_DETECTION_MAIN_H
|
||||
#define P_EXPLOIT_DETECTION_MAIN_H
|
||||
|
||||
struct p_cred {
|
||||
|
||||
kuid_t uid; /* real UID of the task */
|
||||
kgid_t gid; /* real GID of the task */
|
||||
kuid_t suid; /* saved UID of the task */
|
||||
kgid_t sgid; /* saved GID of the task */
|
||||
kuid_t euid; /* effective UID of the task */
|
||||
kgid_t egid; /* effective GID of the task */
|
||||
kuid_t fsuid; /* UID for VFS ops */
|
||||
kgid_t fsgid; /* GID for VFS ops */
|
||||
unsigned securebits; /* SUID-less security management */
|
||||
kernel_cap_t cap_inheritable; /* caps our children can inherit */
|
||||
kernel_cap_t cap_permitted; /* caps we're permitted */
|
||||
kernel_cap_t cap_effective; /* caps we can actually use */
|
||||
kernel_cap_t cap_bset; /* capability bounding set */
|
||||
kernel_cap_t cap_ambient; /* Ambient capability set */
|
||||
struct user_struct *user; /* real user ID subscription */
|
||||
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
|
||||
|
||||
};
|
||||
|
||||
struct p_ed_process_task {
|
||||
|
||||
struct task_struct *p_task;
|
||||
pid_t p_pid;
|
||||
char p_comm[TASK_COMM_LEN+1];
|
||||
const struct cred *p_cred_ptr;
|
||||
const struct cred *p_real_cred_ptr;
|
||||
struct p_cred p_cred;
|
||||
struct p_cred p_real_cred;
|
||||
char p_off;
|
||||
unsigned int p_off_count;
|
||||
|
||||
};
|
||||
|
||||
#include "p_rb_ed_trees/p_rb_ed_pids/p_rb_ed_pids_tree.h"
|
||||
#include "syscalls/p_sys_execve/p_sys_execve.h"
|
||||
#include "syscalls/p_do_fork/p_do_fork.h"
|
||||
#include "syscalls/p_do_exit/p_do_exit.h"
|
||||
#include "syscalls/p_sys_setuid/p_sys_setuid.h"
|
||||
#include "syscalls/p_sys_setreuid/p_sys_setreuid.h"
|
||||
#include "syscalls/p_sys_setresuid/p_sys_setresuid.h"
|
||||
#include "syscalls/p_sys_setfsuid/p_sys_setfsuid.h"
|
||||
#include "syscalls/p_sys_setgid/p_sys_setgid.h"
|
||||
#include "syscalls/p_sys_setregid/p_sys_setregid.h"
|
||||
#include "syscalls/p_sys_setresgid/p_sys_setresgid.h"
|
||||
#include "syscalls/p_sys_setfsgid/p_sys_setfsgid.h"
|
||||
#include "syscalls/p_sys_setgroups/p_sys_setgroups.h"
|
||||
#include "syscalls/p_do_init_module/p_do_init_module.h"
|
||||
#include "syscalls/p_sys_delete_module/p_sys_delete_module.h"
|
||||
#include "syscalls/p_may_open/p_may_open.h"
|
||||
|
||||
|
||||
static inline int p_ed_kill_task_by_task(struct task_struct *p_task) {
|
||||
|
||||
int p_sig = SIGKILL;
|
||||
struct siginfo p_info;
|
||||
|
||||
memset(&p_info, 0, sizeof(struct siginfo));
|
||||
p_info.si_signo = p_sig;
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Trying to kill process[%s | %d]!\n",
|
||||
p_task->comm,task_pid_nr(current));
|
||||
|
||||
return send_sig_info(p_sig, &p_info, p_task);
|
||||
|
||||
// do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p_task, true);
|
||||
|
||||
}
|
||||
|
||||
static inline int p_ed_kill_task_by_pid(pid_t p_pid) {
|
||||
|
||||
struct task_struct *p_task = pid_task(find_vpid(p_pid), PIDTYPE_PID);
|
||||
int p_sig = SIGKILL;
|
||||
struct siginfo p_info;
|
||||
|
||||
memset(&p_info, 0, sizeof(struct siginfo));
|
||||
p_info.si_signo = p_sig;
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Trying to kill process[%s | %d]!\n",
|
||||
p_task->comm,task_pid_nr(current));
|
||||
|
||||
return send_sig_info(p_sig, &p_info, p_task);
|
||||
|
||||
// do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p_task, true);
|
||||
|
||||
}
|
||||
|
||||
int p_iterate_processes(int (*p_func)(void *));
|
||||
int p_print_task_f(void *p_arg);
|
||||
int p_dump_task_f(void *p_arg);
|
||||
int p_remove_task_pid_f(pid_t p_arg);
|
||||
|
||||
void p_dump_creds(struct p_cred *p_where, const struct cred *p_from);
|
||||
void p_update_ed_process(struct p_ed_process *p_source, struct task_struct *p_task);
|
||||
void p_set_ed_process_on(struct p_ed_process *p_source);
|
||||
void p_set_ed_process_off(struct p_ed_process *p_source);
|
||||
|
||||
int p_validate_task_f(void *p_arg);
|
||||
|
||||
int p_exploit_detection_init(void);
|
||||
void p_exploit_detection_exit(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Red-black tree for keeping track user-mode process pid structure
|
||||
*
|
||||
* Notes:
|
||||
* - Make sence with own kmem_cache_* allocation
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 07.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
struct kmem_cache *p_ed_pids_cache = NULL;
|
||||
struct rb_root p_global_ed_pids_root = RB_ROOT;
|
||||
|
||||
DEFINE_SPINLOCK(p_rb_ed_pids_lock);
|
||||
|
||||
struct p_ed_process *p_rb_find_ed_pid(struct rb_root *p_root, pid_t p_arg) {
|
||||
|
||||
struct rb_node *p_node = p_root->rb_node;
|
||||
struct p_ed_process *p_struct = NULL;
|
||||
struct p_ed_process *p_ret = NULL;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_rb_find_ed_pid>\n");
|
||||
|
||||
// spin_lock(&p_rb_ed_pids_lock);
|
||||
|
||||
while(p_node) {
|
||||
p_struct = rb_entry(p_node, struct p_ed_process, p_rb);
|
||||
|
||||
if (p_arg < p_struct->p_ed_task.p_pid) {
|
||||
p_node = p_node->rb_left;
|
||||
} else if (p_arg > p_struct->p_ed_task.p_pid) {
|
||||
p_node = p_node->rb_right;
|
||||
} else {
|
||||
p_ret = p_struct;
|
||||
goto p_rb_find_ed_pid_out;
|
||||
}
|
||||
}
|
||||
|
||||
p_rb_find_ed_pid_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_rb_find_ed_pid> (p_ret => 0x%p)\n",p_ret);
|
||||
|
||||
// spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
struct p_ed_process *p_rb_add_ed_pid(struct rb_root *p_root, pid_t p_arg, struct p_ed_process *p_source) {
|
||||
|
||||
struct rb_node **p_node = &p_root->rb_node;
|
||||
struct rb_node *p_parent = NULL;
|
||||
struct p_ed_process *p_struct;
|
||||
struct p_ed_process *p_ret = NULL;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_rb_add_ed_pid>\n");
|
||||
|
||||
while(*p_node) {
|
||||
p_parent = *p_node;
|
||||
p_struct = rb_entry(p_parent, struct p_ed_process, p_rb);
|
||||
|
||||
if (p_arg < p_struct->p_ed_task.p_pid) {
|
||||
p_node = &(*p_node)->rb_left;
|
||||
} else if (p_arg > p_struct->p_ed_task.p_pid) {
|
||||
p_node = &(*p_node)->rb_right;
|
||||
} else {
|
||||
p_ret = p_struct;
|
||||
goto p_rb_add_ed_pid_out;
|
||||
}
|
||||
|
||||
}
|
||||
rb_link_node(&p_source->p_rb, p_parent, p_node); // Insert this new node as a red leaf
|
||||
rb_insert_color(&p_source->p_rb, p_root); // Rebalance the tree, finish inserting
|
||||
|
||||
p_rb_add_ed_pid_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_rb_add_ed_pid> (p_ret => 0x%p)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_rb_del_ed_pid(struct rb_root *p_root, struct p_ed_process *p_source) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_rb_del_ed_pid>\n");
|
||||
|
||||
rb_erase(&p_source->p_rb, p_root); // Erase the node
|
||||
p_free_ed_pids(p_source); // Free the memory
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_rb_del_ed_pid>\n");
|
||||
}
|
||||
|
||||
static void p_ed_pids_cache_init(void *p_arg) {
|
||||
|
||||
struct p_ed_process *p_struct = p_arg;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_ed_pids_cache_init>\n");
|
||||
|
||||
memset(p_struct, 0x0, sizeof(struct p_ed_process));
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_ed_pids_cache_init>\n");
|
||||
}
|
||||
|
||||
int p_init_rb_ed_pids(void) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_init_rb_ed_pids>\n");
|
||||
|
||||
if ( (p_ed_pids_cache = kmem_cache_create("p_ed_pids", sizeof(struct p_ed_process),
|
||||
0x0, SLAB_HWCACHE_ALIGN, p_ed_pids_cache_init)) == NULL) {
|
||||
p_print_log(P_LKRG_ERR, "kmem_cache_create() for ED PIDs error! :(\n");
|
||||
p_ret = -ENOMEM;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_init_rb_ed_pids> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
void p_delete_rb_ed_pids(void) {
|
||||
|
||||
struct rb_node *p_node;
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_delete_rb_ed_pids>\n");
|
||||
|
||||
if (p_ed_pids_cache) {
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
for (p_node = rb_first(&p_global_ed_pids_root); p_node; p_node = rb_next(p_node)) {
|
||||
p_tmp = rb_entry(p_node, struct p_ed_process, p_rb);
|
||||
p_print_log(P_LKRG_INFO, "Deleting ED PID => %d\n",p_tmp->p_ed_task.p_pid);
|
||||
p_free_ed_pids(p_tmp);
|
||||
}
|
||||
kmem_cache_destroy(p_ed_pids_cache);
|
||||
p_ed_pids_cache = NULL;
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_delete_rb_ed_pids>\n");
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Red-black tree for keeping track user-mode process pid structure
|
||||
*
|
||||
* Notes:
|
||||
* - Make sence with own kmem_cache_* allocation
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 07.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_RB_TREE_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_RB_TREE_H
|
||||
|
||||
#define p_alloc_ed_pids() kmem_cache_alloc(p_ed_pids_cache, GFP_ATOMIC)
|
||||
#define p_free_ed_pids(name) kmem_cache_free(p_ed_pids_cache, (void *)(name))
|
||||
|
||||
//#ifdef P_LKRG_DEBUG
|
||||
#define P_DUMP_RB_ED_PIDS_TREE \
|
||||
do { \
|
||||
struct rb_node *p_node; \
|
||||
\
|
||||
for (p_node = rb_first(&p_global_ed_pids_root); p_node; p_node = rb_next(p_node)) \
|
||||
/* p_debug_log(P_LKRG_DBG, */ \
|
||||
p_print_log(P_LKRG_CRIT, "<%s> pid[%d] [uid[%d] gid[%d] ruid[%d] rgid[%d]\n", \
|
||||
rb_entry(p_node, struct p_ed_process, p_rb)->p_ed_task.p_comm, \
|
||||
rb_entry(p_node, struct p_ed_process, p_rb)->p_ed_task.p_pid, \
|
||||
p_get_uid(&rb_entry(p_node, struct p_ed_process, p_rb)->p_ed_task.p_cred.uid), \
|
||||
p_get_gid(&rb_entry(p_node, struct p_ed_process, p_rb)->p_ed_task.p_cred.gid), \
|
||||
p_get_uid(&rb_entry(p_node, struct p_ed_process, p_rb)->p_ed_task.p_real_cred.uid), \
|
||||
p_get_gid(&rb_entry(p_node, struct p_ed_process, p_rb)->p_ed_task.p_real_cred.gid) \
|
||||
); \
|
||||
} while(0);
|
||||
//#endif
|
||||
|
||||
|
||||
struct p_ed_process {
|
||||
|
||||
struct rb_node p_rb;
|
||||
struct p_ed_process_task p_ed_task;
|
||||
/* ... add other driver-specific fields */
|
||||
|
||||
};
|
||||
|
||||
extern struct kmem_cache *p_ed_pids_cache;
|
||||
extern struct rb_root p_global_ed_pids_root;
|
||||
extern spinlock_t p_rb_ed_pids_lock;
|
||||
|
||||
|
||||
static inline void p_rb_init_ed_pid_node(struct rb_node *rb) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_rb_init_ed_pid_node>\n");
|
||||
|
||||
rb->__rb_parent_color = 0;
|
||||
rb->rb_right = NULL;
|
||||
rb->rb_left = NULL;
|
||||
RB_CLEAR_NODE(rb);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_rb_init_ed_pid_node>\n");
|
||||
}
|
||||
|
||||
struct p_ed_process *p_rb_find_ed_pid(struct rb_root *p_root, pid_t p_arg);
|
||||
struct p_ed_process *p_rb_add_ed_pid(struct rb_root *p_root, pid_t p_arg, struct p_ed_process *p_source);
|
||||
void p_rb_del_ed_pid(struct rb_root *p_root, struct p_ed_process *p_source);
|
||||
int p_init_rb_ed_pids(void);
|
||||
void p_delete_rb_ed_pids(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept exit syscall
|
||||
*
|
||||
* Notes:
|
||||
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
|
||||
* When process dies/exists we need to update RB tree.
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 18.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_do_exit_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_do_exit_kretprobe = {
|
||||
.kp.symbol_name = "do_exit",
|
||||
.handler = p_do_exit_ret,
|
||||
.entry_handler = p_do_exit_entry,
|
||||
.data_size = sizeof(struct p_do_exit_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_do_exit_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_exit_entry>\n");
|
||||
p_debug_kprobe_log(
|
||||
"p_do_exit_entry: comm[%s] Pid:%d\n",current->comm,current->pid);
|
||||
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
if (p_remove_task_pid_f(task_pid_nr(current)))
|
||||
;// DEBUG: p_print_log(P_LKRG_CRIT, "Can't remove ED pid (is not on the list) => %d [%s]\n",task_pid_nr(current),current->comm);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_exit_entry>\n");
|
||||
|
||||
/* A dump_stack() here will give a stack backtrace */
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_do_exit_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_exit_ret>\n");
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_exit_ret>\n");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_do_exit_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_do_exit_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_do_exit_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_do_exit_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_do_exit_kretprobe.kp.symbol_name, p_do_exit_kretprobe.kp.addr);
|
||||
p_do_exit_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_do_exit_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_do_exit_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_do_exit_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_do_exit_hook>\n");
|
||||
|
||||
if (!p_do_exit_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_do_exit_kretprobe.kp.symbol_name, p_do_exit_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_do_exit_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_do_exit_kretprobe.kp.symbol_name, p_do_exit_kretprobe.kp.addr);
|
||||
p_do_exit_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_do_exit_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept exit syscall
|
||||
*
|
||||
* Notes:
|
||||
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
|
||||
* When process dies/exists we need to update RB tree.
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 18.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_DO_EXIT_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_DO_EXIT_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_do_exit_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_do_exit_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_do_exit_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_do_exit_hook(void);
|
||||
void p_uninstall_do_exit_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept fork syscall
|
||||
*
|
||||
* Notes:
|
||||
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
|
||||
* When process forks, child must be tracked as well! We need to update RB tree.
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 18.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_do_fork_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_do_fork_kretprobe = {
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
|
||||
.kp.symbol_name = "do_fork",
|
||||
#else
|
||||
.kp.symbol_name = "_do_fork",
|
||||
#endif
|
||||
.handler = p_do_fork_ret,
|
||||
.entry_handler = p_do_fork_entry,
|
||||
.data_size = sizeof(struct p_do_fork_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_do_fork_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
/* A dump_stack() here will give a stack backtrace */
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_do_fork_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct task_struct *p_task = p_regs->ax ? pid_task(find_vpid(p_regs->ax), PIDTYPE_PID) : NULL;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_fork_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Fork returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
|
||||
/* do not touch kernel threads or the global init */
|
||||
if (p_task) {
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(p_task);
|
||||
if (!(p_task->flags & PF_KTHREAD || is_global_init(p_task))) {
|
||||
int p_ret;
|
||||
|
||||
if ( (p_ret = p_dump_task_f(p_task) !=0)) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Error[%d] when trying to add process[%d |%s] for tracking!\n",
|
||||
p_ret, task_pid_nr(p_task), p_task->comm);
|
||||
}
|
||||
}
|
||||
task_unlock(p_task);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
}
|
||||
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_do_fork_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_do_fork_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_do_fork_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_do_fork_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_do_fork_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_do_fork_kretprobe.kp.symbol_name, p_do_fork_kretprobe.kp.addr);
|
||||
p_do_fork_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_do_fork_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_do_fork_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_do_fork_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_do_fork_hook>\n");
|
||||
|
||||
if (!p_do_fork_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_do_fork_kretprobe.kp.symbol_name, p_do_fork_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_do_fork_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_do_fork_kretprobe.kp.symbol_name, p_do_fork_kretprobe.kp.addr);
|
||||
p_do_fork_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_do_fork_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept fork syscall
|
||||
*
|
||||
* Notes:
|
||||
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
|
||||
* When process forks, child must be tracked as well! We need to update RB tree.
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 18.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_DO_FORK_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_DO_FORK_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_do_fork_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_do_fork_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_do_fork_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_do_fork_hook(void);
|
||||
void p_uninstall_do_fork_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept do_init_module function called from the syscalls:
|
||||
* *) init_module
|
||||
* *) finit_module
|
||||
*
|
||||
* Notes:
|
||||
* - Enforce Exploit Detection validation
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 04.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_do_init_module_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_do_init_module_kretprobe = {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
|
||||
.kp.symbol_name = "do_init_module",
|
||||
#else
|
||||
.kp.symbol_name = "sys_init_module",
|
||||
#endif
|
||||
.handler = p_do_init_module_ret,
|
||||
.entry_handler = p_do_init_module_entry,
|
||||
.data_size = sizeof(struct p_do_init_module_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_do_init_module_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_init_module_entry>\n");
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
if (!capable(CAP_SYS_MODULE)) {
|
||||
struct module *p_tmp_mod = (struct module *)p_regs->di;
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Process[%s | %d] is trying to load a kernel module[%s] "
|
||||
"but does NOT have appropiate permissions! Blocking...\n",
|
||||
current->comm,task_pid_nr(current),p_tmp_mod->name);
|
||||
|
||||
p_tmp_mod->init = p_block_always;
|
||||
// kill this process!
|
||||
p_ed_kill_task_by_task(current);
|
||||
}
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_do_init_module_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_do_init_module_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_do_init_module_ret>\n");
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
if (!capable(CAP_SYS_MODULE)) {
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Process[%s | %d] loaded kernel module but does NOT have "
|
||||
"appropiate permissions! Killing...\n",
|
||||
current->comm,task_pid_nr(current));
|
||||
|
||||
// kill this process!
|
||||
p_ed_kill_task_by_task(current);
|
||||
}
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_do_init_module_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_do_init_module_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_do_init_module_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_do_init_module_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_do_init_module_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_do_init_module_kretprobe.kp.symbol_name, p_do_init_module_kretprobe.kp.addr);
|
||||
p_do_init_module_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_do_init_module_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_do_init_module_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_do_init_module_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_do_init_module_hook>\n");
|
||||
|
||||
if (!p_do_init_module_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_do_init_module_kretprobe.kp.symbol_name, p_do_init_module_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_do_init_module_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_do_init_module_kretprobe.kp.symbol_name, p_do_init_module_kretprobe.kp.addr);
|
||||
p_do_init_module_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_do_init_module_hook>\n");
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept do_init_module function called from the syscalls:
|
||||
* *) init_module
|
||||
* *) finit_module
|
||||
*
|
||||
* Notes:
|
||||
* - Enforce Exploit Detection validation
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 04.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_DO_INIT_MODULE_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_DO_INIT_MODULE_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_do_init_module_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_do_init_module_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_do_init_module_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_do_init_module_hook(void);
|
||||
void p_uninstall_do_init_module_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept 'may_open' function
|
||||
*
|
||||
* Notes:
|
||||
* - Enforce Exploit Detection validation
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 04.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_may_open_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_may_open_kretprobe = {
|
||||
.kp.symbol_name = "may_open",
|
||||
.handler = p_may_open_ret,
|
||||
.entry_handler = p_may_open_entry,
|
||||
.data_size = sizeof(struct p_may_open_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
/*
|
||||
* x86-64 syscall ABI:
|
||||
* *rax - syscall_number
|
||||
* rdi - 1st argument
|
||||
* rsi - 2nd argument
|
||||
* rdx - 3rd argument
|
||||
* rcx - 4rd argument
|
||||
*
|
||||
* r8 - probably 5th one
|
||||
* r9 - probably 5th one
|
||||
*/
|
||||
|
||||
int p_may_open_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_may_open_entry>\n");
|
||||
p_debug_kprobe_log(
|
||||
"p_may_open_entry: comm[%s] Pid:%d => Arguments: "
|
||||
"[path:0x%lx acc_mode:0x%lx flags:0x%lx]\n",
|
||||
current->comm,current->pid,p_regs->di,p_regs->si,p_regs->dx);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_may_open_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_may_open_ret(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_may_open_ret>\n");
|
||||
|
||||
// p_iterate_processes(p_validate_task_f);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_may_open_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_may_open_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_may_open_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_may_open_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_may_open_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_may_open_kretprobe.kp.symbol_name, p_may_open_kretprobe.kp.addr);
|
||||
p_may_open_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_may_open_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_may_open_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_may_open_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_may_open_hook>\n");
|
||||
|
||||
if (!p_may_open_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_may_open_kretprobe.kp.symbol_name, p_may_open_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_may_open_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_may_open_kretprobe.kp.symbol_name, p_may_open_kretprobe.kp.addr);
|
||||
p_may_open_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_may_open_hook>\n");
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept 'may_open' function
|
||||
*
|
||||
* Notes:
|
||||
* - Enforce Exploit Detection validation
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 04.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_PROTECTED_FILE_MAY_OPEN_H
|
||||
#define P_LKRG_PROTECTED_FILE_MAY_OPEN_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_may_open_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_may_open_ret(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_may_open_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_may_open_hook(void);
|
||||
void p_uninstall_may_open_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept delete_module syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Enforce Exploit Detection validation
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 04.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_delete_module_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_delete_module_kretprobe = {
|
||||
.kp.symbol_name = "sys_delete_module",
|
||||
.handler = p_sys_delete_module_ret,
|
||||
.entry_handler = p_sys_delete_module_entry,
|
||||
.data_size = sizeof(struct p_sys_delete_module_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_delete_module_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_delete_module_entry>\n");
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
if (!capable(CAP_SYS_MODULE)) {
|
||||
char *p_tmp_name = (char *)p_regs->di;
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Process[%s | %d] is trying to remove kernel module[%s] "
|
||||
"but does NOT have appropiate permissions! Killing...\n",
|
||||
current->comm, task_pid_nr(current), p_tmp_name);
|
||||
|
||||
p_regs->di = -1;
|
||||
p_regs->si = -1;
|
||||
|
||||
// kill this process!
|
||||
p_ed_kill_task_by_task(current);
|
||||
}
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_delete_module_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_delete_module_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_delete_module_ret>\n");
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
if (!capable(CAP_SYS_MODULE)) {
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"<Exploit Detection> Process[%s | %d] removed kernel module but does NOT have "
|
||||
"appropiate permissions! Killing...\n",
|
||||
current->comm, task_pid_nr(current));
|
||||
|
||||
// kill this process!
|
||||
p_ed_kill_task_by_task(current);
|
||||
}
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_delete_module_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_delete_module_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_delete_module_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_delete_module_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_delete_module_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_delete_module_kretprobe.kp.symbol_name, p_sys_delete_module_kretprobe.kp.addr);
|
||||
p_sys_delete_module_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_delete_module_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_delete_module_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_delete_module_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_delete_module_hook>\n");
|
||||
|
||||
if (!p_sys_delete_module_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_delete_module_kretprobe.kp.symbol_name, p_sys_delete_module_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_delete_module_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_delete_module_kretprobe.kp.symbol_name, p_sys_delete_module_kretprobe.kp.addr);
|
||||
p_sys_delete_module_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_delete_module_hook>\n");
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept delete_module syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Enforce Exploit Detection validation
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 04.X.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_DELETE_MODULE_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_DELETE_MODULE_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_delete_module_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_delete_module_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_delete_module_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_delete_module_hook(void);
|
||||
void p_uninstall_sys_delete_module_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept execve syscall
|
||||
*
|
||||
* Notes:
|
||||
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
|
||||
* When process calls execve, we need to update RB tree.
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 18.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_execve_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_execve_kretprobe = {
|
||||
.kp.symbol_name = "sys_execve",
|
||||
.handler = p_sys_execve_ret,
|
||||
.entry_handler = p_sys_execve_entry,
|
||||
.data_size = sizeof(struct p_sys_execve_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
struct inode *p_get_inode_from_task(struct task_struct *p_arg) {
|
||||
|
||||
struct mm_struct *p_mm;
|
||||
struct inode *p_inode = NULL;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_get_inode_from_task>\n");
|
||||
|
||||
if (!p_arg) {
|
||||
goto p_get_inode_from_task_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from the context of newly created
|
||||
* Process which is intercepted by our *probes. This means
|
||||
* Process did not take control yet. Before we finish our work
|
||||
* Nothing bad should happened in context of parsing mm_struct.
|
||||
* For this specific operation (reading pointer to exe_file)
|
||||
* It is safe to not use read lock. Process can't die before it
|
||||
* is not even taken control.
|
||||
* Additionally, we are under IRQ disabled context and it is
|
||||
* Not safe to take any mutex/semaphore since we can be forced
|
||||
* to sleep.
|
||||
* Current implementation works well!
|
||||
*/
|
||||
// down_read(&p_arg->mm->mmap_sem);
|
||||
|
||||
p_mm = p_arg->mm;
|
||||
if (p_mm->exe_file) {
|
||||
p_inode = p_mm->exe_file->f_inode;
|
||||
}
|
||||
|
||||
// up_read(&p_arg->mm->mmap_sem);
|
||||
|
||||
|
||||
p_get_inode_from_task_out:
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_get_inode_from_task> (p_inode => 0x%p)\n",p_inode);
|
||||
|
||||
return p_inode;
|
||||
}
|
||||
|
||||
int p_sys_execve_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_execve_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct inode *p_inode;
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_execve_ret>\n");
|
||||
|
||||
p_inode = p_get_inode_from_task(current);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"p_sys_execve_ret: returned value => %ld comm[%s] Pid:%d inode[%ld]\n",
|
||||
p_regs->ax,current->comm,current->pid,p_inode->i_ino);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_execve_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_execve_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_execve_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_execve_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_uninstall_sys_execve_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_execve_kretprobe.kp.symbol_name, p_sys_execve_kretprobe.kp.addr);
|
||||
p_sys_execve_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_uninstall_sys_execve_hook_out:
|
||||
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_execve_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_execve_hook(void) {
|
||||
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_execve_hook>\n");
|
||||
|
||||
if (!p_sys_execve_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_execve_kretprobe.kp.symbol_name ,p_sys_execve_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_execve_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_execve_kretprobe.kp.symbol_name ,p_sys_execve_kretprobe.kp.addr);
|
||||
p_sys_execve_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_execve_hook>\n");
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept execve syscall
|
||||
*
|
||||
* Notes:
|
||||
* - We are maintianing Red-Black tree of pid's for Exploit Detection feature.
|
||||
* When process calls execve, we need to update RB tree.
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 18.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_EXECVE_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_EXECVE_H
|
||||
|
||||
#define P_MAX_PATH PATH_MAX + 0x20 /* For weirdos used by d_path */
|
||||
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_execve_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
struct inode *p_get_inode_from_task(struct task_struct *p_arg);
|
||||
|
||||
int p_sys_execve_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_execve_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_execve_hook(void);
|
||||
void p_uninstall_sys_execve_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setfsgid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setfsgid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setfsgid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setfsgid",
|
||||
.handler = p_sys_setfsgid_ret,
|
||||
.entry_handler = p_sys_setfsgid_entry,
|
||||
.data_size = sizeof(struct p_sys_setfsgid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setfsgid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setfsgid_entry>\n");
|
||||
|
||||
/*
|
||||
* This is special case, since we can NOT identify when syscall fail or succeed,
|
||||
* we must verify process list before and after the syscall
|
||||
*/
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setfsgid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setfsgid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setfsgid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setfsgid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
// if (!p_regs->ax) {
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
|
||||
p_update_ed_process(p_tmp, current);
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
// }
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setfsgid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setfsgid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setfsgid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setfsgid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setfsgid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setfsgid_kretprobe.kp.symbol_name, p_sys_setfsgid_kretprobe.kp.addr);
|
||||
p_sys_setfsgid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setfsgid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setfsgid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setfsgid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setfsgid_hook>\n");
|
||||
|
||||
if (!p_sys_setfsgid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setfsgid_kretprobe.kp.symbol_name, p_sys_setfsgid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setfsgid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setfsgid_kretprobe.kp.symbol_name, p_sys_setfsgid_kretprobe.kp.addr);
|
||||
p_sys_setfsgid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setfsgid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setfsgid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETFSGID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETFSGID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setfsgid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setfsgid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setfsgid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setfsgid_hook(void);
|
||||
void p_uninstall_sys_setfsgid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setfsuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setfsuid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setfsuid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setfsuid",
|
||||
.handler = p_sys_setfsuid_ret,
|
||||
.entry_handler = p_sys_setfsuid_entry,
|
||||
.data_size = sizeof(struct p_sys_setfsuid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setfsuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setfsuid_entry>\n");
|
||||
|
||||
/*
|
||||
* This is special case, since we can NOT identify when syscall fail or succeed,
|
||||
* we must verify process list before and after the syscall
|
||||
*/
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setfsuid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setfsuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setfsuid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setfsuid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
// if (!p_regs->ax) {
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
|
||||
p_update_ed_process(p_tmp, current);
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
// }
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setfsuid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setfsuid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setfsuid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setfsuid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setfsuid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setfsuid_kretprobe.kp.symbol_name, p_sys_setfsuid_kretprobe.kp.addr);
|
||||
p_sys_setfsuid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setfsuid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setfsuid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setfsuid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setfsuid_hook>\n");
|
||||
|
||||
if (!p_sys_setfsuid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setfsuid_kretprobe.kp.symbol_name, p_sys_setfsuid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setfsuid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setfsuid_kretprobe.kp.symbol_name, p_sys_setfsuid_kretprobe.kp.addr);
|
||||
p_sys_setfsuid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setfsuid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setfsuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETFSUID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETFSUID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setfsuid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setfsuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setfsuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setfsuid_hook(void);
|
||||
void p_uninstall_sys_setfsuid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setgid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setgid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setgid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setgid",
|
||||
.handler = p_sys_setgid_ret,
|
||||
.entry_handler = p_sys_setgid_entry,
|
||||
.data_size = sizeof(struct p_sys_setgid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setgid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setgid_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setgid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setgid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setgid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setgid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setgid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setgid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setgid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setgid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setgid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setgid_kretprobe.kp.symbol_name, p_sys_setgid_kretprobe.kp.addr);
|
||||
p_sys_setgid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setgid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setgid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setgid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setgid_hook>\n");
|
||||
|
||||
if (!p_sys_setgid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setgid_kretprobe.kp.symbol_name, p_sys_setgid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setgid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setgid_kretprobe.kp.symbol_name, p_sys_setgid_kretprobe.kp.addr);
|
||||
p_sys_setgid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setgid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setgid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETGID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETGID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setgid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setgid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setgid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setgid_hook(void);
|
||||
void p_uninstall_sys_setgid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setgroups syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setgroups_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setgroups_kretprobe = {
|
||||
.kp.symbol_name = "sys_setgroups",
|
||||
.handler = p_sys_setgroups_ret,
|
||||
.entry_handler = p_sys_setgroups_entry,
|
||||
.data_size = sizeof(struct p_sys_setgroups_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setgroups_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setgroups_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setgroups_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setgroups_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setgroups_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"setgroups returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setgroups_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setgroups_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setgroups_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setgroups_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setgroups_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setgroups_kretprobe.kp.symbol_name, p_sys_setgroups_kretprobe.kp.addr);
|
||||
p_sys_setgroups_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setgroups_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setgroups_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setgroups_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setgroups_hook>\n");
|
||||
|
||||
if (!p_sys_setgroups_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setgroups_kretprobe.kp.symbol_name, p_sys_setgroups_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setgroups_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setgroups_kretprobe.kp.symbol_name, p_sys_setgroups_kretprobe.kp.addr);
|
||||
p_sys_setgroups_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setgroups_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setgroups syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETGROUPS_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETGROUPS_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setgroups_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setgroups_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setgroups_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setgroups_hook(void);
|
||||
void p_uninstall_sys_setgroups_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setregid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setregid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setregid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setregid",
|
||||
.handler = p_sys_setregid_ret,
|
||||
.entry_handler = p_sys_setregid_entry,
|
||||
.data_size = sizeof(struct p_sys_setregid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setregid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setregid_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setregid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setregid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setregid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setregid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setregid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setregid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setregid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setregid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setregid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setregid_kretprobe.kp.symbol_name, p_sys_setregid_kretprobe.kp.addr);
|
||||
p_sys_setregid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setregid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setregid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setregid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setregid_hook>\n");
|
||||
|
||||
if (!p_sys_setregid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setregid_kretprobe.kp.symbol_name, p_sys_setregid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setregid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setregid_kretprobe.kp.symbol_name, p_sys_setregid_kretprobe.kp.addr);
|
||||
p_sys_setregid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setregid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setregid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETREGID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETREGID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setregid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setregid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setregid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setregid_hook(void);
|
||||
void p_uninstall_sys_setregid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setresgid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setresgid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setresgid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setresgid",
|
||||
.handler = p_sys_setresgid_ret,
|
||||
.entry_handler = p_sys_setresgid_entry,
|
||||
.data_size = sizeof(struct p_sys_setresgid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setresgid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setresgid_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setresgid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setresgid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setresgid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setresgid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setresgid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setresgid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setresgid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setresgid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setresgid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setresgid_kretprobe.kp.symbol_name, p_sys_setresgid_kretprobe.kp.addr);
|
||||
p_sys_setresgid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setresgid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setresgid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setresgid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setresgid_hook>\n");
|
||||
|
||||
if (!p_sys_setresgid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setresgid_kretprobe.kp.symbol_name, p_sys_setresgid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setresgid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setresgid_kretprobe.kp.symbol_name, p_sys_setresgid_kretprobe.kp.addr);
|
||||
p_sys_setresgid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setresgid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setresgid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETRESGID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETRESGID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setresgid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setresgid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setresgid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setresgid_hook(void);
|
||||
void p_uninstall_sys_setresgid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setresuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setresuid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setresuid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setresuid",
|
||||
.handler = p_sys_setresuid_ret,
|
||||
.entry_handler = p_sys_setresuid_entry,
|
||||
.data_size = sizeof(struct p_sys_setresuid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setresuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setresuid_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setresuid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setresuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setresuid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setresuid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setresuid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setresuid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setresuid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setresuid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setresuid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setresuid_kretprobe.kp.symbol_name, p_sys_setresuid_kretprobe.kp.addr);
|
||||
p_sys_setresuid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setresuid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setresuid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setresuid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setresuid_hook>\n");
|
||||
|
||||
if (!p_sys_setresuid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setresuid_kretprobe.kp.symbol_name, p_sys_setresuid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setresuid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setresuid_kretprobe.kp.symbol_name, p_sys_setresuid_kretprobe.kp.addr);
|
||||
p_sys_setresuid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setresuid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setresuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETRESUID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETRESUID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setresuid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setresuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setresuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setresuid_hook(void);
|
||||
void p_uninstall_sys_setresuid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setreuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setreuid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setreuid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setreuid",
|
||||
.handler = p_sys_setreuid_ret,
|
||||
.entry_handler = p_sys_setreuid_entry,
|
||||
.data_size = sizeof(struct p_sys_setreuid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setreuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setreuid_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setreuid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setreuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setreuid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setreuid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setreuid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setreuid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setreuid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setreuid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setreuid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setreuid_kretprobe.kp.symbol_name, p_sys_setreuid_kretprobe.kp.addr);
|
||||
p_sys_setreuid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setreuid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setreuid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setreuid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setreuid_hook>\n");
|
||||
|
||||
if (!p_sys_setreuid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setreuid_kretprobe.kp.symbol_name, p_sys_setreuid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setreuid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setreuid_kretprobe.kp.symbol_name, p_sys_setreuid_kretprobe.kp.addr);
|
||||
p_sys_setreuid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setreuid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setreuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETREUID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETREUID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setreuid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setreuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setreuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setreuid_hook(void);
|
||||
void p_uninstall_sys_setreuid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../../p_lkrg_main.h"
|
||||
|
||||
|
||||
char p_sys_setuid_kretprobe_state = 0x0;
|
||||
|
||||
static struct kretprobe p_sys_setuid_kretprobe = {
|
||||
.kp.symbol_name = "sys_setuid",
|
||||
.handler = p_sys_setuid_ret,
|
||||
.entry_handler = p_sys_setuid_entry,
|
||||
.data_size = sizeof(struct p_sys_setuid_data),
|
||||
/* Probe up to 20 instances concurrently. */
|
||||
.maxactive = 40,
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setuid_entry>\n");
|
||||
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
// This process is on the ED list - set temporary 'disable' flag!
|
||||
p_set_ed_process_off(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setuid_entry>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_sys_setuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs) {
|
||||
|
||||
struct p_ed_process *p_tmp;
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Entering function <p_sys_setuid_ret>\n");
|
||||
p_debug_kprobe_log(
|
||||
"Setuid returned value => %ld comm[%s] Pid:%d parent[%d]\n",
|
||||
p_regs->ax,current->comm,current->pid,current->real_parent->pid);
|
||||
|
||||
// Update process
|
||||
spin_lock(&p_rb_ed_pids_lock);
|
||||
task_lock(current);
|
||||
if ( (p_tmp = p_rb_find_ed_pid(&p_global_ed_pids_root, task_pid_nr(current))) != NULL) {
|
||||
if (!p_regs->ax) {
|
||||
// This process is on the ED list - update information!
|
||||
p_print_log(P_LKRG_INFO, "Updating ED pid[%d]\n",current->pid);
|
||||
p_update_ed_process(p_tmp, current);
|
||||
}
|
||||
p_set_ed_process_on(p_tmp);
|
||||
}
|
||||
task_unlock(current);
|
||||
spin_unlock(&p_rb_ed_pids_lock);
|
||||
|
||||
p_iterate_processes(p_validate_task_f);
|
||||
|
||||
p_debug_kprobe_log(
|
||||
"Leaving function <p_sys_setuid_ret>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int p_install_sys_setuid_hook(void) {
|
||||
|
||||
int p_ret;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_install_sys_setuid_hook>\n");
|
||||
|
||||
if ( (p_ret = register_kretprobe(&p_sys_setuid_kretprobe)) < 0) {
|
||||
p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() failed! [err=%d]\n",p_ret);
|
||||
goto p_install_sys_setuid_hook_out;
|
||||
}
|
||||
p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: %p\n",
|
||||
p_sys_setuid_kretprobe.kp.symbol_name, p_sys_setuid_kretprobe.kp.addr);
|
||||
p_sys_setuid_kretprobe_state = 0x1;
|
||||
|
||||
// p_ret = 0x0; <- should be 0x0 anyway...
|
||||
|
||||
p_install_sys_setuid_hook_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_install_sys_setuid_hook> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
void p_uninstall_sys_setuid_hook(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_uninstall_sys_setuid_hook>\n");
|
||||
|
||||
if (!p_sys_setuid_kretprobe_state) {
|
||||
p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%p is NOT installed\n",
|
||||
p_sys_setuid_kretprobe.kp.symbol_name, p_sys_setuid_kretprobe.kp.addr);
|
||||
} else {
|
||||
unregister_kretprobe(&p_sys_setuid_kretprobe);
|
||||
p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%p\n",
|
||||
p_sys_setuid_kretprobe.kp.symbol_name, p_sys_setuid_kretprobe.kp.addr);
|
||||
p_sys_setuid_kretprobe_state = 0x0;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_uninstall_sys_setuid_hook>\n");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Intercept setuid syscall
|
||||
*
|
||||
* Notes:
|
||||
* - Exploit Detection features needs to whitelist process which
|
||||
* legitimately increases their privileges (e.g. 'su', 'sudo', etc.)
|
||||
*
|
||||
* Caveats:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_EXPLOIT_DETECTION_SYS_SETUID_H
|
||||
#define P_LKRG_EXPLOIT_DETECTION_SYS_SETUID_H
|
||||
|
||||
/* per-instance private data */
|
||||
struct p_sys_setuid_data {
|
||||
ktime_t entry_stamp;
|
||||
};
|
||||
|
||||
|
||||
int p_sys_setuid_ret(struct kretprobe_instance *ri, struct pt_regs *p_regs);
|
||||
int p_sys_setuid_entry(struct kretprobe_instance *p_ri, struct pt_regs *p_regs);
|
||||
int p_install_sys_setuid_hook(void);
|
||||
void p_uninstall_sys_setuid_hook(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Hashing algorithm module - SHA1 via crypto API
|
||||
*
|
||||
* Notes:
|
||||
* - SHA1 via crypto API
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 11.IV.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
/*
|
||||
* Caller must free the buffer - kfree(*p_arg_out)
|
||||
*/
|
||||
char *p_sha1_hash(char **p_arg_out, const char *p_arg_in, unsigned int p_arg_len) {
|
||||
|
||||
struct crypto_shash *p_tmp_sha1 = (struct crypto_shash *)-1;
|
||||
struct p_sdesc *p_tmp_sdesc = NULL;
|
||||
char p_tmp_sha1_hash[P_SHA1_SIZE];
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
unsigned int p_tmp_size;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_cpu_dead_action>\n");
|
||||
|
||||
if (!p_arg_in || !p_arg_out || !p_arg_len || p_arg_len > 100) {
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -1;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
memset(p_tmp_sha1_hash,0x0,P_SHA1_SIZE);
|
||||
p_tmp_sha1 = crypto_alloc_shash("sha1", 0, 0);
|
||||
if (IS_ERR(p_tmp_sha1)) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"SHA1: crypto_alloc_shash() error!\n");
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -2;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
p_tmp_size = sizeof(struct shash_desc) + crypto_shash_descsize(p_tmp_sha1);
|
||||
if ( (p_tmp_sdesc = kmalloc(p_tmp_size, GFP_ATOMIC)) == NULL) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"SHA1: kmalloc() error!\n");
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -3;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
p_tmp_sdesc->shash.tfm = p_tmp_sha1;
|
||||
p_tmp_sdesc->shash.flags = 0x0;
|
||||
|
||||
if ( (p_ret = crypto_shash_init(&p_tmp_sdesc->shash)) != 0) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"SHA1: Could not init shash\n");
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -4;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
if ( (p_ret = crypto_shash_update(&p_tmp_sdesc->shash, p_arg_in, p_arg_len)) != 0){
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"SHA1: Could not update with own string\n");
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -5;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
if ( (p_ret = crypto_shash_final(&p_tmp_sdesc->shash, p_tmp_sha1_hash)) != 0) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"SHA1: Could not generate sha1 hash\n");
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -6;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
if ( (*p_arg_out = kmalloc(P_SHA1_SIZE, GFP_ATOMIC)) == NULL) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"SHA1: kmalloc() SHA1_SIZE error!\n");
|
||||
*p_arg_out = NULL;
|
||||
p_ret = -7;
|
||||
goto p_sha1_hash_out;
|
||||
}
|
||||
|
||||
memcpy(*p_arg_out, p_tmp_sha1_hash, P_SHA1_SIZE);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"[%d][%s]\n",p_arg_len,p_arg_in);
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"SHA1 => [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n",
|
||||
p_tmp_sha1_hash[0],p_tmp_sha1_hash[1],p_tmp_sha1_hash[2],p_tmp_sha1_hash[3],
|
||||
p_tmp_sha1_hash[4],p_tmp_sha1_hash[5],p_tmp_sha1_hash[6],p_tmp_sha1_hash[7],
|
||||
p_tmp_sha1_hash[8],p_tmp_sha1_hash[9],p_tmp_sha1_hash[10],p_tmp_sha1_hash[11],
|
||||
p_tmp_sha1_hash[12],p_tmp_sha1_hash[13],p_tmp_sha1_hash[14],p_tmp_sha1_hash[15],
|
||||
p_tmp_sha1_hash[16],p_tmp_sha1_hash[17],p_tmp_sha1_hash[18],p_tmp_sha1_hash[19]
|
||||
);
|
||||
|
||||
p_sha1_hash_out:
|
||||
|
||||
if (!IS_ERR(p_tmp_sha1))
|
||||
crypto_free_shash(p_tmp_sha1);
|
||||
if (p_tmp_sdesc)
|
||||
kfree(p_tmp_sdesc);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_sha1_hash> ret => %d\n",p_ret);
|
||||
|
||||
return *p_arg_out;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Hashing algorithm module - SHA1 via crypto API
|
||||
*
|
||||
* Notes:
|
||||
* - SHA1 via crypto API
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 11.IV.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_CRYPTOAPI_SHA1_H
|
||||
#define P_LKRG_CRYPTOAPI_SHA1_H
|
||||
|
||||
#define P_SHA1_SIZE 20
|
||||
|
||||
struct p_sdesc {
|
||||
struct shash_desc shash;
|
||||
char ctx[];
|
||||
};
|
||||
|
||||
char *p_sha1_hash(char **p_arg_out, const char *p_arg_in, unsigned int p_arg_len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Hashing algorithm module - SuperFastHash
|
||||
*
|
||||
* Notes:
|
||||
* - Algorithm from:
|
||||
* *) http://azillionmonkeys.com/qed/hash.html
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
uint32_t p_super_fast_hash(const char *data, unsigned int len) {
|
||||
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if (len == 0 || data == NULL)
|
||||
return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Hashing algorithm module - SuperFastHash
|
||||
*
|
||||
* Notes:
|
||||
* - Algorithm from:
|
||||
* *) http://azillionmonkeys.com/qed/hash.html
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_SUPERFASTHASH_H
|
||||
#define P_LKRG_SUPERFASTHASH_H
|
||||
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
|
||||
uint32_t p_super_fast_hash(const char *data, unsigned int len);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Integrity timer module
|
||||
*
|
||||
* Notes:
|
||||
* - Periodically check critical system hashes using timer
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_INTEGRITY_TIMER_H
|
||||
#define P_LKRG_INTEGRITY_TIMER_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))
|
||||
|
||||
void p_check_integrity(struct work_struct *p_work);
|
||||
void p_integrity_timer(void);
|
||||
void p_offload_work(unsigned long p_timer);
|
||||
|
||||
int p_cmp_bytes(char *p_new, char *p_old, unsigned long p_size);
|
||||
|
||||
int p_offload_cache_init(void);
|
||||
void p_offload_cache_delete(void);
|
||||
|
||||
extern struct timer_list p_timer;
|
||||
extern spinlock_t p_db_lock;
|
||||
extern unsigned long p_db_flags;
|
||||
extern struct kmem_cache *p_offload_cache;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Integrity timer module - check Linux kernel .text section differences
|
||||
*
|
||||
* Notes:
|
||||
* - Linux kernel is heavily consuming *_JUMP_LABEL (if enabled). Most of the
|
||||
* Linux distributions provide kernel with these options compiled. It makes
|
||||
* Linux kernel being self-modifying code. It is very troublesome for this
|
||||
* project. We are relying on comparing hashes from the specific memory
|
||||
* regions and by design self-midifications breaks this functionality.
|
||||
* To mitigate the problem we do make special efford:
|
||||
* - We keep a copy of the entire .text section made during module installation
|
||||
* - If we detect that .text section for kernel was changed we try to find the
|
||||
* offset where modifications was made. We use this offset to calculate the VA
|
||||
* where modification was made. If modification happend because of the
|
||||
* *_JUMP_LABEL options, originally long NOP was injected (5 bytes long) or
|
||||
* already resolved relative 'jmp' instruction. If NOP is modified to 'jmp'
|
||||
* the target is still pointing inside of the same function (symbol name).
|
||||
* We decode jmp instruction to validate if the target is still pointing inside
|
||||
* the same symbol name range, if yes it is most likely 'legit' modification.
|
||||
* If 'jmp' instruction was changed, we only allow to be replaced by long NOP
|
||||
* one. Also modification long NOP is only allowed to become 'jmp' pointing
|
||||
* in the range of the same symbol name function.
|
||||
* *WARN* It is still possible to find injected NOPs by *_JMP_LABEL and overwrte
|
||||
* them using 'jmp' instruction and point to the random address at the
|
||||
* same 'symbol name rage'. It allows attacker to create a rootkit based
|
||||
* only on ROP. A few comments are needed here:
|
||||
* - it is very difficult task to create fully functional rootkit based
|
||||
* only on 1-function ROP - but possible
|
||||
* - at random point of time kernel WILL overwrite this modifications
|
||||
* anyway - so this won't be persistand modofications. Moreover, it
|
||||
* won't be deterministic so risk is very low
|
||||
* - Every other modifications are banned
|
||||
*
|
||||
* Self-modifications are usually made via:
|
||||
* - Tracepoints events
|
||||
* - DO_ONCE() macro
|
||||
*
|
||||
* "whitelist" bytes:
|
||||
* - long nop:
|
||||
* nopl 0x0(%rax,%rax,1): 0x0f 0x1f 0x44 0x00 0x00
|
||||
* - e.g. of relative jmp:
|
||||
* jmpq 0xffffffff8168899e: 0xe9 0x9c 0x03 0x00 0x00
|
||||
*
|
||||
* "arch/x86/include/asm/jump_label.h" defines:
|
||||
* 17 #define JUMP_LABEL_NOP_SIZE 5
|
||||
* 18
|
||||
* 19 #ifdef CONFIG_X86_64
|
||||
* 20 # define STATIC_KEY_INIT_NOP P6_NOP5_ATOMIC
|
||||
* 21 #else
|
||||
* 22 # define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
|
||||
* 23 #endif
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 28.VI.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STATIC_KEY_INIT_NOP
|
||||
#ifdef CONFIG_X86_64
|
||||
# define STATIC_KEY_INIT_NOP P6_NOP5_ATOMIC
|
||||
#else
|
||||
# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MK7)
|
||||
#define P_ASM_NOP5_ATOMIC K7_NOP5_ATOMIC
|
||||
#elif defined(CONFIG_X86_P6_NOP)
|
||||
#define P_ASM_NOP5_ATOMIC P6_NOP5_ATOMIC
|
||||
#elif defined(CONFIG_X86_64)
|
||||
#define P_ASM_NOP5_ATOMIC K8_NOP5_ATOMIC
|
||||
#else
|
||||
#define P_ASM_NOP5_ATOMIC GENERIC_NOP5_ATOMIC
|
||||
#endif
|
||||
|
||||
char p_white_nop[JUMP_LABEL_NOP_SIZE] = { STATIC_KEY_INIT_NOP };
|
||||
char p_white_nop2[JUMP_LABEL_NOP_SIZE] = { P_ASM_NOP5_ATOMIC };
|
||||
|
||||
/*
|
||||
#define VALUE_TO_STRING(x) #x
|
||||
#define VALUE(x) VALUE_TO_STRING(x)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
|
||||
#pragma message(VAR_NAME_VALUE( __stringify(P_ASM_NOP5_ATOMIC)))
|
||||
*/
|
||||
|
||||
int p_cmp_bytes(char *p_new, char *p_old, unsigned long p_size) {
|
||||
|
||||
unsigned long p_tmp;
|
||||
unsigned int *p_val; // 'jmp' arg
|
||||
char p_sym1[KSYM_SYMBOL_LEN]; // symbol name of the original VA
|
||||
char p_sym2[KSYM_SYMBOL_LEN]; // symbol name of the destination 'jmp' VA
|
||||
unsigned long p_VA1; // Original VA
|
||||
unsigned long p_VA2; // destination 'jmp' VA
|
||||
unsigned int p_cnt; // counter
|
||||
char p_flag;
|
||||
size_t p_len; // length of the symbol name
|
||||
|
||||
memset(p_sym1,0x0,KSYM_SYMBOL_LEN);
|
||||
memset(p_sym2,0x0,KSYM_SYMBOL_LEN);
|
||||
|
||||
for (p_tmp = 0x0; p_tmp < p_size-JUMP_LABEL_NOP_SIZE; p_tmp++) {
|
||||
if (p_new[p_tmp] != p_old[p_tmp]) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Offset[0x%lx] old[0x%x] new[0x%x]\n",
|
||||
p_tmp,
|
||||
(unsigned int)(p_old[p_tmp] & 0xFF),
|
||||
(unsigned int)(p_new[p_tmp] & 0xFF));
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"old[0x%x] old+1[0x%x] old+2[0x%x] old+3[0x%x] old+4[0x%x]\n",
|
||||
p_old[p_tmp] & 0xFF,p_old[p_tmp+1] & 0xFF,p_old[p_tmp+2] & 0xFF,
|
||||
p_old[p_tmp+3] & 0xFF, p_old[p_tmp+4] & 0xFF);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"new[0x%x] new+1[0x%x] new+2[0x%x] new+3[0x%x] new+4[0x%x]\n",
|
||||
p_new[p_tmp] & 0xFF, p_new[p_tmp+1] & 0xFF, p_new[p_tmp+2] & 0xFF,
|
||||
p_new[p_tmp+3] & 0xFF, p_new[p_tmp+4] & 0xFF);
|
||||
|
||||
/* OK, we have found difference, let's check if this is "whitelist" modifications */
|
||||
/*
|
||||
if ((p_old[p_tmp] & 0xFF) == 0x0f && (p_old[p_tmp+1] & 0xFF) == 0x1f && // Is long NOP
|
||||
(p_old[p_tmp+2] & 0xFF) == 0x44 && (p_old[p_tmp+3] & 0xFF) == 0x00 && // was overwritten?
|
||||
(p_old[p_tmp+4] & 0xFF) == 0x00) {
|
||||
*/
|
||||
|
||||
p_flag = 0x0;
|
||||
if ( (p_old[p_tmp] & 0xFF) == (p_white_nop[0x0] & 0xFF) ) { // NOP -> JMP/0xcc ?
|
||||
for (p_cnt = 0x1; p_cnt < JUMP_LABEL_NOP_SIZE; p_cnt++) {
|
||||
if ( (p_old[p_tmp+p_cnt] & 0xFF) != (p_white_nop[p_cnt] & 0xFF) ) {
|
||||
p_flag = 0x1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p_flag = (p_flag) ? 0x0 : 0x1;
|
||||
} else if ( (p_new[p_tmp] & 0xFF) == (p_white_nop[0x0] & 0xFF) ) { // JMP/0xcc -> NOP ?
|
||||
for (p_cnt = 0x1; p_cnt < JUMP_LABEL_NOP_SIZE; p_cnt++) {
|
||||
if ( (p_new[p_tmp+p_cnt] & 0xFF) != (p_white_nop[p_cnt] & 0xFF) ) {
|
||||
p_flag = 0x1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p_flag = (p_flag) ? 0x0 : 0x2;
|
||||
}
|
||||
|
||||
if (!p_flag) { // it could be other type of NOP...
|
||||
if ( (p_old[p_tmp] & 0xFF) == (p_white_nop2[0x0] & 0xFF) ) { // NOP -> JMP/0xcc ?
|
||||
for (p_cnt = 0x1; p_cnt < JUMP_LABEL_NOP_SIZE; p_cnt++) {
|
||||
if ( (p_old[p_tmp+p_cnt] & 0xFF) != (p_white_nop2[p_cnt] & 0xFF) ) {
|
||||
p_flag = 0x1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p_flag = (p_flag) ? 0x0 : 0x1;
|
||||
} else if ( (p_new[p_tmp] & 0xFF) == (p_white_nop2[0x0] & 0xFF) ) { // JMP/0xcc -> NOP ?
|
||||
for (p_cnt = 0x1; p_cnt < JUMP_LABEL_NOP_SIZE; p_cnt++) {
|
||||
if ( (p_new[p_tmp+p_cnt] & 0xFF) != (p_white_nop2[p_cnt] & 0xFF) ) {
|
||||
p_flag = 0x1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p_flag = (p_flag) ? 0x0 : 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_flag == 0x1) { // NOP -> JMP/0xcc
|
||||
/*
|
||||
* OK, so we know long NOP was overwritten... we only allow modification
|
||||
* to relative jmp pointing to exactly the same function... Let's check
|
||||
*/
|
||||
if ( (p_new[p_tmp] & 0xFF) == 0xe9) { // Is it 'jmp' ?
|
||||
p_val = (unsigned int *)&p_new[p_tmp+0x1]; // 'jmp' arg
|
||||
p_VA1 = (unsigned long) &p_new[p_tmp]; // original VA
|
||||
p_VA2 = (unsigned long) p_VA1 + 5 + *p_val; // destination VA
|
||||
sprint_symbol_no_offset(p_sym1,p_VA1); // symbol name for original VA
|
||||
sprint_symbol_no_offset(p_sym2,p_VA2); // symbol name for destination VA
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"[NOP->JMP] p_val[0x%x] p_VA1[0x%lx] p_VA2[0x%lx] p_sym1[%s] p_sym2[%s]\n",
|
||||
*p_val,p_VA1,p_VA2,p_sym1,p_sym2);
|
||||
|
||||
p_len = strlen(p_sym1);
|
||||
if (p_len != strlen(p_sym2))
|
||||
return -1; // Lenght is different so for sure this is not the same symbol!
|
||||
|
||||
if (strncmp(p_sym1,p_sym2,p_len))
|
||||
return -1; // This is not the same symbol even length is the same...
|
||||
|
||||
// Shout be P_LKRG_WARN?
|
||||
p_print_log(P_LKRG_INFO, "Detected legit self-modification in core linux .text "
|
||||
"section in VA[0x%lx] function [%s] - tracepoints?\n",
|
||||
p_VA1,p_sym1);
|
||||
|
||||
/*
|
||||
* Let's modify dynamicaly copy of the vmlinux image. We know that current modification
|
||||
* is "whitelisted" and if it returns to the original values we need to be able
|
||||
* to detect that. If we dynamically updating copy of vmlinux image it is possible
|
||||
* to have 'half-baked cake'. If further modifications are NOT "whitelisted" but previous
|
||||
* one was, we return immediately with not fully modified copy of vmlinux. But that's
|
||||
* OK. If further modifications are NOT valid it means system was fully compromised
|
||||
* and non of the data should be trusted. We should PANIC the kernel... or not if
|
||||
* administrator of the system decided otherwise...
|
||||
*/
|
||||
p_old[p_tmp] = p_new[p_tmp];
|
||||
p_old[p_tmp+1] = p_new[p_tmp+1];
|
||||
p_old[p_tmp+2] = p_new[p_tmp+2];
|
||||
p_old[p_tmp+3] = p_new[p_tmp+3];
|
||||
p_old[p_tmp+4] = p_new[p_tmp+4];
|
||||
|
||||
p_tmp += 4; // Let's continue our checks... first, do increase indexer!
|
||||
continue;
|
||||
|
||||
} else if ( ((p_new[p_tmp] & 0xFF) == 0xcc) && // Is it int3 ?
|
||||
// ((p_new[p_tmp+1] & 0xFF) == 0xad) && // rest of the bytes can't be random...
|
||||
((p_new[p_tmp+2] & 0xFF) == 0x00) && // rest of the bytes can't be random...
|
||||
((p_new[p_tmp+3] & 0xFF) == 0x00) && // rest of the bytes can't be random...
|
||||
((p_new[p_tmp+4] & 0xFF) == 0x00)) { // rest of the bytes can't be random...
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"[NOP->0xCC] p_old[0x%lx]{0x%x} -> p_new[0x%lx] => 0x%x\n",
|
||||
p_tmp,p_old[p_tmp],p_tmp,p_new[p_tmp]);
|
||||
|
||||
/*
|
||||
* Let's modify dynamicaly copy of the vmlinux image. We know that current modification
|
||||
* is "whitelisted" and if it returns to the original values we need to be able
|
||||
* to detect that. If we dynamically updating copy of vmlinux image it is possible
|
||||
* to have 'half-baked cake'. If further modifications are NOT "whitelisted" but previous
|
||||
* one was, we return immediately with not fully modified copy of vmlinux. But that's
|
||||
* OK. If further modifications are NOT valid it means system was fully compromised
|
||||
* and non of the data should be trusted. We should PANIC the kernel... or not if
|
||||
* administrator of the system decided otherwise...
|
||||
*/
|
||||
p_old[p_tmp] = p_new[p_tmp];
|
||||
p_old[p_tmp+1] = p_new[p_tmp+1];
|
||||
p_old[p_tmp+2] = p_new[p_tmp+2];
|
||||
p_old[p_tmp+3] = p_new[p_tmp+3];
|
||||
p_old[p_tmp+4] = p_new[p_tmp+4];
|
||||
|
||||
p_tmp += 4; // Let's continue our checks... first, do increase indexer!
|
||||
continue;
|
||||
|
||||
} else { // We do not allow any other modifications...
|
||||
return -1; // We do not need to check further modifications because
|
||||
// this one is malicious so entire system might compromised
|
||||
// anyway - regardless if further modifications are "whitelisted"
|
||||
// or not
|
||||
}
|
||||
} else if (p_flag == 0x2) { // JMP/0xcc -> NOP
|
||||
|
||||
/*
|
||||
* Let's check if original 'jmp' was in the range of the same symbol name
|
||||
* If not, this is very weird situation... should never happens!
|
||||
*/
|
||||
|
||||
if ((p_old[p_tmp] & 0xFF) == 0xe9) {
|
||||
p_val = (unsigned int *)&p_old[p_tmp+0x1]; // 'jmp' arg
|
||||
p_VA1 = (unsigned long) &p_new[p_tmp]; // original VA
|
||||
p_VA2 = (unsigned long) p_VA1 + 5 + *p_val; // destination VA
|
||||
sprint_symbol_no_offset(p_sym1,p_VA1); // symbol name for original VA
|
||||
sprint_symbol_no_offset(p_sym2,p_VA2); // symbol name for destination VA
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"[JMP->NOP] p_val[0x%x] p_VA1[0x%lx] p_VA2[0x%lx] p_sym1[%s] p_sym2[%s]\n",
|
||||
*p_val,p_VA1,p_VA2,p_sym1,p_sym2);
|
||||
|
||||
p_len = strlen(p_sym1);
|
||||
if (p_len != strlen(p_sym2)) {
|
||||
p_print_log(P_LKRG_CRIT,"[WEIRD!] Kernel overwrote JMP instruction pointing "
|
||||
"not in the same function via NOP - should NOT happens!\n");
|
||||
// Weird! Lenght is different so for sure this is not the same symbol!
|
||||
//return -1; <- let's continue checks!
|
||||
}
|
||||
|
||||
if (strncmp(p_sym1,p_sym2,p_len)) {
|
||||
p_print_log(P_LKRG_CRIT,"[WEIRD!] Kernel overwrote JMP instruction pointing "
|
||||
"not in the same function via NOP - should NOT happens!\n");
|
||||
// Weird! This is not the same symbol even length is the same...
|
||||
//return -1; <- let's continue checks!
|
||||
}
|
||||
|
||||
// Shout be P_LKRG_WARN?
|
||||
p_print_log(P_LKRG_INFO, "Detected legit self-modification in core linux .text "
|
||||
"section in VA[0x%lx] function [%s] - tracepoints?\n",
|
||||
p_VA1,p_sym1);
|
||||
|
||||
/*
|
||||
* Let's modify dynamicaly copy of the vmlinux image. We know that current modification
|
||||
* is "whitelisted" and if it returns to the original values we need to be able
|
||||
* to detect that. If we dynamically updating copy of vmlinux image it is possible
|
||||
* to have 'half-baked cake'. If further modifications are NOT "whitelisted" but previous
|
||||
* one was, we return immediately with not fully modified copy of vmlinux. But that's
|
||||
* OK. If further modifications are NOT valid it means system was fully compromised
|
||||
* and non of the data should be trusted. We should PANIC the kernel... or not if
|
||||
* administrator of the system decided otherwise...
|
||||
*/
|
||||
p_old[p_tmp] = p_new[p_tmp];
|
||||
p_old[p_tmp+1] = p_new[p_tmp+1];
|
||||
p_old[p_tmp+2] = p_new[p_tmp+2];
|
||||
p_old[p_tmp+3] = p_new[p_tmp+3];
|
||||
p_old[p_tmp+4] = p_new[p_tmp+4];
|
||||
|
||||
p_tmp += 4; // Let's continue our checks... first, do increase indexer!
|
||||
continue;
|
||||
|
||||
} else if ( ((p_old[p_tmp] & 0xFF) == 0xcc) && // Is it int3 ?
|
||||
// ((p_old[p_tmp+1] & 0xFF) == 0xad) && // rest of the bytes can't be random...
|
||||
((p_old[p_tmp+2] & 0xFF) == 0x00) && // rest of the bytes can't be random...
|
||||
((p_old[p_tmp+3] & 0xFF) == 0x00) && // rest of the bytes can't be random...
|
||||
((p_old[p_tmp+4] & 0xFF) == 0x00)) { // rest of the bytes can't be random...
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"[0xCC->NOP] p_old[0x%lx]{0x%x} -> p_new[0x%lx] => 0x%x\n",
|
||||
p_tmp,p_old[p_tmp],p_tmp,p_new[p_tmp]);
|
||||
|
||||
/*
|
||||
* Let's modify dynamicaly copy of the vmlinux image. We know that current modification
|
||||
* is "whitelisted" and if it returns to the original values we need to be able
|
||||
* to detect that. If we dynamically updating copy of vmlinux image it is possible
|
||||
* to have 'half-baked cake'. If further modifications are NOT "whitelisted" but previous
|
||||
* one was, we return immediately with not fully modified copy of vmlinux. But that's
|
||||
* OK. If further modifications are NOT valid it means system was fully compromised
|
||||
* and non of the data should be trusted. We should PANIC the kernel... or not if
|
||||
* administrator of the system decided otherwise...
|
||||
*/
|
||||
p_old[p_tmp] = p_new[p_tmp];
|
||||
p_old[p_tmp+1] = p_new[p_tmp+1];
|
||||
p_old[p_tmp+2] = p_new[p_tmp+2];
|
||||
p_old[p_tmp+3] = p_new[p_tmp+3];
|
||||
p_old[p_tmp+4] = p_new[p_tmp+4];
|
||||
|
||||
p_tmp += 4; // Let's continue our checks... first, do increase indexer!
|
||||
continue;
|
||||
|
||||
} else { // We do not allow any other modifications...
|
||||
return -1; // We do not need to check further modifications because
|
||||
// this one is malicious so entire system might compromised
|
||||
// anyway - regardless if further modifications are "whitelisted"
|
||||
// or not
|
||||
}
|
||||
} else {
|
||||
return -1; // We do not need to check further modifications because
|
||||
// this one is malicious so entire system might compromised
|
||||
// anyway - regardless if further modifications are "whitelisted"
|
||||
// or not
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Kernel's modules module
|
||||
*
|
||||
* Notes:
|
||||
* - Gathers information about loaded kernel modules and tries
|
||||
* to protect them via calculating hashes from their core_text
|
||||
* section.
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.II.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
* Notes - https://github.com/dgoulet/kjackal/blob/master/src/module.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
/* Submodule with 'struct module' variable accessing wrappers */
|
||||
//#include "p_kmod_wrapper.c"
|
||||
|
||||
/* Submodule for 'kmod' module */
|
||||
#include "p_kmod_notifier.c"
|
||||
|
||||
p_lkrg_global_ctrl_struct p_lkrg_global_ctrl;
|
||||
|
||||
struct list_head *p_ddebug_tables = NULL;
|
||||
struct mutex *p_ddebug_lock = NULL;
|
||||
struct list_head *p_global_modules = NULL;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
struct mutex *p_kernfs_mutex = NULL;
|
||||
#endif
|
||||
struct kset **p_module_kset = NULL;
|
||||
|
||||
int p_kmod_init(void) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_kmod_init>\n");
|
||||
|
||||
p_ddebug_tables = (struct list_head *)p_kallsyms_lookup_name("ddebug_tables");
|
||||
p_ddebug_lock = (struct mutex *)p_kallsyms_lookup_name("ddebug_lock");
|
||||
p_global_modules = (struct list_head *)p_kallsyms_lookup_name("modules");
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
p_kernfs_mutex = (struct mutex *)p_kallsyms_lookup_name("kernfs_mutex");
|
||||
#endif
|
||||
p_module_kset = (struct kset **)p_kallsyms_lookup_name("module_kset");
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"<p_kmod_init> p_ddebug_tables[0x%lx] p_ddebug_lock[0x%lx] "
|
||||
"module_mutex[0x%lx] p_global_modules[0x%p] "
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
"p_kernfs_mutex[0x%p] p_module_kset[0x%p]\n",
|
||||
#else
|
||||
"p_module_kset[0x%p]\n",
|
||||
#endif
|
||||
(long)p_ddebug_tables,
|
||||
(long)p_ddebug_lock,
|
||||
(long)&module_mutex,
|
||||
p_global_modules,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
p_kernfs_mutex,
|
||||
#endif
|
||||
p_module_kset);
|
||||
|
||||
if (!p_global_modules) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"KMOD error! Can't initialize global modules variable :( Exiting...\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_kmod_init_out;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
if (!p_kernfs_mutex) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"KMOD error! Can't find 'kernfs_mutex' variable :( Exiting...\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_kmod_init_out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!p_module_kset) {
|
||||
p_print_log(P_LKRG_ERR,
|
||||
"KMOD error! Can't find 'module_kset' variable :( Exiting...\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_kmod_init_out;
|
||||
}
|
||||
|
||||
/* Register module notification routine */
|
||||
p_register_module_notifier();
|
||||
|
||||
p_kmod_init_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_kmod_init> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'module_lock' must be taken by calling function!
|
||||
*/
|
||||
unsigned int p_count_modules_from_module_list(void) {
|
||||
|
||||
unsigned int p_cnt = 0x0;
|
||||
struct module *p_mod;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_count_modules_from_module_list>\n");
|
||||
|
||||
// mutex_lock(&module_mutex);
|
||||
list_for_each_entry(p_mod, p_global_modules, list) {
|
||||
|
||||
/*
|
||||
if (p_mod->state >= MODULE_STATE_UNFORMED ||
|
||||
p_mod->state < MODULE_STATE_LIVE)
|
||||
continue;
|
||||
*/
|
||||
if (p_mod->state != MODULE_STATE_LIVE)
|
||||
continue;
|
||||
|
||||
if (p_mod == p_find_me)
|
||||
continue;
|
||||
|
||||
if (!p_module_core(p_mod) || !p_core_text_size(p_mod))
|
||||
continue;
|
||||
|
||||
p_cnt++;
|
||||
}
|
||||
// mutex_unlock(&module_mutex);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Leaving function <p_count_modules_from_module_list> (p_cnt => %d)\n",p_cnt);
|
||||
|
||||
return p_cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse module list
|
||||
*
|
||||
* 'module_lock' must be taken by calling function!
|
||||
*/
|
||||
int p_list_from_module_list(p_module_list_mem *p_arg) {
|
||||
|
||||
struct module *p_mod;
|
||||
int p_ret = 0x0;
|
||||
unsigned int p_cnt = 0x0;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_list_from_module_list>\n");
|
||||
|
||||
// mutex_lock(&module_mutex);
|
||||
list_for_each_entry(p_mod, p_global_modules, list) {
|
||||
/*
|
||||
if (p_mod->state >= MODULE_STATE_UNFORMED ||
|
||||
p_mod->state < MODULE_STATE_LIVE)
|
||||
continue;
|
||||
*/
|
||||
if (p_mod->state != MODULE_STATE_LIVE)
|
||||
continue;
|
||||
|
||||
if (p_mod == p_find_me)
|
||||
continue;
|
||||
|
||||
if (!p_module_core(p_mod) || !p_core_text_size(p_mod))
|
||||
continue;
|
||||
|
||||
/* Pointer to THIS_MODULE per module */
|
||||
p_arg[p_cnt].p_mod = p_mod;
|
||||
/* Save module name for that pointer */
|
||||
memcpy(p_arg[p_cnt].p_name,p_mod->name,MODULE_NAME_LEN);
|
||||
p_arg[p_cnt].p_name[MODULE_NAME_LEN] = 0x0;
|
||||
/* Pointer to the module core */
|
||||
p_arg[p_cnt].p_module_core = p_module_core(p_mod);
|
||||
/* Size of the module core text section */
|
||||
p_arg[p_cnt].p_core_text_size = p_core_text_size(p_mod);
|
||||
/* Calculate hash from the module core text section ;) */
|
||||
p_arg[p_cnt].p_mod_core_text_hash = p_super_fast_hash((unsigned char *)p_arg[p_cnt].p_module_core,
|
||||
(unsigned int)p_arg[p_cnt].p_core_text_size);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"[%s | %p] module_core[%p | 0x%x] hash[0x%x]\n",
|
||||
p_arg[p_cnt].p_name,p_arg[p_cnt].p_mod,p_arg[p_cnt].p_module_core,
|
||||
p_arg[p_cnt].p_core_text_size,p_arg[p_cnt].p_mod_core_text_hash);
|
||||
|
||||
p_cnt++;
|
||||
}
|
||||
// mutex_unlock(&module_mutex);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Leaving function <p_list_from_module_list> (p_cnt => %d)\n",p_cnt);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'module_lock' must be taken by calling function!
|
||||
*/
|
||||
unsigned int p_count_modules_from_sysfs_kobj(void) {
|
||||
|
||||
struct module *p_mod = NULL;
|
||||
struct kset *p_kset = *p_module_kset;
|
||||
struct kobject *p_kobj = NULL, *p_tmp_safe = NULL;
|
||||
struct module_kobject *p_mk = NULL;
|
||||
unsigned int p_cnt = 0x0;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_count_modules_from_sysfs_kobj>\n");
|
||||
|
||||
kset_get(p_kset);
|
||||
spin_lock(&p_kset->list_lock);
|
||||
list_for_each_entry_safe(p_kobj, p_tmp_safe, &p_kset->list, entry) {
|
||||
|
||||
if (!__module_address((unsigned long)p_kobj))
|
||||
continue;
|
||||
|
||||
if (!p_kobj->state_initialized || !p_kobj->state_in_sysfs) {
|
||||
/* Weirdo state :( */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!p_kobj->name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p_mk = container_of(p_kobj, struct module_kobject, kobj);
|
||||
if (!p_mk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p_mod = p_mk->mod;
|
||||
if (!p_mod) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_mod->state != MODULE_STATE_LIVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_mod == p_find_me) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!p_module_core(p_mod) || !p_core_text_size(p_mod)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p_cnt++;
|
||||
}
|
||||
spin_unlock(&p_kset->list_lock);
|
||||
kset_put(p_kset);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Leaving function <p_count_modules_from_sysfs_kobj> (p_cnt => %d)\n",p_cnt);
|
||||
|
||||
return p_cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'module_lock' must be taken by calling function!
|
||||
*/
|
||||
int p_list_from_sysfs_kobj(p_module_kobj_mem *p_arg) {
|
||||
|
||||
struct module *p_mod = NULL;
|
||||
struct kset *p_kset = *p_module_kset;
|
||||
struct kobject *p_kobj = NULL, *p_tmp_safe = NULL;
|
||||
struct module_kobject *p_mk = NULL;
|
||||
int p_ret = 0x0;
|
||||
unsigned int p_cnt = 0x0;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_list_from_sysfs_kobj>\n");
|
||||
|
||||
kset_get(p_kset);
|
||||
spin_lock(&p_kset->list_lock);
|
||||
list_for_each_entry_safe(p_kobj, p_tmp_safe, &p_kset->list, entry) {
|
||||
|
||||
if (!__module_address((unsigned long)p_kobj))
|
||||
continue;
|
||||
|
||||
if (!p_kobj->state_initialized || !p_kobj->state_in_sysfs) {
|
||||
/* Weirdo state :( */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!p_kobj->name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p_mk = container_of(p_kobj, struct module_kobject, kobj);
|
||||
if (!p_mk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p_mod = p_mk->mod;
|
||||
if (!p_mod) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_mod->state != MODULE_STATE_LIVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_mod == p_find_me) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!p_module_core(p_mod) || !p_core_text_size(p_mod)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Save pointer to the 'module_kobject' structure */
|
||||
p_arg[p_cnt].p_mk = p_mk;
|
||||
/* Save entire 'kobject' for this module */
|
||||
memcpy(&p_arg[p_cnt].kobj,p_kobj,sizeof(struct kobject));
|
||||
/* Exception */
|
||||
memset(&p_arg[p_cnt].kobj.entry,0x0,sizeof(struct list_head)); // module GOING_AWAY trobules ;(
|
||||
memset(&p_arg[p_cnt].kobj.kref,0x0,sizeof(struct kref)); // module GOING_AWAY trobules ;(
|
||||
|
||||
|
||||
/* Pointer to THIS_MODULE per module */
|
||||
p_arg[p_cnt].p_mod = p_mod;
|
||||
/* Save module name for that pointer */
|
||||
memcpy(p_arg[p_cnt].p_name,p_mod->name,MODULE_NAME_LEN);
|
||||
p_arg[p_cnt].p_name[MODULE_NAME_LEN] = 0x0;
|
||||
/* Pointer to the module core */
|
||||
p_arg[p_cnt].p_module_core = p_module_core(p_mod);
|
||||
/* Size of the module core text section */
|
||||
p_arg[p_cnt].p_core_text_size = p_core_text_size(p_mod);
|
||||
/* Calculate hash from the module core text section ;) */
|
||||
p_arg[p_cnt].p_mod_core_text_hash = p_super_fast_hash((unsigned char *)p_arg[p_cnt].p_module_core,
|
||||
(unsigned int)p_arg[p_cnt].p_core_text_size);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"[%s | %p] module_core[%p | 0x%x] hash[0x%x]\n"
|
||||
"module_kobject[%p] KOBJ: name[%s] parent[%p] kset[%p] ktype[%p] sd[%p] refcount[0x%x|%d]\n",
|
||||
p_arg[p_cnt].p_name,p_arg[p_cnt].p_mod,p_arg[p_cnt].p_module_core,
|
||||
p_arg[p_cnt].p_core_text_size,p_arg[p_cnt].p_mod_core_text_hash,
|
||||
p_arg[p_cnt].p_mk,p_arg[p_cnt].kobj.name,p_arg[p_cnt].kobj.parent,
|
||||
p_arg[p_cnt].kobj.kset,p_arg[p_cnt].kobj.ktype,p_arg[p_cnt].kobj.sd,
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
|
||||
p_arg[p_cnt].kobj.kref.refcount.counter,p_arg[p_cnt].kobj.kref.refcount.counter);
|
||||
#else
|
||||
p_arg[p_cnt].kobj.kref.refcount.refs.counter,p_arg[p_cnt].kobj.kref.refcount.refs.counter);
|
||||
#endif
|
||||
|
||||
p_cnt++;
|
||||
}
|
||||
spin_unlock(&p_kset->list_lock);
|
||||
kset_put(p_kset);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
// p_print_log(P_LKRG_CRIT,
|
||||
"Leaving function <p_list_from_sysfs_kobj> (p_cnt => %d)\n",p_cnt);
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'module_lock' must be taken by calling function!
|
||||
*/
|
||||
int p_kmod_hash(unsigned int *p_module_list_cnt_arg, p_module_list_mem **p_mlm_tmp,
|
||||
unsigned int *p_module_kobj_cnt_arg, p_module_kobj_mem **p_mkm_tmp) {
|
||||
|
||||
*p_mlm_tmp = NULL;
|
||||
*p_mkm_tmp = NULL;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_kmod_hash>\n");
|
||||
|
||||
/*
|
||||
* Originally this mutex was taken here. Unfortunately some use cases of this function
|
||||
* requires to work under global DB spinlock. Because of that calling function must take
|
||||
* 'module_mutex'
|
||||
*/
|
||||
// mutex_lock(&module_mutex);
|
||||
|
||||
*p_module_list_cnt_arg = p_count_modules_from_module_list();
|
||||
*p_module_kobj_cnt_arg = p_count_modules_from_sysfs_kobj();
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"[p_kmod_hash] %s => Found %d modules in module list and %d modules in sysfs.\n",
|
||||
(*p_module_list_cnt_arg != *p_module_kobj_cnt_arg) ? "DOESN\'T MATCH" : "MATCH",
|
||||
*p_module_list_cnt_arg,*p_module_kobj_cnt_arg);
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Allocation logic should be changed! Should preallocate memory once, and if there
|
||||
* there is not enough space, reallocate it multiplying the size, and so on... At some
|
||||
* point allocation won't happens at all since we will have enough room to always store
|
||||
* all necessary informations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OK, we now know how many modules we have in the module list
|
||||
* in this kernel, let's allocate data here...
|
||||
*
|
||||
* __GFP_NOFAIL flag will always generate slowpath warn because developers
|
||||
* decided to depreciate this flag ;/
|
||||
*
|
||||
* We are under time-critical pressure. We are going to use emergency pools
|
||||
* and we can't accept memory allocation fails. Because __GFP_NOFAIL is not
|
||||
* 'safe' flag anymore, we are spinning until allocation successes.
|
||||
*/
|
||||
if ( (*p_mlm_tmp = kzalloc(sizeof(p_module_list_mem) *
|
||||
(*p_module_list_cnt_arg+P_MODULE_BUFFER_RACE), GFP_ATOMIC)) == NULL) {
|
||||
/*
|
||||
* I should NEVER be here!
|
||||
*/
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"KMOD HASH kzalloc() error! Can't allocate memory for module list ;[\n");
|
||||
goto p_kmod_hash_err;
|
||||
}
|
||||
// STRONG_DEBUG
|
||||
else {
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_kmod_hash> p_mlm_tmp allocated at: %p with size: %zd[0x%zx]\n",
|
||||
*p_mlm_tmp,
|
||||
sizeof(p_module_list_mem) * (*p_module_list_cnt_arg+P_MODULE_BUFFER_RACE),
|
||||
sizeof(p_module_list_mem) * (*p_module_list_cnt_arg+P_MODULE_BUFFER_RACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we now know how many modules we have in the sysfs kset/kobject list
|
||||
* in this kernel, let's allocate data here...
|
||||
*
|
||||
* __GFP_NOFAIL flag will always generate slowpath warn because developers
|
||||
* decided to depreciate this flag ;/
|
||||
*
|
||||
* We are under time-critical pressure. We are going to use emergency pools
|
||||
* and we can't accept memory allocation fails. Because __GFP_NOFAIL is not
|
||||
* 'safe' flag anymore, we are spinning until allocation successes.
|
||||
*/
|
||||
if ( (*p_mkm_tmp = kzalloc(sizeof(p_module_kobj_mem) *
|
||||
(*p_module_kobj_cnt_arg+P_MODULE_BUFFER_RACE), GFP_ATOMIC)) == NULL) {
|
||||
/*
|
||||
* I should NEVER be here!
|
||||
*/
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"KMOD HASH kzalloc() error! Can't allocate memory for kobj list;[\n");
|
||||
goto p_kmod_hash_err;
|
||||
}
|
||||
// STRONG_DEBUG
|
||||
else {
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_kmod_hash> p_mkm_tmp allocated at: %p with size: %zd[0x%zx]\n",
|
||||
*p_mkm_tmp,
|
||||
sizeof(p_module_kobj_mem) * (*p_module_kobj_cnt_arg+P_MODULE_BUFFER_RACE),
|
||||
sizeof(p_module_kobj_mem) * (*p_module_kobj_cnt_arg+P_MODULE_BUFFER_RACE));
|
||||
}
|
||||
|
||||
// memset(*p_mkm_tmp,0x0,sizeof(p_module_kobj_mem) * *p_module_kobj_cnt_arg);
|
||||
// memset(*p_mlm_tmp,0x0,sizeof(p_module_list_mem) * *p_module_list_cnt_arg);
|
||||
|
||||
p_list_from_module_list(*p_mlm_tmp);
|
||||
p_list_from_sysfs_kobj(*p_mkm_tmp);
|
||||
|
||||
/*
|
||||
* Originally this mutex was taken here. Unfortunately some use cases of this function
|
||||
* requires to work under global DB spinlock. Because of that calling function must take
|
||||
* 'module_mutex'
|
||||
*/
|
||||
// mutex_unlock(&module_mutex);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_kmod_hash> (SUCCESS)\n");
|
||||
|
||||
return P_LKRG_SUCCESS;
|
||||
|
||||
p_kmod_hash_err:
|
||||
|
||||
if (*p_mlm_tmp)
|
||||
kzfree(*p_mlm_tmp);
|
||||
if (*p_mkm_tmp)
|
||||
kzfree(*p_mkm_tmp);
|
||||
|
||||
/*
|
||||
* Originally this mutex was taken here. Unfortunately some use cases of this function
|
||||
* requires to work under global DB spinlock. Because of that calling function must take
|
||||
* 'module_mutex'
|
||||
*/
|
||||
// mutex_unlock(&module_mutex);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_kmod_hash> (ERROR)\n");
|
||||
|
||||
return P_LKRG_GENERAL_ERROR;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Kernel's modules module
|
||||
*
|
||||
* Notes:
|
||||
* - Gathering information about loaded kernel modules and tries
|
||||
* to protect them via calculating hashes from their core_text
|
||||
* section.
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 09.XI.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_KERNEL_MODULES_H
|
||||
#define P_LKRG_KERNEL_MODULES_H
|
||||
|
||||
#define P_GLOBAL_TO_MODULE(x) \
|
||||
({ \
|
||||
list_entry((void *)*(long *)(*(long*)x),struct module, list); \
|
||||
})
|
||||
|
||||
#define P_MODULE_BUFFER_RACE 5
|
||||
|
||||
typedef struct p_module_list_mem {
|
||||
|
||||
struct module *p_mod;
|
||||
char p_name[MODULE_NAME_LEN+1];
|
||||
void *p_module_core;
|
||||
unsigned int p_core_text_size;
|
||||
|
||||
uint32_t p_mod_core_text_hash;
|
||||
|
||||
} p_module_list_mem;
|
||||
|
||||
|
||||
typedef struct p_module_kobj_mem {
|
||||
|
||||
struct module_kobject *p_mk;
|
||||
struct kobject kobj;
|
||||
|
||||
struct module *p_mod;
|
||||
char p_name[MODULE_NAME_LEN+1];
|
||||
void *p_module_core;
|
||||
unsigned int p_core_text_size;
|
||||
|
||||
uint32_t p_mod_core_text_hash;
|
||||
|
||||
} p_module_kobj_mem;
|
||||
|
||||
|
||||
typedef struct _p_lkrg_global_ctrl_structure {
|
||||
|
||||
unsigned int p_timestamp;
|
||||
unsigned int p_log_level;
|
||||
unsigned int p_force_run;
|
||||
unsigned int p_block_modules;
|
||||
unsigned int p_unhide_module;
|
||||
|
||||
} p_lkrg_global_ctrl_struct;
|
||||
|
||||
|
||||
extern p_lkrg_global_ctrl_struct p_lkrg_global_ctrl;
|
||||
|
||||
extern struct list_head *p_ddebug_tables;
|
||||
extern struct mutex *p_ddebug_lock;
|
||||
extern struct list_head *p_global_modules;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
extern struct mutex *p_kernfs_mutex;
|
||||
#endif
|
||||
extern struct kset **p_module_kset;
|
||||
|
||||
/* Module activity events */
|
||||
extern struct mutex p_module_activity;
|
||||
extern struct module *p_module_activity_ptr;
|
||||
|
||||
int p_block_always(void);
|
||||
|
||||
int p_kmod_init(void);
|
||||
int p_kmod_hash(unsigned int *p_module_list_cnt_arg, p_module_list_mem **p_mlm_tmp,
|
||||
unsigned int *p_module_kobj_cnt_arg, p_module_kobj_mem **p_mkm_tmp);
|
||||
void p_deregister_module_notifier(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Kernel's modules module notifier
|
||||
*
|
||||
* Notes:
|
||||
* - Register notifier function whenever there is any kernel module load/unload activity
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 16.II.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static int p_module_event_notifier(struct notifier_block *p_this, unsigned long p_event, void *p_kmod);
|
||||
static void p_module_notifier_wrapper(unsigned long p_event, struct module *p_kmod);
|
||||
|
||||
DEFINE_MUTEX(p_module_activity);
|
||||
struct module *p_module_activity_ptr;
|
||||
|
||||
static struct notifier_block p_module_block_notifier = {
|
||||
|
||||
.notifier_call = p_module_event_notifier,
|
||||
.next = NULL,
|
||||
.priority = INT_MAX
|
||||
|
||||
};
|
||||
|
||||
|
||||
static void p_module_notifier_wrapper(unsigned long p_event, struct module *p_kmod) {
|
||||
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_module_notifier_wrapper>\n");
|
||||
|
||||
if (p_lkrg_global_ctrl.p_block_modules) {
|
||||
p_kmod->init = p_block_always;
|
||||
}
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_module_notifier_wrapper>\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called when module is load/unloaded
|
||||
*
|
||||
* Kernel supports following states:
|
||||
*
|
||||
* 291 enum module_state {
|
||||
* 292 MODULE_STATE_LIVE, // Normal state.
|
||||
* 293 MODULE_STATE_COMING, // Full formed, running module_init.
|
||||
* 294 MODULE_STATE_GOING, // Going away.
|
||||
* 295 MODULE_STATE_UNFORMED, // Still setting it up.
|
||||
* 296 };
|
||||
*/
|
||||
static int p_module_event_notifier(struct notifier_block *p_this, unsigned long p_event, void *p_kmod) {
|
||||
|
||||
struct module *p_tmp = p_kmod;
|
||||
|
||||
// STRONG_DEBUG
|
||||
#ifdef P_LKRG_DEBUG
|
||||
char *p_mod_strings[] = { "New module is LIVE",
|
||||
"New module is COMING",
|
||||
"Module is GOING AWAY",
|
||||
"New module is UNFORMED yet" };
|
||||
#endif
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"[%ld | %s] "
|
||||
"Entering function <p_module_event_notifier> "
|
||||
"m[0x%p] hd[0x%p] s[0x%p] n[0x%p]\n",
|
||||
p_event,p_mod_strings[p_event],p_tmp,p_tmp->holders_dir,
|
||||
p_tmp->sect_attrs,p_tmp->notes_attrs);
|
||||
|
||||
/* Inform validation routine about active module activities... */
|
||||
mutex_lock(&p_module_activity);
|
||||
p_module_activity_ptr = p_tmp;
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"<p_module_event_notifier> !! Module activity detected [<%s>] %lu: 0x%p\n",p_mod_strings[p_event],p_event,p_kmod);
|
||||
|
||||
/*
|
||||
* If module going away, we need to rebuild our database anyway
|
||||
* It does not depends on the 'blocking' flag
|
||||
*/
|
||||
// if (p_tmp->state == MODULE_STATE_GOING) { <- Linux kernel bug - might not update state value :(
|
||||
if (p_event == MODULE_STATE_GOING) {
|
||||
|
||||
/*
|
||||
* Now recalculate modules information in database!
|
||||
* Every module must be tracked in the internal database
|
||||
* (like hash from .text section) and recalculate global module hashes...
|
||||
*
|
||||
* Because some module is going to be unloaded from the kernel
|
||||
* We must keep in track that information ;)
|
||||
*/
|
||||
|
||||
/* We are heavly consuming module list here - take 'module_mutex' */
|
||||
mutex_lock(&module_mutex);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* Hacky way of 'stopping' KOBJs activities */
|
||||
mutex_lock(p_kernfs_mutex);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* First, synchronize possible database changes with other LKRG components...
|
||||
* We want to be as fast as possible to get this lock! :)
|
||||
* Still there is small race condition window, between taking this lock, and
|
||||
* verification routine doing that. It might be critical from the perspective
|
||||
* of tracking down which modules are currently active in the system and track
|
||||
* down this information in database.
|
||||
* Imagine situation even we have active 'blocking module' functionality and some
|
||||
* random module is going to be unloaded. New event arrives, stack frame for this
|
||||
* function is created and before this operation is finished and lock will be taken
|
||||
* another CPU might already execute validation routine which will take DB lock
|
||||
* before this function will be fast enough to do it after stack frame creation.
|
||||
*
|
||||
* Don't know if there is any solution for that :)
|
||||
*
|
||||
*/
|
||||
|
||||
/* Let's play... God mode on ;) */
|
||||
spin_lock_irqsave(&p_db_lock,p_db_flags);
|
||||
|
||||
|
||||
/* First free currently used memory! */
|
||||
if (p_db.p_module_list_array)
|
||||
kzfree(p_db.p_module_list_array);
|
||||
if (p_db.p_module_kobj_array)
|
||||
kzfree(p_db.p_module_kobj_array);
|
||||
/* OK, now recalculate hashes again! */
|
||||
|
||||
while(p_kmod_hash(&p_db.p_module_list_nr,&p_db.p_module_list_array,
|
||||
&p_db.p_module_kobj_nr,&p_db.p_module_kobj_array) != P_LKRG_SUCCESS);
|
||||
|
||||
/* Update global module list/kobj hash */
|
||||
p_db.p_module_list_hash = p_super_fast_hash((unsigned char *)p_db.p_module_list_array,
|
||||
(unsigned int)p_db.p_module_list_nr * sizeof(p_module_list_mem));
|
||||
p_db.p_module_kobj_hash = p_super_fast_hash((unsigned char *)p_db.p_module_kobj_array,
|
||||
(unsigned int)p_db.p_module_kobj_nr * sizeof(p_module_kobj_mem));
|
||||
/* We should be fine now! */
|
||||
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module list' => [0x%x]\n",p_db.p_module_list_hash);
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module kobj(s)' => [0x%x]\n",p_db.p_module_kobj_hash);
|
||||
|
||||
goto p_module_event_notifier_unlock_out;
|
||||
}
|
||||
|
||||
if (p_lkrg_global_ctrl.p_block_modules) {
|
||||
// if (p_tmp->state == MODULE_STATE_COMING) { <- Linux kernel bug - might not update state value :(
|
||||
if (p_event == MODULE_STATE_COMING) {
|
||||
/* We are not going to modify DB */
|
||||
p_module_notifier_wrapper(p_event,p_tmp);
|
||||
goto p_module_event_notifier_activity_out;
|
||||
}
|
||||
} else {
|
||||
// if (p_tmp->state == MODULE_STATE_LIVE) { <- Linux kernel bug - might not update state value :(
|
||||
if (p_event == MODULE_STATE_LIVE) {
|
||||
|
||||
/*
|
||||
* Now recalculate modules information in database! Since blocking module is disabled
|
||||
* every new module must be add to the internal database, hash from .text section calculated
|
||||
* and recalculate global module hashes...
|
||||
*/
|
||||
|
||||
/* We are heavly consuming module list here - take 'module_mutex' */
|
||||
mutex_lock(&module_mutex);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* Hacky way of 'stopping' KOBJs activities */
|
||||
mutex_lock(p_kernfs_mutex);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* First, synchronize possible database changes with other LKRG components...
|
||||
* We want to be as fast as possible to get this lock! :)
|
||||
* Still there is small race condition window, between taking this lock, and
|
||||
* verification routine doing that. It might be critical from the perspective
|
||||
* of tracking down which modules are currently active in the system and track
|
||||
* down this information in database.
|
||||
* Imagine situation even we have active 'blocking module' functionality and some
|
||||
* random module is going to be unloaded. New event arrives, stack frame for this
|
||||
* function is created and before this operation is finished and lock will be taken
|
||||
* another CPU might already execute validation routine which will take DB lock
|
||||
* before this function will be fast enough to do it after stack frame creation.
|
||||
*
|
||||
* Don't know if there is any solution for that :)
|
||||
*
|
||||
*/
|
||||
spin_lock_irqsave(&p_db_lock,p_db_flags);
|
||||
|
||||
/* First free currently used memory! */
|
||||
if (p_db.p_module_list_array)
|
||||
kzfree(p_db.p_module_list_array);
|
||||
if (p_db.p_module_kobj_array)
|
||||
kzfree(p_db.p_module_kobj_array);
|
||||
/* OK, now recalculate hashes again! */
|
||||
|
||||
while(p_kmod_hash(&p_db.p_module_list_nr,&p_db.p_module_list_array,
|
||||
&p_db.p_module_kobj_nr,&p_db.p_module_kobj_array) != P_LKRG_SUCCESS);
|
||||
|
||||
/* Update global module list/kobj hash */
|
||||
p_db.p_module_list_hash = p_super_fast_hash((unsigned char *)p_db.p_module_list_array,
|
||||
(unsigned int)p_db.p_module_list_nr * sizeof(p_module_list_mem));
|
||||
p_db.p_module_kobj_hash = p_super_fast_hash((unsigned char *)p_db.p_module_kobj_array,
|
||||
(unsigned int)p_db.p_module_kobj_nr * sizeof(p_module_kobj_mem));
|
||||
/* We should be fine now! */
|
||||
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module list' => [0x%x]\n",p_db.p_module_list_hash);
|
||||
p_print_log(P_LKRG_INFO,"Hash from 'module kobj(s)' => [0x%x]\n",p_db.p_module_kobj_hash);
|
||||
|
||||
goto p_module_event_notifier_unlock_out;
|
||||
}
|
||||
}
|
||||
|
||||
goto p_module_event_notifier_activity_out;
|
||||
|
||||
p_module_event_notifier_unlock_out:
|
||||
|
||||
/* God mode off ;) */
|
||||
spin_unlock_irqrestore(&p_db_lock,p_db_flags);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
||||
/* unlock KOBJ activities */
|
||||
mutex_unlock(p_kernfs_mutex);
|
||||
#endif
|
||||
/* Release the 'module_mutex' */
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
p_module_event_notifier_activity_out:
|
||||
|
||||
/* Inform validation routine about active module activities... */
|
||||
mutex_unlock(&p_module_activity);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_module_event_notifier>\n");
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
int p_block_always(void) {
|
||||
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"!! Module insertion blocked (from always!) !!\n");
|
||||
|
||||
return P_LKRG_GENERAL_ERROR;
|
||||
|
||||
}
|
||||
|
||||
void p_register_module_notifier(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"<p_register_module_notifier> Registering module's noitifier routine\n");
|
||||
|
||||
register_module_notifier(&p_module_block_notifier);
|
||||
|
||||
}
|
||||
|
||||
void p_deregister_module_notifier(void) {
|
||||
|
||||
unregister_module_notifier(&p_module_block_notifier);
|
||||
// printk("Goodbye ;)\n");
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Kernel's modules module wrapping access to 'struct module'
|
||||
*
|
||||
* Notes:
|
||||
* - Since kernel 4.5 'struct module' was changed. Accessing some critical
|
||||
* variables must be more 'smart' now. We are wrapping necessary fields here.
|
||||
*
|
||||
* http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/diff/include/linux/module.h?id=7523e4dc5057
|
||||
*
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 16.V.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 6)
|
||||
|
||||
|
||||
static inline void *p_module_core(struct module *p_mod) {
|
||||
return p_mod->core_layout.base;
|
||||
}
|
||||
|
||||
static inline unsigned int p_core_size(struct module *p_mod) {
|
||||
return p_mod->core_layout.size;
|
||||
}
|
||||
|
||||
static inline unsigned int p_core_text_size(struct module *p_mod) {
|
||||
return p_mod->core_layout.text_size;
|
||||
}
|
||||
|
||||
static inline unsigned int p_init_text_size(struct module *p_mod) {
|
||||
return p_mod->init_layout.text_size;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
static inline void *p_module_core(struct module *p_mod) {
|
||||
return p_mod->module_core;
|
||||
}
|
||||
|
||||
static inline unsigned int p_init_text_size(struct module *p_mod) {
|
||||
return p_mod->init_text_size;
|
||||
}
|
||||
|
||||
static inline unsigned int p_core_text_size(struct module *p_mod) {
|
||||
return p_mod->core_text_size;
|
||||
}
|
||||
|
||||
static inline unsigned int p_core_size(struct module *p_mod) {
|
||||
return p_mod->core_size;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Resolve kernel symbols
|
||||
*
|
||||
* Notes:
|
||||
* - We try to 'resolve' old-school Linux kernel function for
|
||||
* resolving symbols on run-time
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
unsigned long (*p_kallsyms_lookup_name)(const char *name) = 0x0;
|
||||
|
||||
|
||||
static int p_lookup_syms_hack(void *unused, const char *name,
|
||||
struct module *mod, unsigned long addr) {
|
||||
|
||||
if (strcmp("kallsyms_lookup_name", name) == 0x0) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
long get_kallsyms_address(void) {
|
||||
|
||||
int p_tmp = 0x0;
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <get_kallsyms_address>\n");
|
||||
|
||||
if ( (p_tmp = kallsyms_on_each_symbol(p_lookup_syms_hack,NULL)) == 0x0) {
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"kallsyms_on_each_symbol error :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto get_kallsyms_address_out;
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
p_debug_log(P_LKRG_DBG,
|
||||
"kallsyms_on_each_symbol() returned => 0x%x\n",p_tmp);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
p_kallsyms_lookup_name = (unsigned long (*)(const char*)) (0xFFFFFFFF00000000 | p_tmp);
|
||||
#else
|
||||
p_kallsyms_lookup_name = (unsigned long (*)(const char*)) (p_tmp);
|
||||
#endif
|
||||
|
||||
get_kallsyms_address_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <get_kallsyms_address> (p_ret => %d)\n",p_ret);
|
||||
|
||||
return P_LKRG_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Resolve kernel symbols
|
||||
*
|
||||
* Notes:
|
||||
* - We try to 'resolve' old-school Linux kernel function for
|
||||
* resolving symbols on run-time
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_RESOLVE_KSYM_H
|
||||
#define P_LKRG_RESOLVE_KSYM_H
|
||||
|
||||
extern unsigned long (*p_kallsyms_lookup_name)(const char *name);
|
||||
|
||||
long get_kallsyms_address(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Notifiers module
|
||||
*
|
||||
* Notes:
|
||||
* - Register multiple notifiers routines for integrity checking
|
||||
* - Unfortunately, since Linux 4.10 there isn't idle notifier anymore :(
|
||||
* Integrity check fired on idle state won't work in newer kernels.
|
||||
* More information can be found here:
|
||||
* => https://patchwork.kernel.org/patch/9435797/
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 30.X.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
static int p_idle_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static int p_freq_transition_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
#endif
|
||||
static int p_cpu_pm_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_netdevice_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_netevent_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static int p_inet6addr_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
#endif
|
||||
static int p_inetaddr_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_taskfree_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_profile_event_exit_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_profile_event_munmap_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_usb_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
static int p_acpi_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data);
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
static struct notifier_block p_idle_notifier_nb = {
|
||||
.notifier_call = p_idle_notifier,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static struct notifier_block p_freq_transition_nb = {
|
||||
.notifier_call = p_freq_transition_notifier,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct notifier_block p_cpu_pm_notifier_nb = {
|
||||
.notifier_call = p_cpu_pm_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_netdevice_notifier_nb = {
|
||||
.notifier_call = p_netdevice_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_netevent_notifier_nb = {
|
||||
.notifier_call = p_netevent_notifier,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static struct notifier_block p_inet6addr_notifier_nb = {
|
||||
.notifier_call = p_inet6addr_notifier,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct notifier_block p_inetaddr_notifier_nb = {
|
||||
.notifier_call = p_inetaddr_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_taskfree_notifier_nb = {
|
||||
.notifier_call = p_taskfree_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_profile_event_exit_notifier_nb = {
|
||||
.notifier_call = p_profile_event_exit_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_profile_event_munmap_notifier_nb = {
|
||||
.notifier_call = p_profile_event_munmap_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_usb_notifier_nb = {
|
||||
.notifier_call = p_usb_notifier,
|
||||
};
|
||||
|
||||
static struct notifier_block p_acpi_notifier_nb = {
|
||||
.notifier_call = p_acpi_notifier,
|
||||
};
|
||||
|
||||
|
||||
void p_register_notifiers(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_register_notifiers>\n");
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
idle_notifier_register(&p_idle_notifier_nb);
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
cpufreq_register_notifier(&p_freq_transition_nb, CPUFREQ_TRANSITION_NOTIFIER);
|
||||
#endif
|
||||
cpu_pm_register_notifier(&p_cpu_pm_notifier_nb);
|
||||
register_netdevice_notifier(&p_netdevice_notifier_nb);
|
||||
register_netevent_notifier(&p_netevent_notifier_nb);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
register_inet6addr_notifier(&p_inet6addr_notifier_nb);
|
||||
#endif
|
||||
register_inetaddr_notifier(&p_inetaddr_notifier_nb);
|
||||
task_handoff_register(&p_taskfree_notifier_nb);
|
||||
profile_event_register(PROFILE_TASK_EXIT, &p_profile_event_exit_notifier_nb);
|
||||
profile_event_register(PROFILE_MUNMAP, &p_profile_event_munmap_notifier_nb);
|
||||
usb_register_notify(&p_usb_notifier_nb);
|
||||
register_acpi_notifier(&p_acpi_notifier_nb);
|
||||
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_register_notifiers>\n");
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
static int p_idle_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_idle_notifier>\n");
|
||||
|
||||
/* 0.005% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_M_SS_MORE_OFTEN_RATE, "<p_idle_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_idle_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static int p_freq_transition_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_freq_transition_notifier>\n");
|
||||
|
||||
/* 10% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_RARE_RATE, "<p_freq_transition_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_freq_transition_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int p_cpu_pm_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_cpu_pm_notifier>\n");
|
||||
|
||||
/* 10% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_RARE_RATE, "<p_cpu_pm_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_cpu_pm_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_netdevice_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_netdevice_notifier>\n");
|
||||
|
||||
/* 1% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_OFTEN_RATE, "<p_netdevice_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_netdevice_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_netevent_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_netevent_notifier>\n");
|
||||
|
||||
/* 5% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_LESS_RARE_RATE, "<p_netevent_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_netevent_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static int p_inet6addr_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_inet6addr_notifier>\n");
|
||||
|
||||
/* 50% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_SUPER_RARE_RATE, "<p_inet6addr_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_inet6addr_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int p_inetaddr_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_inetaddr_notifier>\n");
|
||||
|
||||
/* 50% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_SUPER_RARE_RATE, "<p_inetaddr_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_inetaddr_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_taskfree_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_taskfree_notifier>\n");
|
||||
|
||||
/* 0.01% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_SS_MORE_OFTEN_RATE, "<p_taskfree_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_taskfree_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_profile_event_exit_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_profile_event_exit_notifier>\n");
|
||||
|
||||
/* 0.01% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_SS_MORE_OFTEN_RATE, "<p_profile_event_exit_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_profile_event_exit_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_profile_event_munmap_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_profile_event_munmap_notifier>\n");
|
||||
|
||||
/* 0.005%*/
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_M_SS_MORE_OFTEN_RATE, "<p_profile_event_munmap_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_profile_event_munmap_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_usb_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_usb_notifier>\n");
|
||||
|
||||
/* 50% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_SUPER_RARE_RATE, "<p_usb_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_usb_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static int p_acpi_notifier(struct notifier_block *p_nb, unsigned long p_val, void *p_data) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Entering function <p_acpi_notifier>\n");
|
||||
|
||||
/* 50% */
|
||||
P_TRY_OFFLOAD_NOTIFIER(P_SUPER_RARE_RATE, "<p_acpi_notifier> Offloading integrity check\n");
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_notifier_log(
|
||||
"Leaving function <p_acpi_notifier>\n");
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
void p_deregister_notifiers(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_deregister_notifiers>\n");
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
idle_notifier_unregister(&p_idle_notifier_nb);
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
cpufreq_unregister_notifier(&p_freq_transition_nb, CPUFREQ_TRANSITION_NOTIFIER);
|
||||
#endif
|
||||
cpu_pm_unregister_notifier(&p_cpu_pm_notifier_nb);
|
||||
unregister_netdevice_notifier(&p_netdevice_notifier_nb);
|
||||
unregister_netevent_notifier(&p_netevent_notifier_nb);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unregister_inet6addr_notifier(&p_inet6addr_notifier_nb);
|
||||
#endif
|
||||
unregister_inetaddr_notifier(&p_inetaddr_notifier_nb);
|
||||
task_handoff_unregister(&p_taskfree_notifier_nb);
|
||||
profile_event_unregister(PROFILE_TASK_EXIT, &p_profile_event_exit_notifier_nb);
|
||||
profile_event_unregister(PROFILE_MUNMAP, &p_profile_event_munmap_notifier_nb);
|
||||
usb_unregister_notify(&p_usb_notifier_nb);
|
||||
unregister_acpi_notifier(&p_acpi_notifier_nb);
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_deregister_notifiers>\n");
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Notifiers module
|
||||
*
|
||||
* Notes:
|
||||
* - Register multiple notifiers routines for integrity checking
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 30.X.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_NOTIFIERS_MODULE_H
|
||||
#define P_LKRG_NOTIFIERS_MODULE_H
|
||||
|
||||
/* MAX unsigned int 4294967295 */
|
||||
//#define P_OFTEN_RATE 5000000
|
||||
//#define P_SUPER_OFTEN_RATE 250000
|
||||
//#define P_RARE_RATE 80000000
|
||||
//#define P_SUPER_RARE_RATE 3000000000
|
||||
|
||||
#define P_SUPER_RARE_RATE 2147483647 /* 50% */
|
||||
#define P_RARE_RATE 429496729 /* 10% */
|
||||
#define P_LESS_RARE_RATE 214748364 /* 5% */
|
||||
#define P_OFTEN_RATE 42949672 /* 1% */
|
||||
#define P_MORE_OFTEN_RATE 21474836 /* 0.5% */
|
||||
#define P_M_MORE_OFTEN_RATE 4294967 /* 0.1% */
|
||||
#define P_S_MORE_OFTEN_RATE 2147483 /* 0.05% */
|
||||
#define P_SS_MORE_OFTEN_RATE 429496 /* 0.01% */
|
||||
#define P_M_SS_MORE_OFTEN_RATE 21474 /* 0.005% */
|
||||
#define P_S_SS_MORE_OFTEN_RATE 42949 /* 0.001% */
|
||||
|
||||
#define P_CHECK_RANDOM(x) ({ (get_random_int() < x) ? 1 : 0; })
|
||||
|
||||
#ifdef P_LKRG_DEBUG
|
||||
#define P_TRY_OFFLOAD_NOTIFIER(p_arg1, p_arg2) \
|
||||
do { \
|
||||
if (P_CHECK_RANDOM(p_arg1)) { \
|
||||
p_print_log(P_LKRG_DBG, "%s", p_arg2); \
|
||||
p_offload_work(0); \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define P_TRY_OFFLOAD_NOTIFIER(p_arg1, p_arg2) \
|
||||
do { \
|
||||
if (P_CHECK_RANDOM(p_arg1)) { \
|
||||
p_offload_work(0); \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
|
||||
void p_register_notifiers(void);
|
||||
void p_deregister_notifiers(void);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Log level definitions
|
||||
*
|
||||
* Notes:
|
||||
* - Log level definitions shared with user-mode client
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 31.III.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_LOG_LEVEL_SHARED_H
|
||||
#define P_LKRG_LOG_LEVEL_SHARED_H
|
||||
|
||||
|
||||
/*
|
||||
* Debugging definitions...
|
||||
*/
|
||||
|
||||
// Do we want to provide debug information?
|
||||
#define P_LKRG_DEBUG
|
||||
|
||||
// Debug every time we enter/exit notifiers function?
|
||||
// not recommended - will be too noisy for some notifiers! :)
|
||||
//#define P_LKRG_NOTIFIER_DBG
|
||||
|
||||
// Debug every time we enter/exit *kprobed* function?
|
||||
// not recommended - will be very noisy...
|
||||
//#define P_LKRG_STRONG_KPROBE_DEBUG
|
||||
|
||||
enum P_LOG_LEVELS {
|
||||
|
||||
P_LOG_LEVEL_NONE,
|
||||
P_LOG_LEVEL_ALIVE,
|
||||
P_LOG_LEVEL_ERRORS,
|
||||
P_LOG_LEVEL_WARNS,
|
||||
P_LOG_LEVEL_INFOS,
|
||||
|
||||
#ifdef P_LKRG_DEBUG
|
||||
|
||||
P_LOG_LEVEL_DBG,
|
||||
P_LOG_LEVEL_STRONG_DBG,
|
||||
|
||||
#endif
|
||||
|
||||
P_LOG_LEVEL_MAX
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Error module
|
||||
*
|
||||
* Notes:
|
||||
* - Error code definitions
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_PRINT_LOG_H
|
||||
#define P_LKRG_PRINT_LOG_H
|
||||
|
||||
#include "p_lkrg_log_level_shared.h"
|
||||
|
||||
// Everything is fine...
|
||||
#define P_LKRG_SUCCESS 0x0
|
||||
|
||||
// General error
|
||||
#define P_LKRG_GENERAL_ERROR -1
|
||||
|
||||
// Can't find (resolve) "kallsyms_lookup_name" function
|
||||
#define P_LKRG_RESOLVER_ERROR -100
|
||||
|
||||
// Can't initialize kmod module
|
||||
#define P_LKRG_KMOD_ERROR -101
|
||||
|
||||
// Can't generate database - hashes
|
||||
#define P_LKRG_DATABASE_ERROR -102
|
||||
|
||||
// Can't initialize protected features
|
||||
#define P_LKRG_PROTECTED_FEATURES_ERROR -103
|
||||
|
||||
// Can't register hot CPU plug[in/out] handler
|
||||
#define P_LKRG_HPCPU_ERROR -104
|
||||
|
||||
// Can't register hot CPU plug[in/out] handler
|
||||
#define P_LKRG_EXPLOIT_DETECTION_ERROR -105
|
||||
|
||||
// Enable hash from IOMMU table? - not recommended!
|
||||
// By default disabled
|
||||
//#define P_LKRG_IOMMU_HASH_ENABLED
|
||||
|
||||
// Signature in logs...
|
||||
#define P_LKRG_SIGNATURE "[p_lkrg] "
|
||||
|
||||
//#define P_LKRG_PRINT __P_LKRG_CRIT
|
||||
|
||||
#define P_LKRG_ALIVE 1
|
||||
#define P_LKRG_CRIT 2
|
||||
#define P_LKRG_ERR 3
|
||||
#define P_LKRG_WARN 4
|
||||
#define P_LKRG_INFO 5
|
||||
|
||||
#define P_LKRG_DBG 6
|
||||
#define P_LKRG_STRONG_DBG 7
|
||||
|
||||
|
||||
#define __P_LKRG_CRIT KERN_CRIT
|
||||
#define __P_LKRG_ERR KERN_ERR
|
||||
#define __P_LKRG_WARN KERN_WARNING
|
||||
#define __P_LKRG_INFO KERN_INFO
|
||||
|
||||
#define __P_LKRG_ALIVE __P_LKRG_CRIT
|
||||
|
||||
#define __P_LKRG_DBG KERN_ALERT
|
||||
#define __P_LKRG_STRONG_DBG __P_LKRG_DBG
|
||||
|
||||
|
||||
/*
|
||||
#ifdef P_LKRG_DEBUG
|
||||
|
||||
#define p_print_log(p_level, p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_level == P_LKRG_CRIT) { \
|
||||
p_print_ret = p_print_crit(__P_LKRG_CRIT P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_ALIVE) { \
|
||||
p_print_ret = p_print_alive(__P_LKRG_ALIVE P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_ERR) { \
|
||||
p_print_ret = p_print_err(__P_LKRG_ERR P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_WARN) { \
|
||||
p_print_ret = p_print_warn(__P_LKRG_WARN P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_INFO) { \
|
||||
p_print_ret = p_print_info(__P_LKRG_INFO P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_DBG) { \
|
||||
p_print_ret = p_print_dbg(__P_LKRG_DBG P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_STRONG_DBG) { \
|
||||
p_print_ret = p_print_dbg2(__P_LKRG_STRONG_DBG P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
|
||||
#else
|
||||
*/
|
||||
#define p_print_log(p_level, p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_level == P_LKRG_CRIT) { \
|
||||
p_print_ret = p_print_crit(__P_LKRG_CRIT P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_ALIVE) { \
|
||||
p_print_ret = p_print_alive(__P_LKRG_ALIVE P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_ERR) { \
|
||||
p_print_ret = p_print_err(__P_LKRG_ERR P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_WARN) { \
|
||||
p_print_ret = p_print_warn(__P_LKRG_WARN P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_INFO) { \
|
||||
p_print_ret = p_print_info(__P_LKRG_INFO P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
//#endif
|
||||
|
||||
|
||||
|
||||
#define p_print_crit(p_fmt, p_args...) \
|
||||
({ \
|
||||
printk(p_fmt, ## p_args); \
|
||||
})
|
||||
|
||||
#define p_print_alive(p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_lkrg_global_ctrl.p_log_level >= P_LOG_LEVEL_ALIVE) { \
|
||||
p_print_ret = printk(p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
#define p_print_err(p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_lkrg_global_ctrl.p_log_level >= P_LOG_LEVEL_ERRORS) { \
|
||||
p_print_ret = printk(p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
#define p_print_warn(p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_lkrg_global_ctrl.p_log_level >= P_LOG_LEVEL_WARNS) { \
|
||||
p_print_ret = printk(p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
#define p_print_info(p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_lkrg_global_ctrl.p_log_level >= P_LOG_LEVEL_INFOS) { \
|
||||
p_print_ret = printk(p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
|
||||
#ifdef P_LKRG_DEBUG
|
||||
|
||||
#ifdef P_LKRG_NOTIFIER_DBG
|
||||
#define p_debug_notifier_log(p_fmt, p_args...) \
|
||||
p_debug_log(P_LKRG_STRONG_DBG, p_fmt, ## p_args)
|
||||
#else
|
||||
#define p_debug_notifier_log(p_fmt, p_args...) ({ 0x0; })
|
||||
#endif
|
||||
|
||||
#ifdef P_LKRG_STRONG_KPROBE_DEBUG
|
||||
#define p_debug_kprobe_log(p_fmt, p_args...) \
|
||||
p_debug_log(P_LKRG_STRONG_DBG, p_fmt, ## p_args)
|
||||
#else
|
||||
#define p_debug_kprobe_log(p_fmt, p_args...) ({ 0x0; })
|
||||
#endif
|
||||
|
||||
#define p_debug_log(p_level, p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_level == P_LKRG_DBG) { \
|
||||
p_print_ret = p_print_dbg(__P_LKRG_DBG P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} else if (p_level == P_LKRG_STRONG_DBG) { \
|
||||
p_print_ret = p_print_dbg2(__P_LKRG_STRONG_DBG P_LKRG_SIGNATURE p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
#define p_print_dbg(p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_lkrg_global_ctrl.p_log_level >= P_LOG_LEVEL_DBG) { \
|
||||
p_print_ret = printk(p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
#define p_print_dbg2(p_fmt, p_args...) \
|
||||
({ \
|
||||
int p_print_ret = 0x0; \
|
||||
\
|
||||
if (p_lkrg_global_ctrl.p_log_level >= P_LOG_LEVEL_STRONG_DBG) { \
|
||||
p_print_ret = printk(p_fmt, ## p_args); \
|
||||
} \
|
||||
\
|
||||
p_print_ret; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#define p_debug_log(p_level, p_fmt, p_args...) ({ 0x0; })
|
||||
|
||||
#define p_print_dbg(p_fmt, p_args...) ({ 0x0; })
|
||||
#define p_print_dbg2(p_fmt, p_args...) ({ 0x0; })
|
||||
|
||||
#define p_debug_notifier_log(p_fmt, p_args...) ({ 0x0; })
|
||||
#define p_debug_kprobe_log(p_fmt, p_args...) ({ 0x0; })
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - (Un)Hiding module
|
||||
*
|
||||
* Notes:
|
||||
* - (Un)Hide itself from the module system activity components
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 10.XI.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../p_lkrg_main.h"
|
||||
|
||||
struct module *p_find_me = THIS_MODULE;
|
||||
/*
|
||||
struct kobject *p_find_kobj_parent;
|
||||
struct module_sect_attrs *p_find_sect_attrs;
|
||||
struct module_notes_attrs *p_find_notes_attrs;
|
||||
*/
|
||||
|
||||
|
||||
void p_hide_itself(void) {
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_hide_itself>\n");
|
||||
|
||||
if (!p_lkrg_global_ctrl.p_unhide_module) {
|
||||
p_print_log(P_LKRG_WARN,
|
||||
"Module is already hidden!\n");
|
||||
goto p_hide_itself_out;
|
||||
}
|
||||
|
||||
/*
|
||||
p_find_kobj_parent = p_find_me->mkobj.kobj.parent;
|
||||
p_find_sect_attrs = p_find_me->sect_attrs;
|
||||
p_find_notes_attrs = p_find_me->notes_attrs;
|
||||
*/
|
||||
|
||||
P_HIDE_FROM_MODULE_LIST(p_find_me);
|
||||
P_HIDE_FROM_KOBJ(p_find_me);
|
||||
P_HIDE_FROM_DDEBUG(p_find_me);
|
||||
|
||||
p_lkrg_global_ctrl.p_unhide_module = 0x0;
|
||||
|
||||
p_hide_itself_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_hide_itself>\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef P_LKRG_UNHIDE
|
||||
void p_unhide_itself(void) {
|
||||
|
||||
/* Dead function - used only during development process */
|
||||
struct module *p_tmp_mod = P_GLOBAL_TO_MODULE(p_global_modules);
|
||||
struct kset *p_tmp_kset = p_tmp_mod->mkobj.kobj.kset;
|
||||
struct kobj_type *p_tmp_ktype = p_tmp_mod->mkobj.kobj.ktype;
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Entering function <p_unhide_itself>\n");
|
||||
|
||||
if (p_lkrg_global_ctrl.p_unhide_module) {
|
||||
p_print_log(P_LKRG_WARN,
|
||||
"Module is already unhidden (visible)!\n");
|
||||
goto p_unhide_itself_out;
|
||||
}
|
||||
|
||||
P_UNHIDE_FROM_MODULE_LIST(p_find_me,p_global_modules);
|
||||
P_UNHIDE_FROM_KOBJ(p_find_me,p_tmp_kset,p_tmp_ktype);
|
||||
|
||||
// P_UNHIDE_FROM_KOBJ(p_find_me,p_find_kobj_parent,
|
||||
// p_find_sect_attrs,p_find_notes_attrs);
|
||||
|
||||
p_lkrg_global_ctrl.p_unhide_module = 0x1;
|
||||
|
||||
p_unhide_itself_out:
|
||||
|
||||
// STRONG_DEBUG
|
||||
p_debug_log(P_LKRG_STRONG_DBG,
|
||||
"Leaving function <p_unhide_itself>\n");
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - (Un)Hiding module
|
||||
*
|
||||
* Notes:
|
||||
* - (Un)Hide itself from the module system activity components
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 10.XI.2016
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_HIDING_MODULE_H
|
||||
#define P_LKRG_HIDING_MODULE_H
|
||||
|
||||
#define P_HIDE_FROM_MODULE_LIST(p_arg) \
|
||||
do { \
|
||||
p_debug_log(P_LKRG_DBG, "Hiding module [%s | %p]\n", \
|
||||
p_arg->name,p_arg); \
|
||||
list_del(&p_arg->list); \
|
||||
/* p_arg->list.next->prev = p_arg->list.prev; */ \
|
||||
/* p_arg->list.prev->next = p_arg->list.next; */ \
|
||||
} while(0)
|
||||
|
||||
#define P_HIDE_FROM_KOBJ(p_arg) \
|
||||
do { \
|
||||
if (p_arg->holders_dir && p_arg->holders_dir->parent) { \
|
||||
p_debug_log(P_LKRG_DBG, "Deleting KOBJ [%p]\n", \
|
||||
p_arg->holders_dir->parent); \
|
||||
kobject_del(p_arg->holders_dir->parent); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
#define P_HIDE_FROM_KOBJ(p_arg) \
|
||||
do { \
|
||||
p_debug_log(P_LKRG_DBG, "Deleting KOBJ [%p]\n", \
|
||||
&p_arg->mkobj.kobj); \
|
||||
kobject_del(&p_arg->mkobj.kobj); \
|
||||
p_arg->sect_attrs = NULL; \
|
||||
p_arg->notes_attrs = NULL; \
|
||||
} while(0)
|
||||
*/
|
||||
|
||||
#define P_HIDE_FROM_DDEBUG(p_arg) \
|
||||
do { \
|
||||
p_debug_log(P_LKRG_DBG, \
|
||||
"Deleting ddebug information for module [%s]\n", \
|
||||
p_arg->name); \
|
||||
ddebug_remove_module(p_arg->name); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#ifdef P_LKRG_UNHIDE // (p_find_me, p_global_modules)
|
||||
|
||||
#define P_UNHIDE_FROM_MODULE_LIST(x, y) \
|
||||
do { \
|
||||
p_debug_log(P_LKRG_DBG, "Unhiding module [%s | %p]\n", \
|
||||
x->name,x); \
|
||||
list_add_rcu(&x->list, y); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define P_UNHIDE_FROM_KOBJ(p_mod,p_kset,p_ktype) \
|
||||
do { \
|
||||
/* struct kobject *p_kobj; */ \
|
||||
struct module_use *p_use; \
|
||||
int p_tmp; \
|
||||
p_debug_log(P_LKRG_DBG, "Creating KOBJ for [%s]\n", \
|
||||
p_mod->name); \
|
||||
/* p_kobj = kset_find_obj(p_kset, p_mod->name); \
|
||||
if (p_kobj) { \
|
||||
p_debug_log(P_LKRG_DBG, "Module [%s] is NOT hidden!\n", \
|
||||
p_mod->name); \
|
||||
kobject_put(p_kobj); \
|
||||
return; \
|
||||
} */ \
|
||||
p_mod->mkobj.mod = p_mod; \
|
||||
memset(&p_mod->mkobj.kobj, 0, sizeof(p_mod->mkobj.kobj)); \
|
||||
p_mod->mkobj.kobj.kset = p_kset; \
|
||||
if (kobject_init_and_add(&p_mod->mkobj.kobj, p_ktype, NULL, \
|
||||
"%s", p_mod->name)) { \
|
||||
p_debug_log(P_LKRG_DBG, "FAILED :(\n"); \
|
||||
return; \
|
||||
} \
|
||||
p_mod->holders_dir = kobject_create_and_add("holders", \
|
||||
&p_mod->mkobj.kobj); \
|
||||
if (!p_mod->holders_dir) { \
|
||||
p_debug_log(P_LKRG_DBG, "FAILED :(\n"); \
|
||||
return; \
|
||||
} \
|
||||
if ( (p_tmp = sysfs_create_files(&p_mod->mkobj.kobj, \
|
||||
(const struct attribute **)&p_mod->modinfo_attrs)) != 0) { \
|
||||
p_debug_log(P_LKRG_DBG, "FAILED :(\n"); \
|
||||
return; \
|
||||
} \
|
||||
/* add_usage_links() */ \
|
||||
list_for_each_entry(p_use, &p_mod->target_list, target_list) { \
|
||||
p_tmp = sysfs_create_link(p_use->target->holders_dir, \
|
||||
&p_mod->mkobj.kobj, p_mod->name); \
|
||||
} \
|
||||
/* Created KOBJ for this module is very 'synthetic'. */ \
|
||||
/* During unloading module process, sysfs is heavly */ \
|
||||
/* Influenced. Some of the operations is dangerous if */ \
|
||||
/* Operated on 'syntethic' objects. To avoid crashes */ \
|
||||
/* And limit 'sysfs interaction' let's NULL some of */ \
|
||||
/* Critical 'information' pointers :) */ \
|
||||
p_mod->notes_attrs = NULL; \
|
||||
p_mod->sect_attrs = NULL; \
|
||||
kobject_uevent(&p_mod->mkobj.kobj, KOBJ_ADD); \
|
||||
p_debug_log(P_LKRG_DBG, "SUCCESS :)\n"); \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
#define P_UNHIDE_FROM_KOBJ(p_mod,p_kobj_parent,p_sect,p_notes) \
|
||||
do { \
|
||||
int p_ret; \
|
||||
\
|
||||
p_debug_log(P_LKRG_DBG, "Reestoring KOBJ[0x%p] for [%s]\n", \
|
||||
&p_mod->mkobj.kobj,p_mod->name); \
|
||||
if ( (p_ret = kobject_add(&p_mod->mkobj.kobj, p_kobj_parent, \
|
||||
"p_lkrg")) < 0) { \
|
||||
p_print_log(P_LKRG_INFO, "FAILED to restore KOBJ :(\n"); \
|
||||
return; \
|
||||
} \
|
||||
p_mod->sect_attrs = p_sect; \
|
||||
p_mod->notes_attrs = p_notes; \
|
||||
} while(0)
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
extern struct module *p_find_me;
|
||||
|
||||
void p_hide_itself(void);
|
||||
#ifdef P_LKRG_UNHIDE
|
||||
void p_unhide_itself(void);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Kernel's modules module wrapping access to some critical structures
|
||||
*
|
||||
* Notes:
|
||||
* - Wrapping some of the critical structures in the system e.g.:
|
||||
* -> k[g/u]id_t
|
||||
* -> accesing 'struct module' structure
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 11.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../p_lkrg_main.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
||||
|
||||
inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {
|
||||
p_arg->val = p_val;
|
||||
}
|
||||
|
||||
inline unsigned int p_get_uid(const kuid_t *p_from) {
|
||||
return p_from->val;
|
||||
}
|
||||
|
||||
inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {
|
||||
p_arg->val = p_val;
|
||||
}
|
||||
|
||||
inline unsigned int p_get_gid(const kgid_t *p_from) {
|
||||
return p_from->val;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS
|
||||
|
||||
inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {
|
||||
p_arg->val = p_val;
|
||||
}
|
||||
|
||||
inline unsigned int p_get_uid(const kuid_t *p_from) {
|
||||
return p_from->val;
|
||||
}
|
||||
|
||||
inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {
|
||||
p_arg->val = p_val;
|
||||
}
|
||||
|
||||
inline unsigned int p_get_gid(const kgid_t *p_from) {
|
||||
return p_from->val;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {
|
||||
*p_arg = p_val;
|
||||
}
|
||||
|
||||
inline unsigned int p_get_uid(const kuid_t *p_from) {
|
||||
return *p_from;
|
||||
}
|
||||
|
||||
inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {
|
||||
*p_arg = p_val;
|
||||
}
|
||||
|
||||
inline unsigned int p_get_gid(const kgid_t *p_from) {
|
||||
return *p_from;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 6)
|
||||
|
||||
|
||||
inline void *p_module_core(struct module *p_mod) {
|
||||
return p_mod->core_layout.base;
|
||||
}
|
||||
|
||||
inline unsigned int p_core_size(struct module *p_mod) {
|
||||
return p_mod->core_layout.size;
|
||||
}
|
||||
|
||||
inline unsigned int p_core_text_size(struct module *p_mod) {
|
||||
return p_mod->core_layout.text_size;
|
||||
}
|
||||
|
||||
inline unsigned int p_init_text_size(struct module *p_mod) {
|
||||
return p_mod->init_layout.text_size;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
inline void *p_module_core(struct module *p_mod) {
|
||||
return p_mod->module_core;
|
||||
}
|
||||
|
||||
inline unsigned int p_init_text_size(struct module *p_mod) {
|
||||
return p_mod->init_text_size;
|
||||
}
|
||||
|
||||
inline unsigned int p_core_text_size(struct module *p_mod) {
|
||||
return p_mod->core_text_size;
|
||||
}
|
||||
|
||||
inline unsigned int p_core_size(struct module *p_mod) {
|
||||
return p_mod->core_size;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Kernel's modules module wrapping access to some critical structures
|
||||
*
|
||||
* Notes:
|
||||
* - Wrapping some of the critical structures in the system e.g.:
|
||||
* -> k[g/u]id_t
|
||||
* -> accesing 'struct module' structure
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 11.IX.2017
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_WRAPPER_H
|
||||
#define P_LKRG_WRAPPER_H
|
||||
|
||||
inline void p_set_uid(kuid_t *p_arg, unsigned int p_val);
|
||||
inline unsigned int p_get_uid(const kuid_t *p_from);
|
||||
inline void p_set_gid(kgid_t *p_arg, unsigned int p_val);
|
||||
inline unsigned int p_get_gid(const kgid_t *p_from);
|
||||
|
||||
inline void *p_module_core(struct module *p_mod);
|
||||
inline unsigned int p_core_size(struct module *p_mod);
|
||||
inline unsigned int p_core_text_size(struct module *p_mod);
|
||||
inline unsigned int p_init_text_size(struct module *p_mod);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Main module
|
||||
*
|
||||
* Notes:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "p_lkrg_main.h"
|
||||
|
||||
unsigned int p_init_log_level = 1;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
|
||||
static enum cpuhp_state p_hot_cpus;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main entry point for the module - initialization.
|
||||
*/
|
||||
static int __init p_lkrg_register(void) {
|
||||
|
||||
int p_ret = P_LKRG_SUCCESS;
|
||||
|
||||
|
||||
memset(&p_lkrg_global_ctrl,0x0,sizeof(p_lkrg_global_ctrl_struct));
|
||||
p_lkrg_global_ctrl.p_timestamp = 15; // seconds
|
||||
if (p_init_log_level >= P_LOG_LEVEL_MAX)
|
||||
p_lkrg_global_ctrl.p_log_level = P_LOG_LEVEL_MAX-1; // Max
|
||||
else
|
||||
p_lkrg_global_ctrl.p_log_level = p_init_log_level;
|
||||
p_lkrg_global_ctrl.p_block_modules = 0x0; // Do NOT block loading new modules
|
||||
p_lkrg_global_ctrl.p_unhide_module = 0x1; // We are initially not hidden
|
||||
|
||||
if (get_kallsyms_address() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can't find kallsyms_lookup_name() function address! Exiting...\n");
|
||||
return P_LKRG_RESOLVER_ERROR;
|
||||
}
|
||||
#ifdef P_LKRG_DEBUG
|
||||
else {
|
||||
p_print_log(P_LKRG_DBG,
|
||||
"kallsyms_lookup_name() => 0x%lx\n",(long)p_kallsyms_lookup_name);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* First, we need to plant *kprobes... Before DB is created!
|
||||
*/
|
||||
if (p_exploit_detection_init()) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can't initialize exploit detection features! Exiting...\n");
|
||||
p_ret = P_LKRG_EXPLOIT_DETECTION_ERROR;
|
||||
goto p_main_error;
|
||||
}
|
||||
|
||||
if (p_offload_cache_init()) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can\'t initialize offloading cache :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_main_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize kmod module
|
||||
*/
|
||||
if (p_kmod_init()) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can't initialize kernel modules handling! Exiting...\n");
|
||||
p_ret = P_LKRG_KMOD_ERROR;
|
||||
goto p_main_error;
|
||||
}
|
||||
|
||||
if (p_create_database() != P_LKRG_SUCCESS) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can't create database! Exiting...\n");
|
||||
p_ret = P_LKRG_DATABASE_ERROR;
|
||||
goto p_main_error;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
|
||||
register_hotcpu_notifier(&p_cpu_notifier);
|
||||
#else
|
||||
cpu_notifier_register_begin();
|
||||
__register_hotcpu_notifier(&p_cpu_notifier);
|
||||
cpu_notifier_register_done();
|
||||
#endif
|
||||
#else
|
||||
if ( (p_hot_cpus = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
|
||||
"x86/p_lkrg:online",
|
||||
p_cpu_online_action,
|
||||
p_cpu_dead_action)) < 0) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can't register hot CPU plug[in/out] handler! Exiting...\n");
|
||||
p_ret = P_LKRG_HPCPU_ERROR;
|
||||
goto p_main_error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_register_comm_channel()) {
|
||||
p_print_log(P_LKRG_CRIT,
|
||||
"Can\'t initialize communication channel (sysctl) :(\n");
|
||||
p_ret = P_LKRG_GENERAL_ERROR;
|
||||
goto p_main_error;
|
||||
}
|
||||
|
||||
p_integrity_timer();
|
||||
p_register_notifiers();
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
if (!p_lkrg_global_ctrl.p_unhide_module) {
|
||||
p_hide_itself();
|
||||
}
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
return P_LKRG_SUCCESS;
|
||||
|
||||
p_main_error:
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
|
||||
unregister_hotcpu_notifier(&p_cpu_notifier);
|
||||
#else
|
||||
cpu_notifier_register_begin();
|
||||
__unregister_hotcpu_notifier(&p_cpu_notifier);
|
||||
cpu_notifier_register_done();
|
||||
#endif
|
||||
#else
|
||||
cpuhp_remove_state_nocalls(p_hot_cpus);
|
||||
#endif
|
||||
|
||||
p_deregister_module_notifier();
|
||||
if (p_db.p_IDT_MSR_CRx_array)
|
||||
kzfree(p_db.p_IDT_MSR_CRx_array);
|
||||
p_offload_cache_delete();
|
||||
p_exploit_detection_exit();
|
||||
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function normally should never be called - unloading module cleanup
|
||||
*/
|
||||
static void __exit p_lkrg_deregister(void) {
|
||||
|
||||
#ifdef P_LKRG_DEBUG
|
||||
p_print_log(P_LKRG_DBG,
|
||||
"I should never be here! This operation probably is going to break your system! Goodbye ;)\n");
|
||||
#endif
|
||||
|
||||
del_timer(&p_timer);
|
||||
p_deregister_notifiers();
|
||||
p_deregister_comm_channel();
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
|
||||
unregister_hotcpu_notifier(&p_cpu_notifier);
|
||||
#else
|
||||
cpu_notifier_register_begin();
|
||||
__unregister_hotcpu_notifier(&p_cpu_notifier);
|
||||
cpu_notifier_register_done();
|
||||
#endif
|
||||
#else
|
||||
cpuhp_remove_state_nocalls(p_hot_cpus);
|
||||
#endif
|
||||
|
||||
p_deregister_module_notifier();
|
||||
|
||||
kzfree(p_db.p_IDT_MSR_CRx_array);
|
||||
p_offload_cache_delete();
|
||||
p_exploit_detection_exit();
|
||||
|
||||
}
|
||||
|
||||
|
||||
module_init(p_lkrg_register);
|
||||
module_exit(p_lkrg_deregister);
|
||||
|
||||
module_param(p_init_log_level, uint, 0000);
|
||||
MODULE_PARM_DESC(p_init_log_level, "Logging level init value [1 (alive) is default]");
|
||||
|
||||
MODULE_AUTHOR("Adam 'pi3' Zabrocki (http://pi3.com.pl)");
|
||||
MODULE_DESCRIPTION("pi3's Linux kernel Runtime Guard");
|
||||
MODULE_LICENSE("GPL"); // Don't think so...
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* pi3's Linux kernel Runtime Guard
|
||||
*
|
||||
* Component:
|
||||
* - Main module
|
||||
*
|
||||
* Notes:
|
||||
* - None
|
||||
*
|
||||
* Timeline:
|
||||
* - Created: 24.XI.2015
|
||||
*
|
||||
* Author:
|
||||
* - Adam 'pi3' Zabrocki (http://pi3.com.pl)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P_LKRG_MAIN_H
|
||||
#define P_LKRG_MAIN_H
|
||||
|
||||
#define P_LKRG_UNHIDE
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
|
||||
#include <linux/cpuhotplug.h>
|
||||
#endif
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/netevent.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#include <linux/major.h>
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <linux/signal.h>
|
||||
|
||||
|
||||
/*
|
||||
* p_lkrg modules
|
||||
*/
|
||||
#include "modules/print_log/p_lkrg_print_log.h" // printing, error and debug module
|
||||
#include "modules/hashing/p_super_fast_hash.h" // Hashing module
|
||||
#include "modules/hashing/p_crypto_sha1.h" // SHA1 module
|
||||
#include "modules/ksyms/p_resolve_ksym.h" // Resolver module
|
||||
#include "modules/database/p_database.h" // Database module
|
||||
#include "modules/integrity_timer/p_integrity_timer.h" // Integrity timer module
|
||||
#include "modules/kmod/p_kmod.h" // Kernel's modules module
|
||||
#include "modules/notifiers/p_notifiers.h" // Notifiers module
|
||||
#include "modules/self-defense/hiding/p_hiding.h" // Hiding module
|
||||
#include "modules/wrap/p_struct_wrap.h" // Wrapping module
|
||||
#include "modules/comm_channel/p_comm_channel.h" // Communication channel (sysctl) module
|
||||
|
||||
/*
|
||||
* Exploit Detection
|
||||
*/
|
||||
#include "modules/exploit_detection/p_exploit_detection.h"
|
||||
|
||||
|
||||
extern unsigned int p_init_log_level;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue