RO/NX protection for loadable kernel modules
Subsystems (4)
PATCH v7 1/1 RO/NX protection for loadable kernel modules
This patch is a logical extension of the protection provided by CONFIG_DEBUG_RODATA to LKMs. The protection is provided by splitting module_core and module_init into three logical parts each and setting appropriate page access permissions for each individual section:
1. Code: RO+X
2. RO data: RO+NX
3. RW data: RW+NX
In order to achieve proper protection, layout_sections() have been modified to align each of the three parts mentioned above onto page boundary. Next, the corresponding page access permissions are set right before successful exit from load_module(). Further, free_module() and sys_init_module have been modified to set module_core and module_init as RW+NX right before calling module_free().
By default, the original section layout and access flags are preserved. When compiled with CONFIG_DEBUG_SET_MODULE_RONX=y, the patch will page-align each group of sections to ensure that each page contains only one type of content and will enforce RO/NX for each group of pages.
v1: Initial proof-of-concept patch.
v2: The patch have been re-written to reduce the number of #ifdefs and to make it architecture-agnostic. Code formatting have been corrected also.
v3: Opportunistic RO/NX protectiuon is now unconditional. Section page-alignment is enabled when CONFIG_DEBUG_RODATA=y.
v4: Removed most macros and improved coding style.
v5: Changed page-alignment and RO/NX section size calculation
v6: Fixed comments. Restricted RO/NX enforcement to x86 only
v7: Introduced CONFIG_DEBUG_SET_MODULE_RONX, added calls to set_all_modules_text_rw() and set_all_modules_text_ro() in ftrace
The patch have been developed for Linux 2.6.30 by Siarhei Liakh <[email protected]> and Xuxian Jiang <[email protected]>.
---
arch/x86/Kconfig.debug +11 -0
@@ -115,6 +115,17 @@ config DEBUG_RODATA_TEST feature as well as for the change_page_attr() infrastructure. If in doubt, say "N" +config DEBUG_SET_MODULE_RONX + bool "Set loadable kernel module data as NX and text as RO" + default n + depends on X86 && MODULES + ---help--- + This option helps to catch unintended modifications to loadable + kernel module's text and read-only data. It also prevents execution + of LKM's data. Such protection may interfere with run-time code + patching and dynamic kernel tracing. + If in doubt, say "N". + config DEBUG_NX_TEST tristate "Testcase for the NX non-executable stack feature" depends on DEBUG_KERNEL && m
arch/x86/kernel/ftrace.c +3 -1
@@ -17,6 +17,7 @@#include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> +#include <linux/module.h> #include <trace/syscall.h>
@@ -27,16 +28,17 @@#ifdef CONFIG_DYNAMIC_FTRACE -int ftrace_arch_code_modify_prepare (void ) {set_kernel_text_rw (); +set_all_modules_text_rw ();return 0 ; }int ftrace_arch_code_modify_post_process (void ) {set_kernel_text_ro (); +set_all_modules_text_ro ();return 0 ; }
include/linux/module.h +6 -0
@@ -293,6 +293,9 @@ struct module/* The size of the executable code in each section. */ unsigned int init_text_size, core_text_size; +/* Size of RO sections of the module (text+rodata) */ +unsigned int init_ro_size, core_ro_size; +/* Arch-specific module values */ struct mod_arch_specific arch;
@@ -517,6 +520,9 @@ extern void module_update_markers(void);extern void module_update_tracepoints (void );extern int module_get_iter_tracepoints (struct tracepoint_iter *iter); +void set_all_modules_text_rw (void ); +void set_all_modules_text_ro (void ); +#else /* !CONFIG_MODULES... */ #define EXPORT_SYMBOL (sym)#define EXPORT_SYMBOL_GPL (sym)
@@ -641,6 +647,13 @@ static inline int
module_get_iter_tracepoints(struct tracepoint_iter *iter)
return 0;
}
+static inline void set_all_modules_text_rw()
+{
+}
+
+static inline void set_all_modules_text_ro()
+{
+}
#endif /* CONFIG_MODULES */
struct device_driver;
kernel/module.c +175 -2
221 lines not on this page · raw message
__user *umod,
/* Get rid of temporary copy */
vfree(hdr);
+ /* Set RO and NX regions for core */
+ set_section_ro_nx(mod->module_core,
+ mod->core_text_size,
+ mod->core_ro_size,
+ mod->core_size);
+
+ /* Set RO and NX regions for init */
+ set_section_ro_nx(mod->module_init,
+ mod->init_text_size,
+ mod->init_ro_size,
+ mod->init_size);
+
/* Done! */
return mod;
@@ -2394,6 +2579,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
mutex_lock(&module_mutex);
/* Drop initial reference. */
module_put(mod);
+ unset_section_ro_nx(mod, mod->module_init);
module_free(mod, mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
Rusty Russell
AppliedQuoted 4 lines · Siarhei Liakh
This patch is a logical extension of the protection provided by
CONFIG_DEBUG_RODATAto LKMs. The protection is provided by splittingmodule_coreandmodule_initinto three logical parts each and setting appropriate page access permissions for each individual section:
Thanks, applied!
It will be in linux-next soon, and if all goes well, 2.6.33.
Cheers,
Rusty.