MFC r263329:

Only invoke fasttrap hooks for traps from user mode, and ensure that they're
called with interrupts enabled. Calling fasttrap_pid_probe() with interrupts
disabled can lead to deadlock if fasttrap writes to the process' address
space.
This commit is contained in:
markj 2014-07-29 20:33:18 +00:00
parent 2bf1f15393
commit 8116ff7597
2 changed files with 42 additions and 38 deletions

View File

@ -193,6 +193,9 @@ SYSCTL_INT(_machdep, OID_AUTO, uprintf_signal, CTLFLAG_RW,
void
trap(struct trapframe *frame)
{
#ifdef KDTRACE_HOOKS
struct reg regs;
#endif
struct thread *td = curthread;
struct proc *p = td->td_proc;
int i = 0, ucode = 0, code;
@ -244,28 +247,10 @@ trap(struct trapframe *frame)
/*
* A trap can occur while DTrace executes a probe. Before
* executing the probe, DTrace blocks re-scheduling and sets
* a flag in it's per-cpu flags to indicate that it doesn't
* a flag in its per-cpu flags to indicate that it doesn't
* want to fault. On returning from the probe, the no-fault
* flag is cleared and finally re-scheduling is enabled.
*
* If the DTrace kernel module has registered a trap handler,
* call it and if it returns non-zero, assume that it has
* handled the trap and modified the trap frame so that this
* function can return normally.
*/
if (type == T_DTRACE_RET || type == T_BPTFLT) {
struct reg regs;
fill_frame_regs(frame, &regs);
if (type == T_BPTFLT &&
dtrace_pid_probe_ptr != NULL &&
dtrace_pid_probe_ptr(&regs) == 0)
goto out;
else if (type == T_DTRACE_RET &&
dtrace_return_probe_ptr != NULL &&
dtrace_return_probe_ptr(&regs) == 0)
goto out;
}
if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type))
goto out;
#endif
@ -320,6 +305,14 @@ trap(struct trapframe *frame)
case T_BPTFLT: /* bpt instruction fault */
case T_TRCTRAP: /* trace trap */
enable_intr();
#ifdef KDTRACE_HOOKS
if (type == T_BPTFLT) {
fill_frame_regs(frame, &regs);
if (dtrace_pid_probe_ptr != NULL &&
dtrace_pid_probe_ptr(&regs) == 0)
goto out;
}
#endif
frame->tf_rflags &= ~PSL_T;
i = SIGTRAP;
ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT);
@ -449,6 +442,15 @@ trap(struct trapframe *frame)
goto userout;
i = SIGFPE;
break;
#ifdef KDTRACE_HOOKS
case T_DTRACE_RET:
enable_intr();
fill_frame_regs(frame, &regs);
if (dtrace_return_probe_ptr != NULL &&
dtrace_return_probe_ptr(&regs) == 0)
goto out;
break;
#endif
}
} else {
/* kernel trap */

View File

@ -207,6 +207,9 @@ SYSCTL_INT(_machdep, OID_AUTO, uprintf_signal, CTLFLAG_RW,
void
trap(struct trapframe *frame)
{
#ifdef KDTRACE_HOOKS
struct reg regs;
#endif
struct thread *td = curthread;
struct proc *p = td->td_proc;
int i = 0, ucode = 0, code;
@ -263,28 +266,10 @@ trap(struct trapframe *frame)
/*
* A trap can occur while DTrace executes a probe. Before
* executing the probe, DTrace blocks re-scheduling and sets
* a flag in it's per-cpu flags to indicate that it doesn't
* a flag in its per-cpu flags to indicate that it doesn't
* want to fault. On returning from the probe, the no-fault
* flag is cleared and finally re-scheduling is enabled.
*
* If the DTrace kernel module has registered a trap handler,
* call it and if it returns non-zero, assume that it has
* handled the trap and modified the trap frame so that this
* function can return normally.
*/
if (type == T_DTRACE_RET || type == T_BPTFLT) {
struct reg regs;
fill_frame_regs(frame, &regs);
if (type == T_BPTFLT &&
dtrace_pid_probe_ptr != NULL &&
dtrace_pid_probe_ptr(&regs) == 0)
goto out;
if (type == T_DTRACE_RET &&
dtrace_return_probe_ptr != NULL &&
dtrace_return_probe_ptr(&regs) == 0)
goto out;
}
if ((type == T_PROTFLT || type == T_PAGEFLT) &&
dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type))
goto out;
@ -358,6 +343,14 @@ trap(struct trapframe *frame)
case T_BPTFLT: /* bpt instruction fault */
case T_TRCTRAP: /* trace trap */
enable_intr();
#ifdef KDTRACE_HOOKS
if (type == T_BPTFLT) {
fill_frame_regs(frame, &regs);
if (dtrace_pid_probe_ptr != NULL &&
dtrace_pid_probe_ptr(&regs) == 0)
goto out;
}
#endif
frame->tf_eflags &= ~PSL_T;
i = SIGTRAP;
ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT);
@ -541,6 +534,15 @@ trap(struct trapframe *frame)
#endif
i = SIGFPE;
break;
#ifdef KDTRACE_HOOKS
case T_DTRACE_RET:
enable_intr();
fill_frame_regs(frame, &regs);
if (dtrace_return_probe_ptr != NULL &&
dtrace_return_probe_ptr(&regs) == 0)
goto out;
break;
#endif
}
} else {
/* kernel trap */