From: Arjan van de Ven Date: Wed, 30 Jan 2008 12:34:04 +0000 (+0100) Subject: x86: turn the check_exec function into function that X-Git-Tag: v2.6.25-rc1~1143^2~70 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed724be65fa18833244d81b484e425fc838837fa;p=linux-2.6 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 Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index cbe8e9223b..00f6f341e2 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) #include /* - * We allow the BIOS range to be executable: + * We must allow the BIOS range to be executable: */ #define BIOS_BEGIN 0x000a0000 #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) - pgprot_val(prot) &= ~_PAGE_NX; + return addr >= start && addr < end; +} + +/* + * 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. - * Does not cover __inittext + * The BIOS area between 640k and 1Mb needs to be executable for + * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support. */ - BUG_ON(address >= (unsigned long)&_text && - address < (unsigned long)&_etext && - (pgprot_val(prot) & _PAGE_NX)); + if (within(__pa(address), BIOS_BEGIN, BIOS_END)) + pgprot_val(forbidden) |= _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; } @@ -169,7 +196,7 @@ repeat: BUG_ON(PageLRU(kpte_page)); BUG_ON(PageCompound(kpte_page)); - prot = check_exec(prot, address); + prot = static_protections(prot, address); if (level == PG_LEVEL_4K) { set_pte_atomic(kpte, pfn_pte(pfn, canon_pgprot(prot)));