mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-20 12:54:36 +08:00
RISC-V: Protect all kernel sections including init early
Currently, .init.text & .init.data are intermixed which makes it impossible apply different permissions to them. .init.data shouldn't need exec permissions while .init.text shouldn't have write permission. Moreover, the strict permission are only enforced /init starts. This leaves the kernel vulnerable from possible buggy built-in modules. Keep .init.text & .data in separate sections so that different permissions are applied to each section. Apply permissions to individual sections as early as possible. This improves the kernel protection under CONFIG_STRICT_KERNEL_RWX. We also need to restore the permissions for the entire _init section after it is freed so that those pages can be used for other purpose. Signed-off-by: Atish Patra <atish.patra@wdc.com> Tested-by: Greentime Hu <greentime.hu@sifive.com> Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
This commit is contained in:
parent
b6566dc1ac
commit
19a0086902
@ -9,5 +9,7 @@
|
||||
|
||||
extern char _start[];
|
||||
extern char _start_kernel[];
|
||||
extern char __init_data_begin[], __init_data_end[];
|
||||
extern char __init_text_begin[], __init_text_end[];
|
||||
|
||||
#endif /* __ASM_SECTIONS_H */
|
||||
|
@ -15,11 +15,15 @@ int set_memory_ro(unsigned long addr, int numpages);
|
||||
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);
|
||||
int set_memory_rw_nx(unsigned long addr, int numpages);
|
||||
void protect_kernel_text_data(void);
|
||||
#else
|
||||
static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
|
||||
static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
|
||||
static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
|
||||
static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
|
||||
static inline void protect_kernel_text_data(void) {};
|
||||
static inline int set_memory_rw_nx(unsigned long addr, int numpages) { return 0; }
|
||||
#endif
|
||||
|
||||
int set_direct_map_invalid_noflush(struct page *page);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/sbi.h>
|
||||
#include <asm/tlbflush.h>
|
||||
@ -252,6 +253,8 @@ void __init setup_arch(char **cmdline_p)
|
||||
if (IS_ENABLED(CONFIG_RISCV_SBI))
|
||||
sbi_init();
|
||||
|
||||
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
|
||||
protect_kernel_text_data();
|
||||
#ifdef CONFIG_SWIOTLB
|
||||
swiotlb_init(1);
|
||||
#endif
|
||||
@ -281,3 +284,12 @@ static int __init topology_init(void)
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(topology_init);
|
||||
|
||||
void free_initmem(void)
|
||||
{
|
||||
unsigned long init_begin = (unsigned long)__init_begin;
|
||||
unsigned long init_end = (unsigned long)__init_end;
|
||||
|
||||
set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
|
||||
free_initmem_default(POISON_FREE_INITMEM);
|
||||
}
|
||||
|
@ -29,6 +29,22 @@ SECTIONS
|
||||
HEAD_TEXT_SECTION
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
|
||||
.text : {
|
||||
_text = .;
|
||||
_stext = .;
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
CPUIDLE_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
ENTRY_TEXT
|
||||
IRQENTRY_TEXT
|
||||
SOFTIRQENTRY_TEXT
|
||||
*(.fixup)
|
||||
_etext = .;
|
||||
}
|
||||
|
||||
. = ALIGN(SECTION_ALIGN);
|
||||
__init_begin = .;
|
||||
__init_text_begin = .;
|
||||
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) ALIGN(SECTION_ALIGN) { \
|
||||
@ -53,36 +69,25 @@ SECTIONS
|
||||
{
|
||||
EXIT_TEXT
|
||||
}
|
||||
|
||||
__init_text_end = .;
|
||||
. = ALIGN(SECTION_ALIGN);
|
||||
#ifdef CONFIG_EFI
|
||||
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
|
||||
__pecoff_text_end = .;
|
||||
#endif
|
||||
/* Start of init data section */
|
||||
__init_data_begin = .;
|
||||
INIT_DATA_SECTION(16)
|
||||
.exit.data :
|
||||
{
|
||||
EXIT_DATA
|
||||
}
|
||||
PERCPU_SECTION(L1_CACHE_BYTES)
|
||||
|
||||
__init_data_end = .;
|
||||
__init_end = .;
|
||||
|
||||
. = ALIGN(SECTION_ALIGN);
|
||||
.text : {
|
||||
_text = .;
|
||||
_stext = .;
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
CPUIDLE_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
ENTRY_TEXT
|
||||
IRQENTRY_TEXT
|
||||
SOFTIRQENTRY_TEXT
|
||||
*(.fixup)
|
||||
_etext = .;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
|
||||
__pecoff_text_end = .;
|
||||
#endif
|
||||
|
||||
INIT_DATA_SECTION(16)
|
||||
|
||||
/* Start of data section */
|
||||
_sdata = .;
|
||||
RO_DATA(SECTION_ALIGN)
|
||||
|
@ -612,18 +612,29 @@ static inline void setup_vm_final(void)
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
#ifdef CONFIG_STRICT_KERNEL_RWX
|
||||
void mark_rodata_ro(void)
|
||||
void protect_kernel_text_data(void)
|
||||
{
|
||||
unsigned long text_start = (unsigned long)_text;
|
||||
unsigned long text_end = (unsigned long)_etext;
|
||||
unsigned long text_start = (unsigned long)_start;
|
||||
unsigned long init_text_start = (unsigned long)__init_text_begin;
|
||||
unsigned long init_data_start = (unsigned long)__init_data_begin;
|
||||
unsigned long rodata_start = (unsigned long)__start_rodata;
|
||||
unsigned long data_start = (unsigned long)_data;
|
||||
unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn)));
|
||||
|
||||
set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT);
|
||||
set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
|
||||
set_memory_ro(text_start, (init_text_start - text_start) >> PAGE_SHIFT);
|
||||
set_memory_ro(init_text_start, (init_data_start - init_text_start) >> PAGE_SHIFT);
|
||||
set_memory_nx(init_data_start, (rodata_start - init_data_start) >> PAGE_SHIFT);
|
||||
/* rodata section is marked readonly in mark_rodata_ro */
|
||||
set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
|
||||
set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void mark_rodata_ro(void)
|
||||
{
|
||||
unsigned long rodata_start = (unsigned long)__start_rodata;
|
||||
unsigned long data_start = (unsigned long)_data;
|
||||
|
||||
set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
|
||||
|
||||
debug_checkwx();
|
||||
}
|
||||
|
@ -128,6 +128,12 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_memory_rw_nx(unsigned long addr, int numpages)
|
||||
{
|
||||
return __set_memory(addr, numpages, __pgprot(_PAGE_READ | _PAGE_WRITE),
|
||||
__pgprot(_PAGE_EXEC));
|
||||
}
|
||||
|
||||
int set_memory_ro(unsigned long addr, int numpages)
|
||||
{
|
||||
return __set_memory(addr, numpages, __pgprot(_PAGE_READ),
|
||||
|
Loading…
Reference in New Issue
Block a user