svn commit: r280834 - in head/sys/cddl/dev/dtrace: amd64 i386

Mark Johnston markj at FreeBSD.org
Mon Mar 30 03:55:53 UTC 2015


Author: markj
Date: Mon Mar 30 03:55:51 2015
New Revision: 280834
URL: https://svnweb.freebsd.org/changeset/base/280834

Log:
  Import a missing piece of commit b8fac8e162eda7e98d from illumos-gate.
  
  This adds an upper bound, dtrace_ustackdepth_max, to the number of frames
  traversed when computing the userland stack depth. Some programs - notably
  firefox - are otherwise able to trigger an infinite loop in
  dtrace_getustack_common(), causing a panic.
  
  MFC after:	1 week

Modified:
  head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c
  head/sys/cddl/dev/dtrace/i386/dtrace_isa.c

Modified: head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c
==============================================================================
--- head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c	Sun Mar 29 22:46:07 2015	(r280833)
+++ head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c	Mon Mar 30 03:55:51 2015	(r280834)
@@ -49,6 +49,8 @@ uint16_t dtrace_fuword16_nocheck(void *)
 uint32_t dtrace_fuword32_nocheck(void *);
 uint64_t dtrace_fuword64_nocheck(void *);
 
+int	dtrace_ustackdepth_max = 2048;
+
 void
 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
     uint32_t *intrpc)
@@ -102,14 +104,25 @@ static int
 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
     uintptr_t sp)
 {
+	uintptr_t oldsp;
 	volatile uint16_t *flags =
 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
 	int ret = 0;
 
 	ASSERT(pcstack == NULL || pcstack_limit > 0);
+	ASSERT(dtrace_ustackdepth_max > 0);
 
 	while (pc != 0) {
-		ret++;
+		/*
+		 * We limit the number of times we can go around this
+		 * loop to account for a circular stack.
+		 */
+		if (ret++ >= dtrace_ustackdepth_max) {
+			*flags |= CPU_DTRACE_BADSTACK;
+			cpu_core[curcpu].cpuc_dtrace_illval = sp;
+			break;
+		}
+
 		if (pcstack != NULL) {
 			*pcstack++ = (uint64_t)pc;
 			pcstack_limit--;
@@ -120,10 +133,18 @@ dtrace_getustack_common(uint64_t *pcstac
 		if (sp == 0)
 			break;
 
+		oldsp = sp;
+
 		pc = dtrace_fuword64((void *)(sp +
 			offsetof(struct amd64_frame, f_retaddr)));
 		sp = dtrace_fuword64((void *)sp);
 
+		if (sp == oldsp) {
+			*flags |= CPU_DTRACE_BADSTACK;
+			cpu_core[curcpu].cpuc_dtrace_illval = sp;
+			break;
+		}
+
 		/*
 		 * This is totally bogus:  if we faulted, we're going to clear
 		 * the fault and break.  This is to deal with the apparently

Modified: head/sys/cddl/dev/dtrace/i386/dtrace_isa.c
==============================================================================
--- head/sys/cddl/dev/dtrace/i386/dtrace_isa.c	Sun Mar 29 22:46:07 2015	(r280833)
+++ head/sys/cddl/dev/dtrace/i386/dtrace_isa.c	Mon Mar 30 03:55:51 2015	(r280834)
@@ -55,6 +55,8 @@ uint16_t dtrace_fuword16_nocheck(void *)
 uint32_t dtrace_fuword32_nocheck(void *);
 uint64_t dtrace_fuword64_nocheck(void *);
 
+int	dtrace_ustackdepth_max = 2048;
+
 void
 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
     uint32_t *intrpc)
@@ -113,11 +115,13 @@ dtrace_getustack_common(uint64_t *pcstac
 	uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
 	size_t s1, s2;
 #endif
+	uintptr_t oldsp;
 	volatile uint16_t *flags =
 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
 	int ret = 0;
 
 	ASSERT(pcstack == NULL || pcstack_limit > 0);
+	ASSERT(dtrace_ustackdepth_max > 0);
 
 #ifdef notyet /* XXX signal stack. */
 	if (p->p_model == DATAMODEL_NATIVE) {
@@ -130,7 +134,16 @@ dtrace_getustack_common(uint64_t *pcstac
 #endif
 
 	while (pc != 0) {
-		ret++;
+		/*
+		 * We limit the number of times we can go around this
+		 * loop to account for a circular stack.
+		 */
+		if (ret++ >= dtrace_ustackdepth_max) {
+			*flags |= CPU_DTRACE_BADSTACK;
+			cpu_core[curcpu].cpuc_dtrace_illval = sp;
+			break;
+		}
+
 		if (pcstack != NULL) {
 			*pcstack++ = (uint64_t)pc;
 			pcstack_limit--;
@@ -141,6 +154,8 @@ dtrace_getustack_common(uint64_t *pcstac
 		if (sp == 0)
 			break;
 
+		oldsp = sp;
+
 #ifdef notyet /* XXX signal stack. */ 
 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
 			if (p->p_model == DATAMODEL_NATIVE) {
@@ -179,6 +194,12 @@ dtrace_getustack_common(uint64_t *pcstac
 		sp = dtrace_fuword32((void *)sp);
 #endif /* ! notyet */
 
+		if (sp == oldsp) {
+			*flags |= CPU_DTRACE_BADSTACK;
+			cpu_core[curcpu].cpuc_dtrace_illval = sp;
+			break;
+		}
+
 		/*
 		 * This is totally bogus:  if we faulted, we're going to clear
 		 * the fault and break.  This is to deal with the apparently


More information about the svn-src-all mailing list