]> err.no Git - linux-2.6/commitdiff
x86: turn the check_exec function into function that
authorArjan van de Ven <arjan@linux.intel.com>
Wed, 30 Jan 2008 12:34:04 +0000 (13:34 +0100)
committerIngo Molnar <mingo@elte.hu>
Wed, 30 Jan 2008 12:34:04 +0000 (13:34 +0100)
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>
arch/x86/mm/pageattr.c

index cbe8e9223bee9fa9d40759a5c3ad02b0e7a08a3c..00f6f341e29120ea3c00bf85ee27b338295528c7 100644 (file)
@@ -24,22 +24,49 @@ void clflush_cache_range(void *addr, int size)
 #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_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)));