kernel - Increase UPAGES, add kernel stack guard page
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 29 Oct 2010 18:58:06 +0000 (11:58 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 29 Oct 2010 18:58:06 +0000 (11:58 -0700)
* Increase UPAGES from 3 to 4.  This is the kernel thread stack size.

* Add infrastructure to make it possible to allocate a guard page along
  with a kmem allocation and use it when allocating kernel thread stacks.

  The first page of stacks allocated this way will be non-accessible
  (hence the increase in UPAGES).

sys/cpu/i386/include/param.h
sys/cpu/x86_64/include/param.h
sys/ddb/db_sysctl.c
sys/kern/lwkt_thread.c
sys/vm/vm_extern.h
sys/vm/vm_fault.c
sys/vm/vm_kern.c
sys/vm/vm_kern.h
sys/vm/vm_map.c
sys/vm/vm_map.h

index 5081138..cb90e4b 100644 (file)
 #define MAXDUMPPGS     (DFLTPHYS/PAGE_SIZE)
 
 #define IOPAGES        2               /* pages of i/o permission bitmap */
-#define UPAGES 3               /* pages of u-area */
+#define UPAGES 4               /* pages of u-area */
 
 /*
  * Ceiling on amount of swblock kva space, can be changed via
index fb283c4..662c44e 100644 (file)
 #define MAXDUMPPGS     (DFLTPHYS/PAGE_SIZE)
 
 #define IOPAGES        2               /* pages of i/o permission bitmap */
-#define UPAGES 3               /* pages of u-area */
+#define UPAGES 4               /* pages of u-area */
 
 /*
  * Ceiling on amount of swblock kva space, can be changed via
index b7f1bbd..4d548f1 100644 (file)
@@ -51,6 +51,9 @@
 #define MODE_DDB       "ddb"
 #define MODE_GDB       "gdb"
 
+/*
+ * This sysctl forces the kernel to enter the debugger.
+ */
 static int
 sysctl_debug_enter_debugger(SYSCTL_HANDLER_ARGS)
 {
@@ -72,7 +75,12 @@ sysctl_debug_enter_debugger(SYSCTL_HANDLER_ARGS)
        }
        return error;
 }
+SYSCTL_PROC(_debug, OID_AUTO, enter_debugger, CTLTYPE_STRING | CTLFLAG_RW,
+    0, 0, sysctl_debug_enter_debugger, "A", DESCRIPTION);
 
+/*
+ * This sysctl forces a kernel panic.
+ */
 static int
 sysctl_debug_panic(SYSCTL_HANDLER_ARGS)
 {
@@ -84,9 +92,34 @@ sysctl_debug_panic(SYSCTL_HANDLER_ARGS)
                panic("sysctl_debug_panic");
        return err;
 }
-
-SYSCTL_PROC(_debug, OID_AUTO, enter_debugger, CTLTYPE_STRING | CTLFLAG_RW,
-    0, 0, sysctl_debug_enter_debugger, "A", DESCRIPTION);
-
 SYSCTL_PROC(_debug, OID_AUTO, panic, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
            sysctl_debug_panic, "I", "Set to panic the system");
+
+/*
+ * This sysctl forces a kernel stack guard panic.  If you don't get
+ * a nice clean page-fault guard panic message then the guard isn't
+ * working.
+ */
+static void
+stack_guard_panic2(void)
+{
+       volatile char dummy[128];
+
+       stack_guard_panic2();
+       /* NOT REACHED */
+       kprintf("%p", dummy);   /* dummy to force dummy[] to be allocated */
+}
+
+static int
+sysctl_debug_panic2(SYSCTL_HANDLER_ARGS)
+{
+       int err;
+       int val = 0;
+
+       err = sysctl_handle_int(oidp, &val, sizeof(val), req);
+       if (val == 1)
+               stack_guard_panic2();
+       return err;
+}
+SYSCTL_PROC(_debug, OID_AUTO, panic2, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+           sysctl_debug_panic2, "I", "Set to panic the system w/stack guard");
index a825189..193da2c 100644 (file)
@@ -316,7 +316,7 @@ lwkt_alloc_thread(struct thread *td, int stksize, int cpu, int flags)
        }
     }
     if (stack == NULL) {
-       stack = (void *)kmem_alloc(&kernel_map, stksize);
+       stack = (void *)kmem_alloc_stack(&kernel_map, stksize);
        flags |= TDF_ALLOCATED_STACK;
     }
     if (cpu < 0)
index 79ad9e5..2ef42ce 100644 (file)
@@ -44,6 +44,9 @@
 #ifndef _VM_VM_MAP_H_
 #include <vm/vm_map.h>
 #endif
+#ifndef _VM_VM_KERN_H_
+#include <vm/vm_kern.h>
+#endif
 #ifndef _MACHINE_TYPES_H_
 #include <machine/types.h>
 #endif
@@ -121,6 +124,13 @@ kmem_alloc (vm_map_t map, vm_size_t size)
        return(kmem_alloc3(map, size, 0));
 }
 
+static __inline
+vm_offset_t
+kmem_alloc_stack (vm_map_t map, vm_size_t size)
+{
+       return(kmem_alloc3(map, size, KM_STACK));
+}
+
 #endif                         /* _KERNEL */
 
 #endif                         /* !_VM_VM_EXTERN_H_ */
index 1cea054..67333ee 100644 (file)
@@ -323,9 +323,17 @@ RetryFault:
         */
        fs.map_generation = fs.map->timestamp;
 
-       if (fs.entry->eflags & MAP_ENTRY_NOFAULT) {
-               panic("vm_fault: fault on nofault entry, addr: %lx",
-                   (u_long)vaddr);
+       if (fs.entry->eflags & (MAP_ENTRY_NOFAULT | MAP_ENTRY_KSTACK)) {
+               if (fs.entry->eflags & MAP_ENTRY_NOFAULT) {
+                       panic("vm_fault: fault on nofault entry, addr: %p",
+                             (void *)vaddr);
+               }
+               if ((fs.entry->eflags & MAP_ENTRY_KSTACK) &&
+                   vaddr >= fs.entry->start &&
+                   vaddr < fs.entry->start + PAGE_SIZE) {
+                       panic("vm_fault: fault on stack guard, addr: %p",
+                             (void *)vaddr);
+               }
        }
 
        /*
@@ -1577,7 +1585,8 @@ vm_fault_wire(vm_map_t map, vm_map_entry_t entry, boolean_t user_wire)
        end = entry->end;
        fictitious = entry->object.vm_object &&
                        (entry->object.vm_object->type == OBJT_DEVICE);
-
+       if (entry->eflags & MAP_ENTRY_KSTACK)
+               start += PAGE_SIZE;
        lwkt_gettoken(&vm_token);
        vm_map_unlock(map);
        map->timestamp++;
@@ -1632,6 +1641,8 @@ vm_fault_unwire(vm_map_t map, vm_map_entry_t entry)
        end = entry->end;
        fictitious = entry->object.vm_object &&
                        (entry->object.vm_object->type == OBJT_DEVICE);
+       if (entry->eflags & MAP_ENTRY_KSTACK)
+               start += PAGE_SIZE;
 
        /*
         * Since the pages are wired down, we must be able to get their
index 5c50538..90e4ef4 100644 (file)
@@ -149,8 +149,10 @@ vm_offset_t
 kmem_alloc3(vm_map_t map, vm_size_t size, int kmflags)
 {
        vm_offset_t addr;
+       vm_offset_t gstart;
        vm_offset_t i;
        int count;
+       int cow;
 
        size = round_page(size);
 
@@ -159,6 +161,14 @@ kmem_alloc3(vm_map_t map, vm_size_t size, int kmflags)
        else
                count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
 
+       if (kmflags & KM_STACK) {
+               cow = MAP_IS_KSTACK;
+               gstart = PAGE_SIZE;
+       } else {
+               cow = 0;
+               gstart = 0;
+       }
+
        /*
         * Use the kernel object for wired-down kernel pages. Assume that no
         * region of the kernel object is referenced more than once.
@@ -181,7 +191,7 @@ kmem_alloc3(vm_map_t map, vm_size_t size, int kmflags)
                      &kernel_object, addr, addr, addr + size,
                      VM_MAPTYPE_NORMAL,
                      VM_PROT_ALL, VM_PROT_ALL,
-                     0);
+                     cow);
        vm_map_unlock(map);
        if (kmflags & KM_KRESERVE)
                vm_map_entry_krelease(count);
@@ -205,9 +215,8 @@ kmem_alloc3(vm_map_t map, vm_size_t size, int kmflags)
         * We're intentionally not activating the pages we allocate to prevent a
         * race with page-out.  vm_map_wire will wire the pages.
         */
-
        lwkt_gettoken(&vm_token);
-       for (i = 0; i < size; i += PAGE_SIZE) {
+       for (i = gstart; i < size; i += PAGE_SIZE) {
                vm_page_t mem;
 
                mem = vm_page_grab(&kernel_object, OFF_TO_IDX(addr + i),
@@ -222,6 +231,8 @@ kmem_alloc3(vm_map_t map, vm_size_t size, int kmflags)
 
        /*
         * And finally, mark the data as non-pageable.
+        *
+        * NOTE: vm_map_wire() handles any kstack guard.
         */
        vm_map_wire(map, (vm_offset_t)addr, addr + size, kmflags);
 
index 0baf937..2bd0160 100644 (file)
@@ -80,6 +80,7 @@
  */
 #define KM_PAGEABLE    0x0001
 #define KM_KRESERVE    0x0002
+#define KM_STACK       0x0004
 
 /* Kernel memory management definitions. */
 extern struct vm_map buffer_map;
index 7bb2bac..49f3a65 100644 (file)
@@ -908,6 +908,8 @@ vm_map_insert(vm_map_t map, int *countp,
                protoeflags |= MAP_ENTRY_NOCOREDUMP;
        if (cow & MAP_IS_STACK)
                protoeflags |= MAP_ENTRY_STACK;
+       if (cow & MAP_IS_KSTACK)
+               protoeflags |= MAP_ENTRY_KSTACK;
 
        lwkt_gettoken(&vm_token);
        lwkt_gettoken(&vmobj_token);
index eb43d70..5061ffb 100644 (file)
@@ -173,6 +173,7 @@ struct vm_map_entry {
 #define MAP_ENTRY_IN_TRANSITION                0x0100  /* entry being changed */
 #define MAP_ENTRY_NEEDS_WAKEUP         0x0200  /* waiter's in transition */
 #define MAP_ENTRY_NOCOREDUMP           0x0400  /* don't include in a core */
+#define MAP_ENTRY_KSTACK               0x0800  /* guarded kernel stack */
 
 /*
  * flags for vm_map_[un]clip_range()
@@ -455,6 +456,7 @@ vmspace_president_count(struct vmspace *vmspace)
 #define MAP_PREFAULT_PARTIAL   0x0010
 #define MAP_DISABLE_SYNCER     0x0020
 #define MAP_IS_STACK           0x0040
+#define MAP_IS_KSTACK          0x0080
 #define MAP_DISABLE_COREDUMP   0x0100
 #define MAP_PREFAULT_MADVISE   0x0200  /* from (user) madvise request */