Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ ccflags-y := ${ccflags-m}
$(TARGET)-objs += src/modules/print_log/p_lkrg_debug_log.o
endif

#
# Allow overriding LKRG_LOCKED_DOWN via Make.
#
ifneq ($(LKRG_LOCKED_DOWN),)
ccflags-y += -DLKRG_LOCKED_DOWN=$(LKRG_LOCKED_DOWN)
endif

#
# Allow overriding LKRG_LOCKDOWN_BY_KERNEL via Make.
#
ifneq ($(LKRG_LOCKDOWN_BY_KERNEL),)
ccflags-y += -DLKRG_LOCKDOWN_BY_KERNEL=$(LKRG_LOCKDOWN_BY_KERNEL)
endif

obj-m += $(TARGET).o
$(TARGET)-objs += src/modules/ksyms/p_resolve_ksym.o \
src/modules/hashing/p_lkrg_fast_hash.o \
Expand Down
80 changes: 74 additions & 6 deletions src/p_lkrg_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ static char *p_verify_boot_params(void) {
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;
}

Expand All @@ -167,21 +169,28 @@ static void p_init_page_attr(void) {

#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
Expand Down Expand Up @@ -445,11 +454,68 @@ static int __init p_lkrg_register(void) {

p_debug_log(P_LOG_DEBUG, "kallsyms_lookup_name() => 0x%lx", (unsigned long)P_SYM(p_kallsyms_lookup_name));

/*
* Get state of kernel lockdown
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
int k_lockdown = is_kernel_locked_down();
#else
int k_lockdown = 0;
#endif

/*
* LKRG lockdown handling
*/
#if LKRG_LOCKED_DOWN == 0
if (k_lockdown == 1) {

p_print_log(P_LOG_ALIVE, "Kernel lockdown is enabled: LKRG is locked down");

int incr_refc = try_module_get(THIS_MODULE);

if (incr_refc) {

int p_lkrg_lockdown = 1;
p_print_log(P_LOG_ALIVE, "LKRG lockdown enabled: Unloading LKRG is disallowed");
} else {

p_print_log(P_LOG_FATAL, "LKRG lockdown failed: Can't increment module refcount");

p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
}
} else if (k_lockdown == 0) {
p_print_log(P_LOG_ALIVE, "Kernel lockdown is disabled: LKRG lockdown disabled");
} else {

p_print_log(P_LOG_FATAL, "LKRG failed to get kernel lockdown status, is kernel compiled with lockdown?");

p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
}
#else
p_print_log(P_LOG_ALIVE, "LKRG is locked down: Module was built with lockdown enabled");

int incr_refc = try_module_get(THIS_MODULE);

if (incr_refc) {

int p_lkrg_lockdown = 1;
p_print_log(P_LOG_ALIVE, "LKRG lockdown enabled: Unloading LKRG is disallowed");
} else {

p_print_log(P_LOG_FATAL, "LKRG lockdown failed: Can't increment module refcount");

p_ret = P_LKRG_GENERAL_ERROR;
goto p_main_error;
}
#endif

/*
* 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)");
p_print_log(P_LOG_DYING, "Not loading LKRG: '" P_BOOT_DISABLE_LKRG "' kernel boot parameter detected");
lkrg_deregister_net();
return P_LKRG_BOOT_DISABLE_LKRG;
}
Expand Down Expand Up @@ -593,14 +659,14 @@ static int __init p_lkrg_register(void) {
p_register_notifiers();
p_init_page_attr();

p_print_log(P_LOG_ALIVE, "LKRG initialized successfully");
p_print_log(P_LOG_ALIVE, "LKRG initialized successfully");

p_ret = P_LKRG_SUCCESS;
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_print_log(P_LOG_DYING, "Not loading LKRG: Initialization failed");
P_CTRL(p_kint_validate) = 0;
p_deregister_notifiers();
if (p_timer.function)
Expand Down Expand Up @@ -656,7 +722,9 @@ static int __init p_lkrg_register(void) {
/*
* This function normally should never be called - unloading module cleanup
*/
static void __exit p_lkrg_deregister(void) {
static void __exit p_lkrg_deregister(void)
{
#if !LKRG_WITH_NO_UNLOAD

p_print_log(P_LOG_DYING, "Unloading LKRG");

Expand Down Expand Up @@ -706,9 +774,9 @@ static void __exit p_lkrg_deregister(void) {
p_print_log(P_LOG_DYING, "LKRG unloaded");

lkrg_deregister_net();
#endif
}


#ifdef MODULE
module_init(p_lkrg_register);
#else
Expand Down
50 changes: 50 additions & 0 deletions src/p_lkrg_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,20 @@
#ifndef P_LKRG_MAIN_H
#define P_LKRG_MAIN_H

#ifndef LKRG_LOCKED_DOWN
#define LKRG_LOCKED_DOWN 0
#endif

#ifndef LKRG_LOCKDOWN_BY_KERNEL
#define LKRG_LOCKDOWN_BY_KERNEL 0
#endif

#define LKRG_WITH_HIDE
#define P_BOOT_DISABLE_LKRG "nolkrg"

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cred.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
Expand Down Expand Up @@ -507,6 +516,39 @@ static inline int p_lkrg_counter_lock_val_read(p_lkrg_counter_lock *p_arg) {
}
/* End */

/*
* LKRG lockdown global
*/
extern int p_lkrg_lockdown __ro_after_init;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think __ro_after_init is ineffective for modules, isn't it? We use our own usually-read-only page instead.


/*
* Kernel lockdown API
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)

typedef bool (*kernel_is_locked_down_t)(const struct cred *, unsigned int);

/* Resolve kernel_is_locked_down(). Returns: 1 - kernel is locked down, 0 - no lockdown, -1 - error. */
static inline int is_kernel_locked_down(void)
{
kernel_is_locked_down_t fn = NULL;

fn = (kernel_is_locked_down_t)kallsyms_lookup_name("kernel_is_locked_down");
if (fn) {
return fn(current_cred(), 0) ? 1 : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how you're able to call kallsyms_lookup_name directly, whereas we have to locate it and go via a function pointer? Also, your call via fn is expected to fail on kernels with CET IBT (on supporting Intel CPUs and not in a VM) or KCFI - something we worked around with extra magic for such calls we make in 1.0.

}

unsigned long addr = kallsyms_lookup_name("kernel_locked_down");
if (addr) {
int val = *(int *)addr;
return val ? 1 : 0;
}

return -1;
}
#endif
/* End */

/*
* LKRG modules
*/
Expand Down Expand Up @@ -561,4 +603,12 @@ static inline int p_lkrg_counter_lock_val_read(p_lkrg_counter_lock *p_arg) {
#error "LKRG requires CONFIG_TRIM_UNUSED_KSYMS to be disabled if it should be built as a kernel module"
#endif

#if LKRG_LOCKED_DOWN != 0 && LKRG_LOCKED_DOWN != 1
#error "LKRG_LOCKED_DOWN must be 0 or 1"
#endif

#if LKRG_LOCKDOWN_BY_KERNEL != 0 && LKRG_LOCKDOWN_BY_KERNEL != 1
#error "LKRG_LOCKDOWN_BY_KERNEL must be 0 or 1"
#endif

#endif
Loading