lkdtm: add function for testing .rodata section
This adds a function that lives in the .rodata section. The section flags are corrected using objcopy since there is no way with gcc to declare section flags in an architecture-agnostic way. Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
426f3a53d4
commit
9a49a528dc
|
@ -59,3 +59,11 @@ obj-$(CONFIG_CXL_BASE) += cxl/
|
|||
obj-$(CONFIG_PANEL) += panel.o
|
||||
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o
|
||||
|
||||
OBJCOPYFLAGS :=
|
||||
OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \
|
||||
--set-section-flags .text=alloc,readonly \
|
||||
--rename-section .text=.rodata
|
||||
$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o
|
||||
$(call if_changed,objcopy)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __LKDTM_H
|
||||
#define __LKDTM_H
|
||||
|
||||
void lkdtm_rodata_do_nothing(void);
|
||||
|
||||
#endif
|
|
@ -52,6 +52,8 @@
|
|||
#include <linux/ide.h>
|
||||
#endif
|
||||
|
||||
#include "lkdtm.h"
|
||||
|
||||
/*
|
||||
* Make sure our attempts to over run the kernel stack doesn't trigger
|
||||
* a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
|
||||
|
@ -103,6 +105,7 @@ enum ctype {
|
|||
CT_EXEC_STACK,
|
||||
CT_EXEC_KMALLOC,
|
||||
CT_EXEC_VMALLOC,
|
||||
CT_EXEC_RODATA,
|
||||
CT_EXEC_USERSPACE,
|
||||
CT_ACCESS_USERSPACE,
|
||||
CT_WRITE_RO,
|
||||
|
@ -145,6 +148,7 @@ static char* cp_type[] = {
|
|||
"EXEC_STACK",
|
||||
"EXEC_KMALLOC",
|
||||
"EXEC_VMALLOC",
|
||||
"EXEC_RODATA",
|
||||
"EXEC_USERSPACE",
|
||||
"ACCESS_USERSPACE",
|
||||
"WRITE_RO",
|
||||
|
@ -346,15 +350,18 @@ static noinline void corrupt_stack(void)
|
|||
memset((void *)data, 0, 64);
|
||||
}
|
||||
|
||||
static void noinline execute_location(void *dst)
|
||||
static noinline void execute_location(void *dst, bool write)
|
||||
{
|
||||
void (*func)(void) = dst;
|
||||
|
||||
pr_info("attempting ok execution at %p\n", do_nothing);
|
||||
do_nothing();
|
||||
|
||||
memcpy(dst, do_nothing, EXEC_SIZE);
|
||||
flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
|
||||
if (write) {
|
||||
memcpy(dst, do_nothing, EXEC_SIZE);
|
||||
flush_icache_range((unsigned long)dst,
|
||||
(unsigned long)dst + EXEC_SIZE);
|
||||
}
|
||||
pr_info("attempting bad execution at %p\n", func);
|
||||
func();
|
||||
}
|
||||
|
@ -551,25 +558,28 @@ static void lkdtm_do_action(enum ctype which)
|
|||
schedule();
|
||||
break;
|
||||
case CT_EXEC_DATA:
|
||||
execute_location(data_area);
|
||||
execute_location(data_area, true);
|
||||
break;
|
||||
case CT_EXEC_STACK: {
|
||||
u8 stack_area[EXEC_SIZE];
|
||||
execute_location(stack_area);
|
||||
execute_location(stack_area, true);
|
||||
break;
|
||||
}
|
||||
case CT_EXEC_KMALLOC: {
|
||||
u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL);
|
||||
execute_location(kmalloc_area);
|
||||
execute_location(kmalloc_area, true);
|
||||
kfree(kmalloc_area);
|
||||
break;
|
||||
}
|
||||
case CT_EXEC_VMALLOC: {
|
||||
u32 *vmalloc_area = vmalloc(EXEC_SIZE);
|
||||
execute_location(vmalloc_area);
|
||||
execute_location(vmalloc_area, true);
|
||||
vfree(vmalloc_area);
|
||||
break;
|
||||
}
|
||||
case CT_EXEC_RODATA:
|
||||
execute_location(lkdtm_rodata_do_nothing, false);
|
||||
break;
|
||||
case CT_EXEC_USERSPACE: {
|
||||
unsigned long user_addr;
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* This includes functions that are meant to live entirely in .rodata
|
||||
* (via objcopy tricks), to validate the non-executability of .rodata.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
|
||||
void lkdtm_rodata_do_nothing(void)
|
||||
{
|
||||
/* Does nothing. We just want an architecture agnostic "return". */
|
||||
}
|
Loading…
Reference in New Issue