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

Commit 38f15e4e authored by Kees Cook's avatar Kees Cook Committed by Shiraz Hashim
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.

Change-Id: If1f8a6bb33539ba7161802e4f4760ada9521dce4
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>
Git-commit: 80d6b0c2eed2a504f6740cd1f5ea76dc50abfc4d
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


Signed-off-by: default avatarShiraz Hashim <shashim@codeaurora.org>
parent c5c232e0
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -508,6 +508,16 @@ int set_memory_rw(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(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 flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
			     void *kaddr, unsigned long len);
			     void *kaddr, unsigned long len);

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


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


#define	OLD_NOP		0xe1a00000	/* mov r0, r0 */
#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)
static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
{
{
	return rec->arch.old_mcount ? OLD_NOP : NOP;
	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)
int ftrace_arch_code_modify_post_process(void)
{
{
	set_all_modules_text_ro();
	set_all_modules_text_ro();
	/* Make sure any TLB misses during machine stop are cleared. */
	flush_tlb_all();
	return 0;
	return 0;
}
}


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


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


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


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