lkrg/src/p_lkrg_main.c
2023-05-19 14:09:29 +02:00

698 lines
21 KiB
C

/*
* 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 log_level = 3;
unsigned int heartbeat = 0;
unsigned int block_modules = 0;
unsigned int interval = 15;
unsigned int kint_validate = 3;
unsigned int kint_enforce = 2;
unsigned int msr_validate = 0;
unsigned int pint_validate = 1;
unsigned int pint_enforce = 1;
unsigned int pcfi_validate = 2;
unsigned int pcfi_enforce = 1;
unsigned int umh_validate = 1;
unsigned int umh_enforce = 1;
#if defined(CONFIG_X86)
unsigned int smep_validate = 1;
unsigned int smep_enforce = 2;
unsigned int smap_validate = 1;
unsigned int smap_enforce = 2;
#endif
unsigned int profile_validate = 3;
unsigned int profile_enforce = 2;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
static enum cpuhp_state p_hot_cpus;
#endif
unsigned int p_attr_init = 0;
DEFINE_MUTEX(p_ro_page_mutex);
p_ro_page p_ro __p_lkrg_read_only = {
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
.p_marker_np1 = P_LKRG_MARKER1,
#endif
.p_lkrg_global_ctrl.ctrl = {
.p_kint_validate = 3, // kint_validate
.p_kint_enforce = 2, // kint_enforce
.p_pint_validate = 1, // pint_validate
.p_pint_enforce = 1, // pint_enforce
.p_interval = 15, // interval
.p_log_level = 3, // log_level
.p_trigger = 0, // trigger
.p_block_modules = 0, // block_modules
.p_hide_lkrg = 0, // hide_lkrg
.p_heartbeat = 0, // heartbeat
#if defined(CONFIG_X86)
.p_smep_validate = 1, // smep_validate
.p_smep_enforce = 2, // smep_enforce
.p_smap_validate = 1, // smap_validate
.p_smap_enforce = 2, // smap_enforce
#endif
.p_umh_validate = 1, // umh_validate
.p_umh_enforce = 1, // umh_enforce
.p_msr_validate = 0, // msr_validate
.p_pcfi_validate = 2, // pcfi_validate
.p_pcfi_enforce = 1, // pcfi_enforce
/* Profiles */
.p_profile_validate = 3, // profile_validate
.p_profile_enforce = 2 // profile_enforce
},
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
.p_marker_np2 = P_LKRG_MARKER1,
.p_marker_np3 = P_LKRG_MARKER2
#endif
};
static char *p_verify_boot_params(void) {
char **p_params_ptr = (char **)P_SYM(p_kallsyms_lookup_name)("saved_command_line");
char *p_params;
p_params = (p_params_ptr) ? *p_params_ptr : NULL;
if (!p_params) {
p_print_log(P_LOG_FAULT, "Can't find kernel boot parameters, not checking for '" P_BOOT_DISABLE_LKRG "'");
return NULL;
}
return strstr(p_params, P_BOOT_DISABLE_LKRG);
}
static void p_init_page_attr(void) {
unsigned long *p_long_tmp = 0;
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
unsigned long p_long_offset = PAGE_SIZE/sizeof(p_long_tmp); // On purpose sizeof pointer
#endif
p_long_tmp = (unsigned long *)P_CTRL_ADDR;
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
if (*(p_long_tmp-p_long_offset) == P_LKRG_MARKER1) {
p_debug_log(P_LOG_DEBUG, "Found marker before configuration page");
if (*(p_long_tmp+p_long_offset) == P_LKRG_MARKER1) {
p_debug_log(P_LOG_DEBUG, "Found marker after configuration page");
#endif
P_SYM(p_state_init) = 2;
p_set_memory_ro((unsigned long)p_long_tmp,1);
p_debug_log(P_LOG_DEBUG, "Configuration page marked read-only");
p_attr_init++;
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
p_set_memory_np((unsigned long)(p_long_tmp-p_long_offset),1);
p_debug_log(P_LOG_DEBUG, "Setup guard page before configuration page");
if (*(p_long_tmp+p_long_offset*2) == P_LKRG_MARKER2) {
p_debug_log(P_LOG_DEBUG, "Found next marker after configuration page");
p_set_memory_np((unsigned long)(p_long_tmp+p_long_offset),1);
p_debug_log(P_LOG_DEBUG, "Setup guard page after configuration page");
p_attr_init++;
}
#endif
#if !defined(CONFIG_ARM64)
P_SYM(p_flush_tlb_all)();
#else
flush_tlb_all();
#endif
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
}
} else {
p_print_log(P_LOG_FAULT, "Can't find marker pages, so configuration page is not read-only");
p_debug_log(P_LOG_DEBUG, "*(p_long_tmp[0x%lx]-PAGE_SIZE) => [0x%lx] 0x%lx",
(unsigned long)p_long_tmp,
(unsigned long)p_long_tmp-p_long_offset,
*(p_long_tmp-p_long_offset));
p_debug_log(P_LOG_DEBUG, "*(p_long_tmp[0x%lx]+PAGE_SIZE) => [0x%lx] 0x%lx",
(unsigned long)p_long_tmp,
(unsigned long)p_long_tmp+p_long_offset,
*(p_long_tmp+p_long_offset));
p_debug_log(P_LOG_DEBUG, "*(p_long_tmp[0x%lx]+2*PAGE_SIZE) => [0x%lx] 0x%lx",
(unsigned long)p_long_tmp,
(unsigned long)p_long_tmp+2*p_long_offset,
*(p_long_tmp+2*p_long_offset));
}
#endif
}
static void p_uninit_page_attr(void) {
unsigned long *p_long_tmp = 0;
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
unsigned long p_long_offset = PAGE_SIZE/sizeof(p_long_tmp); // On purpose sizeof pointer
#endif
if (p_attr_init) {
p_long_tmp = (unsigned long *)P_CTRL_ADDR;
p_set_memory_rw((unsigned long)p_long_tmp,1);
p_debug_log(P_LOG_DEBUG, "Configuration page marked read-write");
#if !defined(CONFIG_ARM) && (!defined(P_KERNEL_AGGRESSIVE_INLINING) && defined(CONFIG_X86))
p_set_memory_p((unsigned long)(p_long_tmp-p_long_offset),1);
p_debug_log(P_LOG_DEBUG, "Disabled guard page before configuration page");
p_set_memory_rw((unsigned long)(p_long_tmp-p_long_offset),1);
*(p_long_tmp-p_long_offset) = P_LKRG_MARKER1;
if (p_attr_init > 1) {
p_debug_log(P_LOG_DEBUG, "Disabled guard page after configuration page");
p_set_memory_p((unsigned long)(p_long_tmp+p_long_offset),1);
p_set_memory_rw((unsigned long)(p_long_tmp+p_long_offset),1);
*(p_long_tmp+p_long_offset) = P_LKRG_MARKER1;
}
#endif
#if !defined(CONFIG_ARM64)
P_SYM(p_flush_tlb_all)();
#else
flush_tlb_all();
#endif
schedule();
} else {
p_print_log(P_LOG_FAULT, "Configuration page was not read-only");
}
p_attr_init ^= p_attr_init;
}
void p_parse_module_params(void) {
/* Interval */
if (interval > 1800) {
P_CTRL(p_interval) = 1800; // Max
} else if (interval < 5) {
P_CTRL(p_interval) = 5; // Min
} else {
P_CTRL(p_interval) = interval;
}
/* log_level */
if (log_level > P_LOG_MAX) {
P_CTRL(p_log_level) = P_LOG_MAX;
} else {
P_CTRL(p_log_level) = log_level;
}
/* heartbeat */
if (heartbeat > 1) {
P_CTRL(p_heartbeat) = 1;
} else {
P_CTRL(p_heartbeat) = heartbeat;
}
/* block_modules */
if (block_modules > 1) {
P_CTRL(p_block_modules) = 1;
} else {
P_CTRL(p_block_modules) = block_modules;
}
/* kint_validate */
if (kint_validate > 3) {
P_CTRL(p_kint_validate) = 3;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_kint_validate) != kint_validate) {
P_CTRL(p_kint_validate) = kint_validate;
P_CTRL(p_profile_validate) = 9;
}
/* kint_enforce */
if (kint_enforce > 2) {
P_CTRL(p_kint_enforce) = 2;
P_CTRL(p_profile_enforce) = 9;
} else if (P_CTRL(p_kint_enforce) != kint_enforce) {
P_CTRL(p_kint_enforce) = kint_enforce;
P_CTRL(p_profile_enforce) = 9;
}
/* msr_validate */
if (msr_validate > 1) {
P_CTRL(p_msr_validate) = 1;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_msr_validate) != msr_validate) {
P_CTRL(p_msr_validate) = msr_validate;
P_CTRL(p_profile_validate) = 9;
}
/* pint_validate */
if (pint_validate > 3) {
P_CTRL(p_pint_validate) = 3;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_pint_validate) != pint_validate) {
P_CTRL(p_pint_validate) = pint_validate;
P_CTRL(p_profile_validate) = 9;
}
/* pint_enforce */
if (pint_enforce > 2) {
P_CTRL(p_pint_enforce) = 2;
P_CTRL(p_profile_enforce) = 9;
} else if (P_CTRL(p_pint_enforce) != pint_enforce) {
P_CTRL(p_pint_enforce) = pint_enforce;
P_CTRL(p_profile_enforce) = 9;
}
/* umh_validate */
if (umh_validate > 2) {
P_CTRL(p_umh_validate) = 2;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_umh_validate) != umh_validate) {
P_CTRL(p_umh_validate) = umh_validate;
P_CTRL(p_profile_validate) = 9;
}
/* umh_enforce */
if (umh_enforce > 2) {
P_CTRL(p_umh_enforce) = 2;
P_CTRL(p_profile_enforce) = 9;
} else if (P_CTRL(p_umh_enforce) != umh_enforce) {
P_CTRL(p_umh_enforce) = umh_enforce;
P_CTRL(p_profile_enforce) = 9;
}
/* pcfi_validate */
if (pcfi_validate > 2) {
P_CTRL(p_pcfi_validate) = 2;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_pcfi_validate) != pcfi_validate) {
P_CTRL(p_pcfi_validate) = pcfi_validate;
P_CTRL(p_profile_validate) = 9;
}
/* pcfi_enforce */
if (pcfi_enforce > 2) {
P_CTRL(p_pcfi_enforce) = 2;
P_CTRL(p_profile_enforce) = 9;
} else if (P_CTRL(p_pcfi_enforce) != pcfi_enforce) {
P_CTRL(p_pcfi_enforce) = pcfi_enforce;
P_CTRL(p_profile_enforce) = 9;
}
p_pcfi_CPU_flags = 0;
#if defined(CONFIG_X86)
if (boot_cpu_has(X86_FEATURE_SMEP)) {
P_ENABLE_SMEP_FLAG(p_pcfi_CPU_flags);
/* smep_validate */
if (smep_validate > 1) {
P_CTRL(p_smep_validate) = 1;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_smep_validate) != smep_validate) {
P_CTRL(p_smep_validate) = smep_validate;
P_CTRL(p_profile_validate) = 9;
}
/* smep_enforce */
if (smep_enforce > 2) {
P_CTRL(p_smep_enforce) = 2;
P_CTRL(p_profile_enforce) = 9;
} else if (P_CTRL(p_smep_enforce) != smep_enforce) {
P_CTRL(p_smep_enforce) = smep_enforce;
P_CTRL(p_profile_enforce) = 9;
}
} else {
P_CTRL(p_smep_validate) = 0;
P_CTRL(p_smep_enforce) = 0;
p_print_log(P_LOG_ISSUE, "System does not support SMEP, which won't be validated");
}
if (boot_cpu_has(X86_FEATURE_SMAP)) {
P_ENABLE_SMAP_FLAG(p_pcfi_CPU_flags);
/* smap_validate */
if (smap_validate > 1) {
P_CTRL(p_smap_validate) = 1;
P_CTRL(p_profile_validate) = 9;
} else if (P_CTRL(p_smap_validate) != smap_validate) {
P_CTRL(p_smap_validate) = smap_validate;
P_CTRL(p_profile_validate) = 9;
}
/* smap_enforce */
if (smap_enforce > 2) {
P_CTRL(p_smap_enforce) = 2;
P_CTRL(p_profile_enforce) = 9;
} else if (P_CTRL(p_smap_enforce) != smap_enforce) {
P_CTRL(p_smap_enforce) = smap_enforce;
P_CTRL(p_profile_enforce) = 9;
}
} else {
P_CTRL(p_smap_validate) = 0;
P_CTRL(p_smap_enforce) = 0;
p_print_log(P_LOG_ISSUE, "System does not support SMAP, which won't be validated");
}
P_ENABLE_WP_FLAG(p_pcfi_CPU_flags);
#endif
}
/*
* Main entry point for the module - initialization.
*/
static int __init p_lkrg_register(void) {
int p_ret = P_LKRG_SUCCESS;
char p_cpu = 0;
char p_freeze = 0;
P_SYM(p_state_init) = 0;
if (get_kallsyms_address() != P_LKRG_SUCCESS) {
p_print_log(P_LOG_FATAL, "Can't find 'kallsyms_lookup_name'");
p_ret = P_LKRG_RESOLVER_ERROR;
goto p_main_error;
}
p_debug_log(P_LOG_DEBUG, "kallsyms_lookup_name() => 0x%lx", (unsigned long)P_SYM(p_kallsyms_lookup_name));
/*
* Verify if user disabled loading LKRG from boot parameters
*/
if (p_verify_boot_params()) {
p_print_log(P_LOG_DYING, "Not loading LKRG ('" P_BOOT_DISABLE_LKRG "' kernel boot parameter detected)");
return P_LKRG_BOOT_DISABLE_LKRG;
}
p_print_log(P_LOG_ALIVE, "Loading LKRG");
/*
* Generate random SipHash key
*/
p_global_siphash_key.p_low = (uint64_t)get_random_long();
p_global_siphash_key.p_high = (uint64_t)get_random_long();
p_parse_module_params();
P_SYM(p_find_me) = THIS_MODULE;
/*
* Verify if kprobes run as intended
*/
/* Register kprobes hooks necessary to verify kprobes itself */
if (p_install_lkrg_dummy_hook(0)) {
p_print_log(P_LOG_FATAL, "Can't hook 'lkrg_dummy'");
return P_LKRG_GENERAL_ERROR;
}
/* Verify kprobes now */
if (lkrg_verify_kprobes()) {
/*
* Kprobes does not work as intended.
* LKRG can't function without it, stop initialization!
*/
p_print_log(P_LOG_FATAL, "Can't continue initialization without working kprobes");
p_uninstall_lkrg_dummy_hook();
return P_LKRG_GENERAL_ERROR;
}
P_SYM_INIT(freeze_processes)
P_SYM_INIT(thaw_processes)
#if defined(CONFIG_X86) && LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
P_SYM_INIT(native_write_cr4)
#endif
#ifdef P_LKRG_UNEXPORTED_MODULE_ADDRESS
P_SYM_INIT(__module_address)
P_SYM_INIT(__module_text_address)
#endif
#if defined(CONFIG_OPTPROBES)
P_SYM_INIT(wait_for_kprobe_optimizer)
#endif
// Freeze all non-kernel processes
while (P_SYM(p_freeze_processes)())
schedule();
p_freeze = 1;
/*
* First, we need to plant *kprobes... Before DB is created!
*/
if (p_exploit_detection_init()) {
p_print_log(P_LOG_FATAL, "Can't initialize exploit detection features");
p_ret = P_LKRG_EXPLOIT_DETECTION_ERROR;
goto p_main_error;
}
if (p_offload_cache_init()) {
p_print_log(P_LOG_FATAL, "Can't initialize cache for system integrity WQ");
p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
}
/*
* Initialize kmod module
*/
if (p_kmod_init()) {
p_print_log(P_LOG_FATAL, "Can't initialize kernel module handling");
p_ret = P_LKRG_KMOD_ERROR;
goto p_main_error;
}
if (p_create_database() != P_LKRG_SUCCESS) {
p_print_log(P_LOG_FATAL, "Can't create database");
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/lkrg:online",
p_cpu_online_action,
p_cpu_dead_action)) < 0) {
p_print_log(P_LOG_FATAL, "Can't register hot CPU plug[in/out] handler");
p_ret = P_LKRG_HPCPU_ERROR;
goto p_main_error;
}
#endif
p_cpu = 1;
#if !defined(CONFIG_ARM64)
P_SYM_INIT(flush_tlb_all)
#endif
#if defined(P_KERNEL_AGGRESSIVE_INLINING)
P_SYM_INIT(set_memory_ro)
P_SYM_INIT(set_memory_rw)
#if defined(CONFIG_ARM64)
P_SYM_INIT(set_memory_valid)
#endif
#else
#if defined(CONFIG_X86)
P_SYM_INIT(change_page_attr_set_clr)
#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
P_SYM_INIT(change_memory_common)
#else
p_print_log(P_LOG_FATAL, "Unsupported platform");
p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
#endif
#endif
if (p_register_comm_channel()) {
p_print_log(P_LOG_FATAL, "Can't initialize sysctl");
p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
}
if (P_CTRL(p_hide_lkrg)) {
p_hide_itself();
}
p_integrity_timer();
p_register_notifiers();
p_init_page_attr();
p_print_log(P_LOG_ALIVE, "LKRG initialized successfully");
p_ret = P_LKRG_SUCCESS;
p_main_error:
if (p_ret != P_LKRG_SUCCESS) {
p_print_log(P_LOG_DYING, "Not loading LKRG (initialization failed)");
P_CTRL(p_kint_validate) = 0;
p_deregister_notifiers();
if (p_timer.function)
del_timer_sync(&p_timer);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
if (p_cpu)
unregister_hotcpu_notifier(&p_cpu_notifier);
#else
if (p_cpu) {
cpu_notifier_register_begin();
__unregister_hotcpu_notifier(&p_cpu_notifier);
cpu_notifier_register_done();
}
#endif
#else
if (p_cpu)
cpuhp_remove_state_nocalls(p_hot_cpus);
#endif
p_exploit_detection_exit();
p_unregister_arch_metadata();
p_offload_cache_delete();
p_deregister_module_notifier();
p_uninstall_lkrg_dummy_hook();
if (p_db.p_CPU_metadata_array) {
p_kzfree(p_db.p_CPU_metadata_array);
p_db.p_CPU_metadata_array = NULL;
}
if (p_attr_init)
p_uninit_page_attr();
#if defined(P_LKRG_JUMP_LABEL_STEXT_DEBUG)
if (p_db.kernel_stext_copy)
vfree(p_db.kernel_stext_copy);
#endif
}
if (p_freeze) {
// Thaw all non-kernel processes
P_SYM(p_thaw_processes)();
p_freeze = 0;
}
return p_ret;
p_sym_error:
p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
}
/*
* This function normally should never be called - unloading module cleanup
*/
static void __exit p_lkrg_deregister(void) {
p_print_log(P_LOG_DYING, "Unloading LKRG");
p_uninit_page_attr();
P_CTRL(p_kint_validate) = 0;
p_deregister_notifiers();
if (p_timer.function)
del_timer_sync(&p_timer);
// Freeze all non-kernel processes
while (P_SYM(p_freeze_processes)())
schedule();
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_exploit_detection_exit();
p_unregister_arch_metadata();
p_offload_cache_delete();
p_deregister_module_notifier();
p_uninstall_lkrg_dummy_hook();
if (p_db.p_CPU_metadata_array)
p_kzfree(p_db.p_CPU_metadata_array);
#if defined(P_LKRG_JUMP_LABEL_STEXT_DEBUG)
if (p_db.kernel_stext_copy)
vfree(p_db.kernel_stext_copy);
#endif
// Thaw all non-kernel processes
P_SYM(p_thaw_processes)();
p_print_log(P_LOG_DYING, "LKRG unloaded");
}
#ifdef MODULE
module_init(p_lkrg_register);
#else
late_initcall_sync(p_lkrg_register);
#endif
module_exit(p_lkrg_deregister);
module_param(log_level, uint, 0000);
MODULE_PARM_DESC(log_level, "log_level [3 (issue) is default]");
module_param(heartbeat, uint, 0000);
MODULE_PARM_DESC(heartbeat, "heartbeat [0 (don't print) is default]");
module_param(block_modules, uint, 0000);
MODULE_PARM_DESC(block_modules, "block_modules [0 (don't block) is default]");
module_param(interval, uint, 0000);
MODULE_PARM_DESC(interval, "interval [15 seconds is default]");
module_param(kint_validate, uint, 0000);
MODULE_PARM_DESC(kint_validate, "kint_validate [3 (periodically + random events) is default]");
module_param(kint_enforce, uint, 0000);
MODULE_PARM_DESC(kint_enforce, "kint_enforce [2 (panic) is default]");
module_param(msr_validate, uint, 0000);
MODULE_PARM_DESC(msr_validate, "msr_validate [0 (disabled) is default]");
module_param(pint_validate, uint, 0000);
MODULE_PARM_DESC(pint_validate, "pint_validate [1 (current) is default]");
module_param(pint_enforce, uint, 0000);
MODULE_PARM_DESC(pint_enforce, "pint_enforce [1 (kill task) is default]");
module_param(umh_validate, uint, 0000);
MODULE_PARM_DESC(umh_validate, "umh_validate [1 (allow specific paths) is default]");
module_param(umh_enforce, uint, 0000);
MODULE_PARM_DESC(umh_enforce, "umh_enforce [1 (prevent execution) is default]");
module_param(pcfi_validate, uint, 0000);
MODULE_PARM_DESC(pcfi_validate, "pcfi_validate [2 (fully enabled pCFI) is default]");
module_param(pcfi_enforce, uint, 0000);
MODULE_PARM_DESC(pcfi_enforce, "pcfi_enforce [1 (kill task) is default]");
#if defined(CONFIG_X86)
module_param(smep_validate, uint, 0000);
MODULE_PARM_DESC(smep_validate, "smep_validate [1 (enabled) is default]");
module_param(smep_enforce, uint, 0000);
MODULE_PARM_DESC(smep_enforce, "smep_enforce [2 (panic) is default]");
module_param(smap_validate, uint, 0000);
MODULE_PARM_DESC(smap_validate, "smap_validate [1 (enabled) is default]");
module_param(smap_enforce, uint, 0000);
MODULE_PARM_DESC(smap_enforce, "smap_enforce [2 (panic) is default]");
#endif
MODULE_AUTHOR("Adam 'pi3' Zabrocki (http://pi3.com.pl)");
MODULE_DESCRIPTION("pi3's Linux kernel Runtime Guard");
MODULE_LICENSE("GPL v2");