]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] i386 __verify_write fixes
authorBrian Gerst <bgerst@didntduck.org>
Tue, 29 Oct 2002 08:34:07 +0000 (00:34 -0800)
committerChristoph Hellwig <hch@lst.de>
Tue, 29 Oct 2002 08:34:07 +0000 (00:34 -0800)
This patch does a few cleanups/fixes with __verify_write:
 - Only compile it when needed.
 - Move test for KERNEL_DS out of line.
 - The mmap semaphore is needed to access the vma list.
 - Use fixmap for the WP test.
 - Removes an obsolete comment in fixmap.h

arch/i386/kernel/i386_ksyms.c
arch/i386/mm/fault.c
arch/i386/mm/init.c
arch/i386/mm/ioremap.c
include/asm-i386/fixmap.h
include/asm-i386/uaccess.h

index e0c130aabeee5073f5835ad555bff9dfd175e05b..a9038147bb09db2a00f29aa760fdbc3626f81940 100644 (file)
@@ -72,7 +72,9 @@ EXPORT_SYMBOL(pfn_to_nid);
 #ifdef CONFIG_X86_NUMAQ
 EXPORT_SYMBOL(xquad_portio);
 #endif
+#ifndef CONFIG_X86_WP_WORKS_OK
 EXPORT_SYMBOL(__verify_write);
+#endif
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_extended_fpu);
index 9857a3c7e8d1421a2119cb67ffa7574b5f9e6bbb..232aac460eb319eac10f9028ebbcc2106e24270a 100644 (file)
@@ -30,17 +30,20 @@ extern void die(const char *,struct pt_regs *,long);
 
 extern int console_loglevel;
 
+#ifndef CONFIG_X86_WP_WORKS_OK
 /*
  * Ugly, ugly, but the goto's result in better assembly..
  */
 int __verify_write(const void * addr, unsigned long size)
 {
+       struct mm_struct *mm = current->mm;
        struct vm_area_struct * vma;
        unsigned long start = (unsigned long) addr;
 
-       if (!size)
+       if (!size || segment_eq(get_fs(),KERNEL_DS))
                return 1;
 
+       down_read(&mm->mmap_sem);
        vma = find_vma(current->mm, start);
        if (!vma)
                goto bad_area;
@@ -80,6 +83,13 @@ good_area:
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;;
        }
+       /*
+        * We really need to hold mmap_sem over the whole access to
+        * userspace, else another thread could change permissions.
+        * This is unfixable, so don't use i386-class machines for
+        * critical servers.
+        */
+       up_read(&mm->mmap_sem);
        return 1;
 
 check_stack:
@@ -89,6 +99,7 @@ check_stack:
                goto good_area;
 
 bad_area:
+       up_read(&mm->mmap_sem);
        return 0;
 
 out_of_memory:
@@ -98,6 +109,7 @@ out_of_memory:
        }
        goto bad_area;
 }
+#endif
 
 /*
  * Unlock any spinlocks which will prevent us from getting the
index ca8a9d54f1169d66207c3456cd3802db03458507..cd9d8e0700f487ccb7a2963e2758e3055b6183ac 100644 (file)
@@ -378,15 +378,10 @@ void __init paging_init(void)
  * This function cannot be __init, since exceptions don't work in that
  * section.
  */
-static int do_test_wp_bit(unsigned long vaddr);
+static int do_test_wp_bit(void);
 
 void __init test_wp_bit(void)
 {
-       const unsigned long vaddr = PAGE_OFFSET;
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte, old_pte;
-
        if (cpu_has_pse) {
                /* Ok, all PSE-capable CPUs are definitely handling the WP bit right. */
                boot_cpu_data.wp_works_ok = 1;
@@ -395,17 +390,10 @@ void __init test_wp_bit(void)
 
        printk("Checking if this processor honours the WP bit even in supervisor mode... ");
 
-       pgd = swapper_pg_dir + __pgd_offset(vaddr);
-       pmd = pmd_offset(pgd, vaddr);
-       pte = pte_offset_kernel(pmd, vaddr);
-       old_pte = *pte;
-       *pte = pfn_pte(0, PAGE_READONLY);
-       local_flush_tlb();
-
-       boot_cpu_data.wp_works_ok = do_test_wp_bit(vaddr);
-
-       *pte = old_pte;
-       local_flush_tlb();
+       /* Any page-aligned address will do, the test is non-destructive */
+       __set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY);
+       boot_cpu_data.wp_works_ok = do_test_wp_bit();
+       clear_fixmap(FIX_WP_TEST);
 
        if (!boot_cpu_data.wp_works_ok) {
                printk("No.\n");
@@ -550,7 +538,7 @@ void __init pgtable_cache_init(void)
 #endif
 
 /* Put this after the callers, so that it cannot be inlined */
-static int do_test_wp_bit(unsigned long vaddr)
+static int do_test_wp_bit(void)
 {
        char tmp_reg;
        int flag;
@@ -564,7 +552,7 @@ static int do_test_wp_bit(unsigned long vaddr)
                "       .align 4        \n"
                "       .long 1b,2b     \n"
                ".previous              \n"
-               :"=m" (*(char *) vaddr),
+               :"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
                 "=q" (tmp_reg),
                 "=r" (flag)
                :"2" (1)
index 22d82e3b3e9f995154bb010509d1247ddfc2aa34..8a6809bd624e65e2a9ac11a10d151f5406927a8e 100644 (file)
@@ -289,7 +289,7 @@ void __init bt_iounmap(void *addr, unsigned long size)
 
        idx = FIX_BTMAP_BEGIN;
        while (nrpages > 0) {
-               __set_fixmap(idx, 0, __pgprot(0));
+               clear_fixmap(idx);
                --idx;
                --nrpages;
        }
index 831cff57b81420eb242c12d2397c8756999ad508..5cbdbbe4b35dc1d94c1b3af609fef0a573ce2122 100644 (file)
@@ -27,7 +27,7 @@
  * Here we define all the compile-time 'special' virtual
  * addresses. The point is to have a constant address at
  * compile time, but to set the physical address only
- * in the boot process. We allocate these special  addresses
+ * in the boot process. We allocate these special addresses
  * from the end of virtual memory (0xfffff000) backwards.
  * Also this lets us do fail-safe vmalloc(), we
  * can guarantee that these special addresses and
  * TLB entries of such buffers will not be flushed across
  * task switches.
  */
-
-/*
- * on UP currently we will have no trace of the fixmap mechanizm,
- * no page table allocations, etc. This might change in the
- * future, say framebuffers for the console driver(s) could be
- * fix-mapped?
- */
 enum fixed_addresses {
 #ifdef CONFIG_X86_LOCAL_APIC
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
@@ -81,6 +74,7 @@ enum fixed_addresses {
 #define NR_FIX_BTMAPS  16
        FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
        FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
+       FIX_WP_TEST,
        __end_of_fixed_addresses
 };
 
@@ -94,6 +88,10 @@ extern void __set_fixmap (enum fixed_addresses idx,
  */
 #define set_fixmap_nocache(idx, phys) \
                __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+
+#define clear_fixmap(idx) \
+               __set_fixmap(idx, 0, __pgprot(0))
+
 /*
  * used by vmalloc.c.
  *
index ccd1d56ace855ece9b8b6f79e5ad4916596f9717..15d367991bf802b0c433c01e2acb7bb86e83faab 100644 (file)
@@ -64,7 +64,6 @@ int __verify_write(const void *, unsigned long);
 
 #define access_ok(type,addr,size) ( (__range_ok(addr,size) == 0) && \
                         ((type) == VERIFY_READ || boot_cpu_data.wp_works_ok || \
-                        segment_eq(get_fs(),KERNEL_DS) || \
                          __verify_write((void *)(addr),(size))))
 
 #endif