svn commit: r349016 - in stable/12/sys: amd64/amd64 cddl/contrib/opensolaris/uts/common/dtrace i386/i386

Mark Johnston markj at FreeBSD.org
Thu Jun 13 16:33:57 UTC 2019


Author: markj
Date: Thu Jun 13 16:33:55 2019
New Revision: 349016
URL: https://svnweb.freebsd.org/changeset/base/349016

Log:
  MFC r348742:
  Fix a race between fasttrap and the user breakpoint handler.

Modified:
  stable/12/sys/amd64/amd64/trap.c
  stable/12/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c
  stable/12/sys/i386/i386/trap.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/amd64/amd64/trap.c
==============================================================================
--- stable/12/sys/amd64/amd64/trap.c	Thu Jun 13 16:33:01 2019	(r349015)
+++ stable/12/sys/amd64/amd64/trap.c	Thu Jun 13 16:33:55 2019	(r349016)
@@ -113,6 +113,10 @@ void dblfault_handler(struct trapframe *frame);
 
 static int trap_pfault(struct trapframe *, int);
 static void trap_fatal(struct trapframe *, vm_offset_t);
+#ifdef KDTRACE_HOOKS
+static bool trap_user_dtrace(struct trapframe *,
+    int (**hook)(struct trapframe *));
+#endif
 
 #define MAX_TRAP_MSG		32
 static char *trap_msg[] = {
@@ -284,11 +288,11 @@ trap(struct trapframe *frame)
 			break;
 
 		case T_BPTFLT:		/* bpt instruction fault */
-			enable_intr();
 #ifdef KDTRACE_HOOKS
-			if (dtrace_pid_probe_ptr != NULL &&
-			    dtrace_pid_probe_ptr(frame) == 0)
+			if (trap_user_dtrace(frame, &dtrace_pid_probe_ptr))
 				return;
+#else
+			enable_intr();
 #endif
 			signo = SIGTRAP;
 			ucode = TRAP_BRKPT;
@@ -425,9 +429,7 @@ trap(struct trapframe *frame)
 			break;
 #ifdef KDTRACE_HOOKS
 		case T_DTRACE_RET:
-			enable_intr();
-			if (dtrace_return_probe_ptr != NULL)
-				dtrace_return_probe_ptr(frame);
+			(void)trap_user_dtrace(frame, &dtrace_return_probe_ptr);
 			return;
 #endif
 		}
@@ -947,6 +949,25 @@ trap_fatal(frame, eva)
 	else
 		panic("unknown/reserved trap");
 }
+
+#ifdef KDTRACE_HOOKS
+/*
+ * Invoke a userspace DTrace hook.  The hook pointer is cleared when no
+ * userspace probes are enabled, so we must synchronize with DTrace to ensure
+ * that a trapping thread is able to call the hook before it is cleared.
+ */
+static bool
+trap_user_dtrace(struct trapframe *frame, int (**hookp)(struct trapframe *))
+{
+	int (*hook)(struct trapframe *);
+
+	hook = (int (*)(struct trapframe *))atomic_load_ptr(hookp);
+	enable_intr();
+	if (hook != NULL)
+		return ((hook)(frame) == 0);
+	return (false);
+}
+#endif
 
 /*
  * Double fault handler. Called when a fault occurs while writing

Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c	Thu Jun 13 16:33:01 2019	(r349015)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c	Thu Jun 13 16:33:55 2019	(r349016)
@@ -1125,31 +1125,17 @@ fasttrap_enable_callbacks(void)
 static void
 fasttrap_disable_callbacks(void)
 {
-#ifdef illumos
-	ASSERT(MUTEX_HELD(&cpu_lock));
-#endif
-
-
 	mutex_enter(&fasttrap_count_mtx);
 	ASSERT(fasttrap_pid_count > 0);
 	fasttrap_pid_count--;
 	if (fasttrap_pid_count == 0) {
-#ifdef illumos
-		cpu_t *cur, *cpu = CPU;
-
-		for (cur = cpu->cpu_next_onln; cur != cpu;
-		    cur = cur->cpu_next_onln) {
-			rw_enter(&cur->cpu_ft_lock, RW_WRITER);
-		}
-#endif
+		/*
+		 * Synchronize with the breakpoint handler, which is careful to
+		 * enable interrupts only after loading the hook pointer.
+		 */
+		dtrace_sync();
 		dtrace_pid_probe_ptr = NULL;
 		dtrace_return_probe_ptr = NULL;
-#ifdef illumos
-		for (cur = cpu->cpu_next_onln; cur != cpu;
-		    cur = cur->cpu_next_onln) {
-			rw_exit(&cur->cpu_ft_lock);
-		}
-#endif
 	}
 	mutex_exit(&fasttrap_count_mtx);
 }

Modified: stable/12/sys/i386/i386/trap.c
==============================================================================
--- stable/12/sys/i386/i386/trap.c	Thu Jun 13 16:33:01 2019	(r349015)
+++ stable/12/sys/i386/i386/trap.c	Thu Jun 13 16:33:55 2019	(r349016)
@@ -116,6 +116,10 @@ void syscall(struct trapframe *frame);
 
 static int trap_pfault(struct trapframe *, int, vm_offset_t);
 static void trap_fatal(struct trapframe *, vm_offset_t);
+#ifdef KDTRACE_HOOKS
+static bool trap_user_dtrace(struct trapframe *,
+    int (**hook)(struct trapframe *));
+#endif
 void dblfault_handler(void);
 
 extern inthand_t IDTVEC(bpt), IDTVEC(dbg), IDTVEC(int0x80_syscall);
@@ -321,11 +325,11 @@ trap(struct trapframe *frame)
 			break;
 
 		case T_BPTFLT:		/* bpt instruction fault */
-			enable_intr();
 #ifdef KDTRACE_HOOKS
-			if (dtrace_pid_probe_ptr != NULL &&
-			    dtrace_pid_probe_ptr(frame) == 0)
+			if (trap_user_dtrace(frame, &dtrace_pid_probe_ptr))
 				return;
+#else
+			enable_intr();
 #endif
 			signo = SIGTRAP;
 			ucode = TRAP_BRKPT;
@@ -503,9 +507,7 @@ user_trctrap_out:
 			break;
 #ifdef KDTRACE_HOOKS
 		case T_DTRACE_RET:
-			enable_intr();
-			if (dtrace_return_probe_ptr != NULL)
-				dtrace_return_probe_ptr(frame);
+			(void)trap_user_dtrace(frame, &dtrace_return_probe_ptr);
 			return;
 #endif
 		}
@@ -993,6 +995,25 @@ trap_fatal(frame, eva)
 	else
 		panic("unknown/reserved trap");
 }
+
+#ifdef KDTRACE_HOOKS
+/*
+ * Invoke a userspace DTrace hook.  The hook pointer is cleared when no
+ * userspace probes are enabled, so we must synchronize with DTrace to ensure
+ * that a trapping thread is able to call the hook before it is cleared.
+ */
+static bool
+trap_user_dtrace(struct trapframe *frame, int (**hookp)(struct trapframe *))
+{
+	int (*hook)(struct trapframe *);
+
+	hook = (int (*)(struct trapframe *))atomic_load_ptr(hookp);
+	enable_intr();
+	if (hook != NULL)
+		return ((hook)(frame) == 0);
+	return (false);
+}
+#endif
 
 /*
  * Double fault handler. Called when a fault occurs while writing


More information about the svn-src-all mailing list