Commit ed724be6 authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Ingo Molnar

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: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent f316fe68
...@@ -24,22 +24,49 @@ void clflush_cache_range(void *addr, int size) ...@@ -24,22 +24,49 @@ void clflush_cache_range(void *addr, int size)
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
/* /*
* We allow the BIOS range to be executable: * We must allow the BIOS range to be executable:
*/ */
#define BIOS_BEGIN 0x000a0000 #define BIOS_BEGIN 0x000a0000
#define BIOS_END 0x00100000 #define BIOS_END 0x00100000
static inline pgprot_t check_exec(pgprot_t prot, unsigned long address) static inline int
within(unsigned long addr, unsigned long start, unsigned long end)
{ {
if (__pa(address) >= BIOS_BEGIN && __pa(address) < BIOS_END) return addr >= start && addr < end;
pgprot_val(prot) &= ~_PAGE_NX; }
/*
* Certain areas of memory on x86 require very specific protection flags,
* for example the BIOS area or kernel text. Callers don't always get this
* right (again, ioremap() on BIOS memory is not uncommon) so this function
* checks and fixes these known static required protection bits.
*/
static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
{
pgprot_t forbidden = __pgprot(0);
/* /*
* Better fail early if someone sets the kernel text to NX. * The BIOS area between 640k and 1Mb needs to be executable for
* Does not cover __inittext * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support.
*/ */
BUG_ON(address >= (unsigned long)&_text && if (within(__pa(address), BIOS_BEGIN, BIOS_END))
address < (unsigned long)&_etext && pgprot_val(forbidden) |= _PAGE_NX;
(pgprot_val(prot) & _PAGE_NX));
/*
* The kernel text needs to be executable for obvious reasons
* Does not cover __inittext since that is gone later on
*/
if (within(address, (unsigned long)_text, (unsigned long)_etext))
pgprot_val(forbidden) |= _PAGE_NX;
#ifdef CONFIG_DEBUG_RODATA
/* The .rodata section needs to be read-only */
if (within(address, (unsigned long)__start_rodata,
(unsigned long)__end_rodata))
pgprot_val(forbidden) |= _PAGE_RW;
#endif
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
return prot; return prot;
} }
...@@ -169,7 +196,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot) ...@@ -169,7 +196,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot)
BUG_ON(PageLRU(kpte_page)); BUG_ON(PageLRU(kpte_page));
BUG_ON(PageCompound(kpte_page)); BUG_ON(PageCompound(kpte_page));
prot = check_exec(prot, address); prot = static_protections(prot, address);
if (level == PG_LEVEL_4K) { if (level == PG_LEVEL_4K) {
set_pte_atomic(kpte, pfn_pte(pfn, canon_pgprot(prot))); set_pte_atomic(kpte, pfn_pte(pfn, canon_pgprot(prot)));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment