x86: Add NX protection for kernel data
This patch expands functionality of CONFIG_DEBUG_RODATA to set main (static) kernel data area as NX. The following steps are taken to achieve this: 1. Linker script is adjusted so .text always starts and ends on a page bound 2. Linker script is adjusted so .rodata always start and end on a page boundary 3. NX is set for all pages from _etext through _end in mark_rodata_ro. 4. free_init_pages() sets released memory NX in arch/x86/mm/init.c 5. bios rom is set to x when pcibios is used. The results of patch application may be observed in the diff of kernel page table dumps: pcibios: -- data_nx_pt_before.txt 2009-10-13 07:48:59.000000000 -0400 ++ data_nx_pt_after.txt 2009-10-13 07:26:46.000000000 -0400 0x00000000-0xc0000000 3G pmd ---[ Kernel Mapping ]--- -0xc0000000-0xc0100000 1M RW GLB x pte +0xc0000000-0xc00a0000 640K RW GLB NX pte +0xc00a0000-0xc0100000 384K RW GLB x pte -0xc0100000-0xc03d7000 2908K ro GLB x pte +0xc0100000-0xc0318000 2144K ro GLB x pte +0xc0318000-0xc03d7000 764K ro GLB NX pte -0xc03d7000-0xc0600000 2212K RW GLB x pte +0xc03d7000-0xc0600000 2212K RW GLB NX pte 0xc0600000-0xf7a00000 884M RW PSE GLB NX pmd 0xf7a00000-0xf7bfe000 2040K RW GLB NX pte 0xf7bfe000-0xf7c00000 8K pte No pcibios: -- data_nx_pt_before.txt 2009-10-13 07:48:59.000000000 -0400 ++ data_nx_pt_after.txt 2009-10-13 07:26:46.000000000 -0400 0x00000000-0xc0000000 3G pmd ---[ Kernel Mapping ]--- -0xc0000000-0xc0100000 1M RW GLB x pte +0xc0000000-0xc0100000 1M RW GLB NX pte -0xc0100000-0xc03d7000 2908K ro GLB x pte +0xc0100000-0xc0318000 2144K ro GLB x pte +0xc0318000-0xc03d7000 764K ro GLB NX pte -0xc03d7000-0xc0600000 2212K RW GLB x pte +0xc03d7000-0xc0600000 2212K RW GLB NX pte 0xc0600000-0xf7a00000 884M RW PSE GLB NX pmd 0xf7a00000-0xf7bfe000 2040K RW GLB NX pte 0xf7bfe000-0xf7c00000 8K pte The patch has been originally developed for Linux 2.6.34-rc2 x86 by Siarhei Liakh <sliakh.lkml@gmail.com> and Xuxian Jiang <jiang@cs.ncsu.edu>. -v1: initial patch for 2.6.30 -v2: patch for 2.6.31-rc7 -v3: moved all code into arch/x86, adjusted credits -v4: fixed ifdef, removed credits from CREDITS -v5: fixed an address calculation bug in mark_nxdata_nx() -v6: added acked-by and PT dump diff to commit log -v7: minor adjustments for -tip -v8: rework with the merge of "Set first MB as RW+NX" Signed-off-by: Siarhei Liakh <sliakh.lkml@gmail.com> Signed-off-by: Xuxian Jiang <jiang@cs.ncsu.edu> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr> Cc: Arjan van de Ven <arjan@infradead.org> Cc: James Morris <jmorris@namei.org> Cc: Andi Kleen <ak@muc.de> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Dave Jones <davej@redhat.com> Cc: Kees Cook <kees.cook@canonical.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> LKML-Reference: <4CE2F82E.60601@free.fr> [ minor cleanliness edits ] Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
committed by
Ingo Molnar
parent
64edc8ed5f
commit
5bd5a45266
@@ -9,6 +9,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/pci_x86.h>
|
||||
#include <asm/pci-functions.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/* BIOS32 signature: "_32_" */
|
||||
#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
|
||||
@@ -25,6 +26,27 @@
|
||||
#define PCIBIOS_HW_TYPE1_SPEC 0x10
|
||||
#define PCIBIOS_HW_TYPE2_SPEC 0x20
|
||||
|
||||
int pcibios_enabled;
|
||||
|
||||
/* According to the BIOS specification at:
|
||||
* http://members.datafast.net.au/dft0802/specs/bios21.pdf, we could
|
||||
* restrict the x zone to some pages and make it ro. But this may be
|
||||
* broken on some bios, complex to handle with static_protections.
|
||||
* We could make the 0xe0000-0x100000 range rox, but this can break
|
||||
* some ISA mapping.
|
||||
*
|
||||
* So we let's an rw and x hole when pcibios is used. This shouldn't
|
||||
* happen for modern system with mmconfig, and if you don't want it
|
||||
* you could disable pcibios...
|
||||
*/
|
||||
static inline void set_bios_x(void)
|
||||
{
|
||||
pcibios_enabled = 1;
|
||||
set_memory_x(PAGE_OFFSET + BIOS_BEGIN, (BIOS_END - BIOS_BEGIN) >> PAGE_SHIFT);
|
||||
if (__supported_pte_mask & _PAGE_NX)
|
||||
printk(KERN_INFO "PCI : PCI BIOS aera is rw and x. Use pci=nobios if you want it NX.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the standard structure used to identify the entry point
|
||||
* to the BIOS32 Service Directory, as documented in
|
||||
@@ -332,6 +354,7 @@ static struct pci_raw_ops * __devinit pci_find_bios(void)
|
||||
DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n",
|
||||
bios32_entry);
|
||||
bios32_indirect.address = bios32_entry + PAGE_OFFSET;
|
||||
set_bios_x();
|
||||
if (check_pcibios())
|
||||
return &pci_bios_access;
|
||||
}
|
||||
|
Reference in New Issue
Block a user