Message ID | 20200217083223.2011-7-zong.li@sifive.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Support strict kernel memory permissions for security | expand |
On Mon, 17 Feb 2020 00:32:21 PST (-0800), zong.li@sifive.com wrote: > The commit contains that make text section as non-writable, rodata > section as read-only, and data section as non-executable. > > The init section should be changed to non-executable. > > Signed-off-by: Zong Li <zong.li@sifive.com> > --- > arch/riscv/Kconfig | 1 + > arch/riscv/include/asm/set_memory.h | 8 +++++ > arch/riscv/mm/init.c | 45 +++++++++++++++++++++++++++++ > 3 files changed, 54 insertions(+) > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > index f524d7e60648..308a4dbc0b39 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -62,6 +62,7 @@ config RISCV > select ARCH_HAS_GIGANTIC_PAGE > select ARCH_HAS_SET_DIRECT_MAP > select ARCH_HAS_SET_MEMORY > + select ARCH_HAS_STRICT_KERNEL_RWX > select ARCH_WANT_HUGE_PMD_SHARE if 64BIT > select SPARSEMEM_STATIC if 32BIT > select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU > diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h > index a91f192063c2..d3076087cb34 100644 > --- a/arch/riscv/include/asm/set_memory.h > +++ b/arch/riscv/include/asm/set_memory.h > @@ -15,6 +15,14 @@ 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_STRICT_KERNEL_RWX > +void set_kernel_text_ro(void); > +void set_kernel_text_rw(void); > +#else > +static inline void set_kernel_text_ro(void) { } > +static inline void set_kernel_text_rw(void) { } > +#endif > + > int set_direct_map_invalid_noflush(struct page *page); > int set_direct_map_default_noflush(struct page *page); > > diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c > index 965a8cf4829c..09fa643e079c 100644 > --- a/arch/riscv/mm/init.c > +++ b/arch/riscv/mm/init.c > @@ -12,11 +12,13 @@ > #include <linux/sizes.h> > #include <linux/of_fdt.h> > #include <linux/libfdt.h> > +#include <linux/set_memory.h> > > #include <asm/fixmap.h> > #include <asm/tlbflush.h> > #include <asm/sections.h> > #include <asm/pgtable.h> > +#include <asm/ptdump.h> > #include <asm/io.h> > > #include "../kernel/head.h" > @@ -477,6 +479,49 @@ static void __init setup_vm_final(void) > csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE); > local_flush_tlb_all(); > } > + > +#ifdef CONFIG_STRICT_KERNEL_RWX > +void set_kernel_text_rw(void) > +{ > + unsigned long text_start = (unsigned long)_text; > + unsigned long text_end = (unsigned long)_etext; > + > + set_memory_rw(text_start, (text_end - text_start) >> PAGE_SHIFT); > +} > + > +void set_kernel_text_ro(void) > +{ > + unsigned long text_start = (unsigned long)_text; > + unsigned long text_end = (unsigned long)_etext; > + > + set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT); > +} > + > +void mark_rodata_ro(void) > +{ > + unsigned long text_start = (unsigned long)_text; > + unsigned long text_end = (unsigned long)_etext; > + unsigned long rodata_start = (unsigned long)__start_rodata; > + unsigned long data_start = (unsigned long)_sdata; > + 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_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); Ya, this'll risk barfing because of srodata. > + set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT); > +} > +#endif > + > +void free_initmem(void) > +{ > + unsigned long init_begin = (unsigned long)__init_begin; > + unsigned long init_end = (unsigned long)__init_end; > + > + /* Make the region as non-execuatble. */ > + set_memory_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT); > + free_initmem_default(POISON_FREE_INITMEM); > +} > + > #else > asmlinkage void __init setup_vm(uintptr_t dtb_pa) > {
Palmer Dabbelt <palmer@dabbelt.com> 於 2020年3月5日 週四 上午9:22寫道: > > On Mon, 17 Feb 2020 00:32:21 PST (-0800), zong.li@sifive.com wrote: > > The commit contains that make text section as non-writable, rodata > > section as read-only, and data section as non-executable. > > > > The init section should be changed to non-executable. > > > > Signed-off-by: Zong Li <zong.li@sifive.com> > > --- > > arch/riscv/Kconfig | 1 + > > arch/riscv/include/asm/set_memory.h | 8 +++++ > > arch/riscv/mm/init.c | 45 +++++++++++++++++++++++++++++ > > 3 files changed, 54 insertions(+) > > > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > > index f524d7e60648..308a4dbc0b39 100644 > > --- a/arch/riscv/Kconfig > > +++ b/arch/riscv/Kconfig > > @@ -62,6 +62,7 @@ config RISCV > > select ARCH_HAS_GIGANTIC_PAGE > > select ARCH_HAS_SET_DIRECT_MAP > > select ARCH_HAS_SET_MEMORY > > + select ARCH_HAS_STRICT_KERNEL_RWX > > select ARCH_WANT_HUGE_PMD_SHARE if 64BIT > > select SPARSEMEM_STATIC if 32BIT > > select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU > > diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h > > index a91f192063c2..d3076087cb34 100644 > > --- a/arch/riscv/include/asm/set_memory.h > > +++ b/arch/riscv/include/asm/set_memory.h > > @@ -15,6 +15,14 @@ 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_STRICT_KERNEL_RWX > > +void set_kernel_text_ro(void); > > +void set_kernel_text_rw(void); > > +#else > > +static inline void set_kernel_text_ro(void) { } > > +static inline void set_kernel_text_rw(void) { } > > +#endif > > + > > int set_direct_map_invalid_noflush(struct page *page); > > int set_direct_map_default_noflush(struct page *page); > > > > diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c > > index 965a8cf4829c..09fa643e079c 100644 > > --- a/arch/riscv/mm/init.c > > +++ b/arch/riscv/mm/init.c > > @@ -12,11 +12,13 @@ > > #include <linux/sizes.h> > > #include <linux/of_fdt.h> > > #include <linux/libfdt.h> > > +#include <linux/set_memory.h> > > > > #include <asm/fixmap.h> > > #include <asm/tlbflush.h> > > #include <asm/sections.h> > > #include <asm/pgtable.h> > > +#include <asm/ptdump.h> > > #include <asm/io.h> > > > > #include "../kernel/head.h" > > @@ -477,6 +479,49 @@ static void __init setup_vm_final(void) > > csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE); > > local_flush_tlb_all(); > > } > > + > > +#ifdef CONFIG_STRICT_KERNEL_RWX > > +void set_kernel_text_rw(void) > > +{ > > + unsigned long text_start = (unsigned long)_text; > > + unsigned long text_end = (unsigned long)_etext; > > + > > + set_memory_rw(text_start, (text_end - text_start) >> PAGE_SHIFT); > > +} > > + > > +void set_kernel_text_ro(void) > > +{ > > + unsigned long text_start = (unsigned long)_text; > > + unsigned long text_end = (unsigned long)_etext; > > + > > + set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT); > > +} > > + > > +void mark_rodata_ro(void) > > +{ > > + unsigned long text_start = (unsigned long)_text; > > + unsigned long text_end = (unsigned long)_etext; > > + unsigned long rodata_start = (unsigned long)__start_rodata; > > + unsigned long data_start = (unsigned long)_sdata; > > + 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_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); > > Ya, this'll risk barfing because of srodata. It might be OK because the range includes .rodata, .srodata and __ex_table sections, but I need another symbol instead of _sdata as you mentioned in other patch. > > > + set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT); > > +} > > +#endif > > + > > +void free_initmem(void) > > +{ > > + unsigned long init_begin = (unsigned long)__init_begin; > > + unsigned long init_end = (unsigned long)__init_end; > > + > > + /* Make the region as non-execuatble. */ > > + set_memory_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT); > > + free_initmem_default(POISON_FREE_INITMEM); > > +} > > + > > #else > > asmlinkage void __init setup_vm(uintptr_t dtb_pa) > > { >
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index f524d7e60648..308a4dbc0b39 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -62,6 +62,7 @@ config RISCV select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_MEMORY + select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_WANT_HUGE_PMD_SHARE if 64BIT select SPARSEMEM_STATIC if 32BIT select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h index a91f192063c2..d3076087cb34 100644 --- a/arch/riscv/include/asm/set_memory.h +++ b/arch/riscv/include/asm/set_memory.h @@ -15,6 +15,14 @@ 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_STRICT_KERNEL_RWX +void set_kernel_text_ro(void); +void set_kernel_text_rw(void); +#else +static inline void set_kernel_text_ro(void) { } +static inline void set_kernel_text_rw(void) { } +#endif + int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 965a8cf4829c..09fa643e079c 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -12,11 +12,13 @@ #include <linux/sizes.h> #include <linux/of_fdt.h> #include <linux/libfdt.h> +#include <linux/set_memory.h> #include <asm/fixmap.h> #include <asm/tlbflush.h> #include <asm/sections.h> #include <asm/pgtable.h> +#include <asm/ptdump.h> #include <asm/io.h> #include "../kernel/head.h" @@ -477,6 +479,49 @@ static void __init setup_vm_final(void) csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE); local_flush_tlb_all(); } + +#ifdef CONFIG_STRICT_KERNEL_RWX +void set_kernel_text_rw(void) +{ + unsigned long text_start = (unsigned long)_text; + unsigned long text_end = (unsigned long)_etext; + + set_memory_rw(text_start, (text_end - text_start) >> PAGE_SHIFT); +} + +void set_kernel_text_ro(void) +{ + unsigned long text_start = (unsigned long)_text; + unsigned long text_end = (unsigned long)_etext; + + set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT); +} + +void mark_rodata_ro(void) +{ + unsigned long text_start = (unsigned long)_text; + unsigned long text_end = (unsigned long)_etext; + unsigned long rodata_start = (unsigned long)__start_rodata; + unsigned long data_start = (unsigned long)_sdata; + 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_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); + set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT); +} +#endif + +void free_initmem(void) +{ + unsigned long init_begin = (unsigned long)__init_begin; + unsigned long init_end = (unsigned long)__init_end; + + /* Make the region as non-execuatble. */ + set_memory_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT); + free_initmem_default(POISON_FREE_INITMEM); +} + #else asmlinkage void __init setup_vm(uintptr_t dtb_pa) {
The commit contains that make text section as non-writable, rodata section as read-only, and data section as non-executable. The init section should be changed to non-executable. Signed-off-by: Zong Li <zong.li@sifive.com> --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/set_memory.h | 8 +++++ arch/riscv/mm/init.c | 45 +++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+)