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
This commit is contained in:
parent
81d4ad979d
commit
57c4e2d807
@ -1089,6 +1089,8 @@ fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index)
|
||||
ASSERT(p->p_proc_flag & P_PR_LOCK);
|
||||
#endif
|
||||
p->p_dtrace_count--;
|
||||
|
||||
atomic_add_rel_64(&p->p_fasttrap_tp_gen, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -37,7 +37,7 @@ typedef struct kdtrace_proc {
|
||||
u_int64_t p_dtrace_count; /* Number of DTrace tracepoints */
|
||||
void *p_dtrace_helpers; /* DTrace helpers, if any */
|
||||
int p_dtrace_model;
|
||||
|
||||
uint64_t p_fasttrap_tp_gen; /* Tracepoint hash table gen */
|
||||
} kdtrace_proc_t;
|
||||
|
||||
/*
|
||||
@ -86,6 +86,7 @@ typedef struct kdtrace_thread {
|
||||
u_int64_t td_hrtime; /* Last time on cpu. */
|
||||
void *td_dtrace_sscr; /* Saved scratch space location. */
|
||||
void *td_systrace_args; /* syscall probe arguments. */
|
||||
uint64_t td_fasttrap_tp_gen; /* Tracepoint hash table gen. */
|
||||
} kdtrace_thread_t;
|
||||
|
||||
/*
|
||||
@ -113,10 +114,12 @@ typedef struct kdtrace_thread {
|
||||
#define t_dtrace_regv td_dtrace->td_dtrace_regv
|
||||
#define t_dtrace_sscr td_dtrace->td_dtrace_sscr
|
||||
#define t_dtrace_systrace_args td_dtrace->td_systrace_args
|
||||
#define t_fasttrap_tp_gen td_dtrace->td_fasttrap_tp_gen
|
||||
#define p_dtrace_helpers p_dtrace->p_dtrace_helpers
|
||||
#define p_dtrace_count p_dtrace->p_dtrace_count
|
||||
#define p_dtrace_probes p_dtrace->p_dtrace_probes
|
||||
#define p_model p_dtrace->p_dtrace_model
|
||||
#define p_fasttrap_tp_gen p_dtrace->p_fasttrap_tp_gen
|
||||
|
||||
#define DATAMODEL_NATIVE 0
|
||||
#ifdef __amd64__
|
||||
|
Loading…
Reference in New Issue
Block a user