Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80d6b0c2 authored by Kees Cook's avatar Kees Cook
Browse files

ARM: mm: allow text and rodata sections to be read-only



This introduces CONFIG_DEBUG_RODATA, making kernel text and rodata
read-only. Additionally, this splits rodata from text so that rodata can
also be NX, which may lead to wasted memory when aligning to SECTION_SIZE.
The read-only areas are made writable during ftrace updates and kexec.

Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Tested-by: default avatarLaura Abbott <lauraa@codeaurora.org>
Acked-by: default avatarNicolas Pitre <nico@linaro.org>
parent 1e6b4811
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -487,6 +487,16 @@ int set_memory_rw(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);

#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
void set_kernel_text_rw(void);
void set_kernel_text_ro(void);
#else
static inline void set_kernel_text_rw(void) { }
static inline void set_kernel_text_ro(void) { }
#endif

void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
			     void *kaddr, unsigned long len);

#endif
+19 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/ftrace.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/stop_machine.h>

#include <asm/cacheflush.h>
#include <asm/opcodes.h>
@@ -35,6 +36,22 @@

#define	OLD_NOP		0xe1a00000	/* mov r0, r0 */

static int __ftrace_modify_code(void *data)
{
	int *command = data;

	set_kernel_text_rw();
	ftrace_modify_all_code(*command);
	set_kernel_text_ro();

	return 0;
}

void arch_ftrace_update_code(int command)
{
	stop_machine(__ftrace_modify_code, &command, NULL);
}

static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
{
	return rec->arch.old_mcount ? OLD_NOP : NOP;
@@ -73,6 +90,8 @@ int ftrace_arch_code_modify_prepare(void)
int ftrace_arch_code_modify_post_process(void)
{
	set_all_modules_text_ro();
	/* Make sure any TLB misses during machine stop are cleared. */
	flush_tlb_all();
	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ void machine_kexec(struct kimage *image)
	reboot_code_buffer = page_address(image->control_code_page);

	/* Prepare parameters for reboot_code_buffer*/
	set_kernel_text_rw();
	kexec_start_address = image->start;
	kexec_indirection_page = page_list;
	kexec_mach_type = machine_arch_type;
+3 −0
Original line number Diff line number Diff line
@@ -120,6 +120,9 @@ SECTIONS
			ARM_CPU_KEEP(PROC_INFO)
	}

#ifdef CONFIG_DEBUG_RODATA
	. = ALIGN(1<<SECTION_SHIFT);
#endif
	RO_DATA(PAGE_SIZE)

	. = ALIGN(4);
+12 −0
Original line number Diff line number Diff line
@@ -1017,3 +1017,15 @@ config ARM_KERNMEM_PERMS
	  padded to section-size (1MiB) boundaries (because their permissions
	  are different and splitting the 1M pages into 4K ones causes TLB
	  performance problems), wasting memory.

config DEBUG_RODATA
	bool "Make kernel text and rodata read-only"
	depends on ARM_KERNMEM_PERMS
	default y
	help
	  If this is set, kernel text and rodata will be made read-only. This
	  is to help catch accidental or malicious attempts to change the
	  kernel's executable code. Additionally splits rodata from kernel
	  text so it can be made explicitly non-executable. This creates
	  another section-size padded region, so it can waste more memory
	  space while gaining the read-only protections.
Loading