aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2008-01-30 07:34:04 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:34:04 -0500
commited724be65fa18833244d81b484e425fc838837fa (patch)
tree9d66141531f04a7b4abcb7f4573fe2a87595a2db /arch/x86
parentf316fe687521fad5ad2fd8389397c38aa97439d2 (diff)
x86: turn the check_exec function into function that
What the check_exec() function really is trying to do is enforce certain bits in the pgprot that are required by the x86 architecture, but that callers might not be aware of (such as NX bit exclusion of the BIOS area for BIOS based PCI access; it's not uncommon to ioremap the BIOS region for various purposes and normally ioremap() memory has the NX bit set). This patch turns the check_exec() function into static_protections() which also is now used to make sure the kernel text area remains non-NX and that the .rodata section remains read-only. If the architecture ends up requiring more such mandatory prot settings for specific areas, this is now a reasonable place to add these. Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/mm/pageattr.c47
1 files changed, 37 insertions, 10 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index cbe8e9223bee..00f6f341e291 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -24,22 +24,49 @@ void clflush_cache_range(void *addr, int size)
24#include <asm/pgalloc.h> 24#include <asm/pgalloc.h>
25 25
26/* 26/*
27 * We allow the BIOS range to be executable: 27 * We must allow the BIOS range to be executable:
28 */ 28 */
29#define BIOS_BEGIN 0x000a0000 29#define BIOS_BEGIN 0x000a0000
30#define BIOS_END 0x00100000 30#define BIOS_END 0x00100000
31 31
32static inline pgprot_t check_exec(pgprot_t prot, unsigned long address) 32static inline int
33within(unsigned long addr, unsigned long start, unsigned long end)
33{ 34{
34 if (__pa(address) >= BIOS_BEGIN && __pa(address) < BIOS_END) 35 return addr >= start && addr < end;
35 pgprot_val(prot) &= ~_PAGE_NX; 36}
37
38/*
39 * Certain areas of memory on x86 require very specific protection flags,
40 * for example the BIOS area or kernel text. Callers don't always get this
41 * right (again, ioremap() on BIOS memory is not uncommon) so this function
42 * checks and fixes these known static required protection bits.
43 */
44static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
45{
46 pgprot_t forbidden = __pgprot(0);
47
36 /* 48 /*
37 * Better fail early if someone sets the kernel text to NX. 49 * The BIOS area between 640k and 1Mb needs to be executable for
38 * Does not cover __inittext 50 * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support.
39 */ 51 */
40 BUG_ON(address >= (unsigned long)&_text && 52 if (within(__pa(address), BIOS_BEGIN, BIOS_END))
41 address < (unsigned long)&_etext && 53 pgprot_val(forbidden) |= _PAGE_NX;
42 (pgprot_val(prot) & _PAGE_NX)); 54
55 /*
56 * The kernel text needs to be executable for obvious reasons
57 * Does not cover __inittext since that is gone later on
58 */
59 if (within(address, (unsigned long)_text, (unsigned long)_etext))
60 pgprot_val(forbidden) |= _PAGE_NX;
61
62#ifdef CONFIG_DEBUG_RODATA
63 /* The .rodata section needs to be read-only */
64 if (within(address, (unsigned long)__start_rodata,
65 (unsigned long)__end_rodata))
66 pgprot_val(forbidden) |= _PAGE_RW;
67#endif
68
69 prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
43 70
44 return prot; 71 return prot;
45} 72}
@@ -169,7 +196,7 @@ repeat:
169 BUG_ON(PageLRU(kpte_page)); 196 BUG_ON(PageLRU(kpte_page));
170 BUG_ON(PageCompound(kpte_page)); 197 BUG_ON(PageCompound(kpte_page));
171 198
172 prot = check_exec(prot, address); 199 prot = static_protections(prot, address);
173 200
174 if (level == PG_LEVEL_4K) { 201 if (level == PG_LEVEL_4K) {
175 set_pte_atomic(kpte, pfn_pte(pfn, canon_pgprot(prot))); 202 set_pte_atomic(kpte, pfn_pte(pfn, canon_pgprot(prot)));