aboutsummaryrefslogtreecommitdiff
path: root/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2019-02-21 22:54:17 +0000
committerMark Johnston <markj@FreeBSD.org>2019-02-21 22:54:17 +0000
commit4f1b715c8487f7a6d45083dbe998e82a971f48b4 (patch)
treef9920c102daf3505c78a07f8a93f201192ecf4bb /sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
parentc0ca37d17b451f3eedbb95041475280b721451a7 (diff)
downloadsrc-4f1b715c8487f7a6d45083dbe998e82a971f48b4.tar.gz
src-4f1b715c8487f7a6d45083dbe998e82a971f48b4.zip
Fix a tracepoint lookup race in fasttrap_pid_probe().
fasttrap hooks the userspace breakpoint handler; the hook looks up the breakpoint address in a hash table of tracepoints. It is possible for the tracepoint to be removed by a different thread in between the breakpoint trap and the hash table lookup, in which case SIGTRAP gets delivered to the target process. Fix the problem by adding a per-process generation counter that gets incremented when a tracepoint belonging to that process is removed. Then, when a lookup fails, the trapping instruction is restarted if the thread's counter doesn't match that of the process. Reviewed by: cem MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D19273
Notes
Notes: svn path=/head/; revision=344452
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
index f1fb8906b870..8e6840f27866 100644
--- a/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
+++ b/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
@@ -967,6 +967,7 @@ fasttrap_pid_probe(struct trapframe *tf)
struct reg reg, *rp;
proc_t *p = curproc, *pp;
struct rm_priotracker tracker;
+ uint64_t gen;
uintptr_t pc;
uintptr_t new_pc = 0;
fasttrap_bucket_t *bucket;
@@ -1026,8 +1027,22 @@ fasttrap_pid_probe(struct trapframe *tf)
while (pp->p_vmspace == pp->p_pptr->p_vmspace)
pp = pp->p_pptr;
pid = pp->p_pid;
+ if (pp != p) {
+ PROC_LOCK(pp);
+ if ((pp->p_flag & P_WEXIT) != 0) {
+ /*
+ * This can happen if the child was created with
+ * rfork(2). Userspace tracing cannot work reliably in
+ * such a scenario, but we can at least try.
+ */
+ PROC_UNLOCK(pp);
+ sx_sunlock(&proctree_lock);
+ return (-1);
+ }
+ _PHOLD_LITE(pp);
+ PROC_UNLOCK(pp);
+ }
sx_sunlock(&proctree_lock);
- pp = NULL;
rm_rlock(&fasttrap_tp_lock, &tracker);
#endif
@@ -1051,11 +1066,28 @@ fasttrap_pid_probe(struct trapframe *tf)
if (tp == NULL) {
#ifdef illumos
mutex_exit(pid_mtx);
+ return (-1);
#else
rm_runlock(&fasttrap_tp_lock, &tracker);
-#endif
+ gen = atomic_load_acq_64(&pp->p_fasttrap_tp_gen);
+ if (pp != p)
+ PRELE(pp);
+ if (curthread->t_fasttrap_tp_gen != gen) {
+ /*
+ * At least one tracepoint associated with this PID has
+ * been removed from the table since #BP was raised.
+ * Speculate that we hit a tracepoint that has since
+ * been removed, and retry the instruction.
+ */
+ curthread->t_fasttrap_tp_gen = gen;
+ tf->tf_rip = pc;
+ return (0);
+ }
return (-1);
+#endif
}
+ if (pp != p)
+ PRELE(pp);
/*
* Set the program counter to the address of the traced instruction