RO/NX protection for loadable kernel modules
Subsystems (4)
PATCH v12 4/4 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
V8: updated for compatibility with linux 2.6.33-rc5
V9: coding style fixes
V10: more coding style fixes
V11: minor adjutments for -tip
V12: minor adjutments for v2.6.35-rc2-tip
---
arch/x86/Kconfig.debug +11 -0
@@ -113,6 +113,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 -0
@@ -19,6 +19,7 @@#include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> +#include <linux/module.h> #include <trace/syscall.h>
@@ -49,6 +50,7 @@ static DEFINE_PER_CPU(int, save_modifying_code);int ftrace_arch_code_modify_prepare (void ) {set_kernel_text_rw (); +set_all_modules_text_rw (); modifying_code =1 ;return 0 ; }
@@ -56,6 +58,7 @@ int ftrace_arch_code_modify_prepare(void)int ftrace_arch_code_modify_post_process (void ) { modifying_code =0 ; +set_all_modules_text_ro ();set_kernel_text_ro ();return 0 ; }
include/linux/module.h +13 -0
@@ -308,6 +308,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;
@@ -545,6 +548,9 @@ extern void print_modules(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)
@@ -670,6 +676,13 @@ static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter) return 0; } +static inline void set_all_modules_text_rw (void ) +{ +} + +static inline void set_all_modules_text_ro (void ) +{ +}#endif /* CONFIG_MODULES */ #ifdef CONFIG_SYSFS
kernel/module.c +180 -2
238 lines not on this page · raw message
[tip:x86/mm] x86, mm: RO/NX protection for loadable kernel modules
Commit-ID: 1e858c081af56a5d86597ff8e03abc9131eea750 Gitweb: http://git.kernel.org/tip/1e858c081af56a5d86597ff8e03abc9131eea750 Author: Siarhei Liakh <[email protected]> AuthorDate: Sun, 6 Jun 2010 21:01:36 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Fri, 11 Jun 2010 15:14:02 -0700
x86, mm: 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
V8: updated for compatibility with linux 2.6.33-rc5
V9: coding style fixes
V10: more coding style fixes
V11: minor adjutments for -tip
V12: minor adjutments for v2.6.35-rc2-tip
LKML-Reference: <[email protected]>
--- arch/x86/Kconfig.debug | 11 +++ arch/x86/kernel/ftrace.c | 3 + include/linux/module.h | 13 +++ kernel/module.c | 182 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 207 insertions(+), 2 deletions(-)
arch/x86/Kconfig.debug +11 -0
@@ -113,6 +113,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 -0
@@ -19,6 +19,7 @@#include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> +#include <linux/module.h> #include <trace/syscall.h>
@@ -49,6 +50,7 @@ static DEFINE_PER_CPU(int, save_modifying_code);int ftrace_arch_code_modify_prepare (void ) {set_kernel_text_rw (); +set_all_modules_text_rw (); modifying_code =1 ;return 0 ; }
@@ -56,6 +58,7 @@ int ftrace_arch_code_modify_prepare(void)int ftrace_arch_code_modify_post_process (void ) { modifying_code =0 ; +set_all_modules_text_ro ();set_kernel_text_ro ();return 0 ; }
include/linux/module.h +13 -0
@@ -308,6 +308,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;
@@ -545,6 +548,9 @@ extern void print_modules(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)
@@ -670,6 +676,13 @@ static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter) return 0; } +static inline void set_all_modules_text_rw (void ) +{ +} + +static inline void set_all_modules_text_ro (void ) +{ +}#endif /* CONFIG_MODULES */ #ifdef CONFIG_SYSFS
kernel/module.c +180 -2
238 lines not on this page · raw message