Initial LKRG-main

This commit is contained in:
Adam_pi3 2017-10-26 22:29:49 -07:00
commit 45cf3846d0
68 changed files with 9677 additions and 0 deletions

1
LICENSE Normal file
View File

@ -0,0 +1 @@
All rights reserved to Adam 'pi3' Zabrocki

64
Makefile Normal file
View File

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

1
README Normal file
View File

@ -0,0 +1 @@
All rights reserved to Adam 'pi3' Zabrocki.

View File

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

View File

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

355
src/modules/database/CPU.c Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

514
src/modules/kmod/p_kmod.c Normal file
View File

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

89
src/modules/kmod/p_kmod.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

191
src/p_lkrg_main.c Normal file
View File

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

87
src/p_lkrg_main.h Normal file
View File

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