Subject: kernel stack overflow detection
To: None <tech-kern@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 05/30/2002 23:05:20
----Next_Part(Thu_May_30_23:05:20_2002_346)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
hi.
I made patches to detect kernel stack overflow.
(because i've seen some overflow on recent i386..)
# alloc 1 more page for kernel stack so that
# kernel stack overflow doesn't cause destruction.
# (i386 only. but i think it's easy for other archs, too)
options KSTACK_SAFE
# detect kernel stack overflow using debug register.
# (i386 only)
options KSTACK_CHECK_DR0
# detect kernel stack overflow using magic number.
# (MI)
options KSTACK_CHECK_MAGIC
comments?
---
YAMAMOTO Takashi<yamt@mwd.biglobe.ne.jp>
----Next_Part(Thu_May_30_23:05:20_2002_346)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="kstack.diff"
Index: kern_fork.c
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/kern/kern_fork.c,v
retrieving revision 1.88
diff -u -p -r1.88 kern_fork.c
--- kern_fork.c 2001/12/08 00:35:30 1.88
+++ kern_fork.c 2002/05/30 13:42:58
@@ -81,6 +81,7 @@
__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.88 2001/12/08 00:35:30 thorpej Exp $");
#include "opt_ktrace.h"
+#include "opt_kstack.h"
#include "opt_multiprocessor.h"
#include <sys/param.h>
@@ -101,6 +102,66 @@ __KERNEL_RCSID(0, "$NetBSD: kern_fork.c,
#include <sys/sched.h>
#include <sys/signalvar.h>
+#ifdef KSTACK_CHECK_MAGIC
+#include <sys/user.h>
+
+#define KSTACK_MAGIC 0xdeadbeaf
+
+void kstack_setup_magic(const struct proc *);
+void kstack_check_magic(const struct proc *);
+
+void
+kstack_setup_magic(const struct proc *p)
+{
+ KASSERT(p != 0);
+ KASSERT(p != &proc0);
+
+ /*
+ * setup magic number on the top of the kernel stack
+ * so that later modification on it can be detected.
+ */
+ *(u_int32_t *)KSTACK_END(p) = KSTACK_MAGIC;
+}
+
+void
+kstack_check_magic(const struct proc *p)
+{
+ static int dont_check;
+
+ KASSERT(p != 0);
+
+ if (dont_check)
+ return;
+
+ /* don't check proc0 */ /*XXX*/
+ if (p == &proc0)
+ return;
+
+ if (*(u_int32_t *)KSTACK_END(p) != KSTACK_MAGIC) {
+#ifndef KSTACK_SAFE
+ /* XXX should panic? */
+#endif
+ printf("kernel stack magic changed for pid %u: "
+ "maybe kernel stack overflow\n", p->p_pid);
+
+#ifdef KSTACK_SAFE
+ /*
+ * no more checks.
+ * if kernel stack once overflow, it's enough bad..
+ */
+ dont_check = 1;
+ printf("kernel stack magic check disabled\n");
+#else
+ /*
+ * re-setup magic
+ * XXX this will break stack more..
+ */
+ kstack_setup_magic(p);
+#endif
+ }
+}
+#endif /*KSTACK_CHECK_MAGIC*/
+
#include <sys/syscallargs.h>
#include <uvm/uvm_extern.h>
@@ -376,6 +437,9 @@ fork1(struct proc *p1, int flags, int ex
stack, stacksize,
(func != NULL) ? func : child_return,
(arg != NULL) ? arg : p2);
+#ifdef KSTACK_CHECK_MAGIC
+ kstack_setup_magic(p2);
+#endif
/*
* BEGIN PID ALLOCATION.
Index: kern_synch.c
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/kern/kern_synch.c,v
retrieving revision 1.108
diff -u -p -r1.108 kern_synch.c
--- kern_synch.c 2002/05/21 01:38:27 1.108
+++ kern_synch.c 2002/05/30 13:42:58
@@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_synch.c
#include "opt_ddb.h"
#include "opt_ktrace.h"
+#include "opt_kstack.h"
#include "opt_lockdebug.h"
#include "opt_multiprocessor.h"
@@ -95,6 +96,11 @@ __KERNEL_RCSID(0, "$NetBSD: kern_synch.c
#include <sys/resourcevar.h>
#include <sys/sched.h>
+#ifdef KSTACK_CHECK_MAGIC
+/* XXX should be in proc.h or user.h */
+void kstack_check_magic(const struct proc *);
+#endif
+
#include <uvm/uvm_extern.h>
#ifdef KTRACE
@@ -847,6 +853,10 @@ mi_switch(struct proc *p)
* scheduling flags.
*/
spc->spc_flags &= ~SPCF_SWITCHCLEAR;
+
+#ifdef KSTACK_CHECK_MAGIC
+ kstack_check_magic(p);
+#endif
/*
* Pick a new current process and switch to it. When we
Index: param.h
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/sys/param.h,v
retrieving revision 1.140
diff -u -p -r1.140 param.h
--- param.h 2002/05/22 03:29:09 1.140
+++ param.h 2002/05/30 13:43:10
@@ -277,6 +277,14 @@
#ifdef _KERNEL
/*
+ * kernel stack paramaters
+ */
+#ifndef SHAM_USPACE
+#define SHAM_USPACE USPACE
+#endif
+#define KSTACK_END(p) ((caddr_t)ALIGN((p)->p_addr + 1) + USPACE - SHAM_USPACE)
+
+/*
* macro to convert from milliseconds to hz without integer overflow
* Default version using only 32bits arithmetics.
* 64bit port can define 64bit version in their <machine/param.h>
Index: files
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/conf/files,v
retrieving revision 1.531
diff -u -p -r1.531 files
--- files 2002/05/22 05:49:57 1.531
+++ files 2002/05/30 13:43:34
@@ -138,6 +138,7 @@ defparam opt_kgdb.h KGDB_DEV KGDB_DEVNA
KGDB_DEVADDR KGDB_DEVRATE KGDB_DEVMODE
defflag LOCKDEBUG
defflag SYSCALL_DEBUG
+defflag opt_kstack.h KSTACK_CHECK_MAGIC
# memory (ram) disk options
#
Index: files.i386
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/conf/files.i386,v
retrieving revision 1.206
diff -u -p -r1.206 files.i386
--- files.i386 2002/04/18 12:54:12 1.206
+++ files.i386 2002/05/30 13:44:02
@@ -57,6 +57,10 @@ defparam opt_pcibios.h PCIBIOS_IRQS_HINT
# Large page size
defflag LARGEPAGES
+# kernel stack debug
+defflag opt_kstack_safe.h KSTACK_SAFE
+defflag opt_kstack_dr0.h KSTACK_CHECK_DR0
+
file arch/i386/i386/autoconf.c
file arch/i386/i386/bus_machdep.c
file arch/i386/i386/conf.c
Index: trap.c
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/i386/trap.c,v
retrieving revision 1.165
diff -u -p -r1.165 trap.c
--- trap.c 2002/02/18 15:58:02 1.165
+++ trap.c 2002/05/30 13:44:28
@@ -86,6 +86,7 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.1
#include "opt_math_emulate.h"
#include "opt_vm86.h"
#include "opt_cputype.h"
+#include "opt_kstack_dr0.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -155,6 +156,26 @@ int trapdebug = 0;
#define IDTVEC(name) __CONCAT(X, name)
+#ifdef KSTACK_CHECK_DR0
+/* XXX should be in cpufunc.h */
+static __inline u_int
+rdr6(void)
+{
+ u_int val;
+
+ __asm __volatile("movl %%dr6,%0" : "=r" (val));
+ return val;
+}
+
+/* XXX should be in cpufunc.h */
+static __inline void
+ldr6(u_int val)
+{
+
+ __asm __volatile("movl %0,%%dr6" : : "r" (val));
+}
+#endif
+
/*
* trap(frame):
* Exception, fault, and trap interface to BSD kernel. This
@@ -202,6 +223,22 @@ trap(frame)
default:
we_re_toast:
+#ifdef KSTACK_CHECK_DR0
+ if (type == T_TRCTRAP) {
+ u_int mask, dr6 = rdr6();
+
+ mask = 1 << 0; /* dr0 */
+ if (dr6 & mask) {
+#ifndef KSTACK_SAFE
+ /* XXX should panic? */
+#endif
+ printf("trap on DR0: maybe kernel stack overflow\n");
+ dr6 &= ~mask;
+ ldr6(dr6);
+ return;
+ }
+ }
+#endif
#ifdef KGDB
if (kgdb_trap(type, &frame))
return;
Index: pmap.c
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/i386/pmap.c,v
retrieving revision 1.136
diff -u -p -r1.136 pmap.c
--- pmap.c 2002/03/27 04:47:28 1.136
+++ pmap.c 2002/05/30 13:44:29
@@ -65,6 +65,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.1
#include "opt_cputype.h"
#include "opt_user_ldt.h"
#include "opt_largepages.h"
+#include "opt_kstack_dr0.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -1654,6 +1655,11 @@ pmap_ldt_cleanup(p)
}
#endif /* USER_LDT */
+#ifdef KSTACK_CHECK_DR0
+/* XXX should be in cpufunc.h or somewhere */
+void dr0(caddr_t, u_int32_t, u_int32_t, u_int32_t);
+#endif
+
/*
* pmap_activate: activate a process' pmap (fill in %cr3 and LDT info)
*
@@ -1675,6 +1681,16 @@ pmap_activate(p)
lcr3(pcb->pcb_cr3);
if (pcb == curpcb)
lldt(pcb->pcb_ldt_sel);
+
+#ifdef KSTACK_CHECK_DR0
+ /*
+ * setup breakpoint on the top of stack
+ */
+ if (p == &proc0)
+ dr0(0, 0, 0, 0);
+ else
+ dr0(KSTACK_END(p), 1, 3, 1);
+#endif
}
/*
Index: param.h
===================================================================
RCS file: /cvs/cvsroot/syssrc/sys/arch/i386/include/param.h,v
retrieving revision 1.48
diff -u -p -r1.48 param.h
--- param.h 2002/02/26 15:13:23 1.48
+++ param.h 2002/05/30 13:45:00
@@ -90,7 +90,17 @@
#define SSIZE 1 /* initial stack size/NBPG */
#define SINCR 1 /* increment of stack/NBPG */
-#define UPAGES 2 /* pages of u-area */
+
+#if defined(_KERNEL_OPT)
+#include "opt_kstack_safe.h"
+#endif
+#define SHAM_UPAGES 2
+#define SHAM_USPACE (SHAM_UPAGES * NBPG)
+#ifdef KSTACK_SAFE
+#define UPAGES (SHAM_UPAGES + 1) /* "real" pages of u-area */
+#else
+#define UPAGES SHAM_UPAGES /* pages of u-area */
+#endif
#define USPACE (UPAGES * NBPG) /* total size of u-area */
#ifndef MSGBUFSIZE
----Next_Part(Thu_May_30_23:05:20_2002_346)----