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-stable-12
mailing list