diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/mm/pageattr.c | 47 |
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 | ||
32 | static inline pgprot_t check_exec(pgprot_t prot, unsigned long address) | 32 | static inline int |
33 | within(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 | */ | ||
44 | static 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))); |