summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/sys_process.c200
1 files changed, 114 insertions, 86 deletions
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index ab830f3..42cdebc 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -332,35 +332,73 @@ ptrace(struct thread *td, struct ptrace_args *uap)
struct fpreg fpreg;
struct reg reg;
} r;
- struct proc *curp, *p;
+ struct proc *p;
struct thread *td2;
int error, write;
+ int proctree_locked = 0;
- curp = td->td_proc;
- error = 0;
+ /*
+ * Do copyin() early before getting locks and lock proctree before
+ * locking the process.
+ */
+ switch (uap->req) {
+ case PT_TRACE_ME:
+ case PT_ATTACH:
+ case PT_STEP:
+ case PT_CONTINUE:
+ case PT_DETACH:
+ sx_xlock(&proctree_lock);
+ proctree_locked = 1;
+ break;
+#ifdef PT_SETREGS
+ case PT_SETREGS:
+ error = copyin(uap->addr, &r.reg, sizeof r.reg);
+ if (error)
+ return (error);
+ break;
+#endif /* PT_SETREGS */
+#ifdef PT_SETFPREGS
+ case PT_SETFPREGS:
+ error = copyin(uap->addr, &r.fpreg, sizeof r.fpreg);
+ if (error)
+ return (error);
+ break;
+#endif /* PT_SETFPREGS */
+#ifdef PT_SETDBREGS
+ case PT_SETDBREGS:
+ error = copyin(uap->addr, &r.dbreg, sizeof r.dbreg);
+ if (error)
+ return (error);
+ break;
+#endif /* PT_SETDBREGS */
+ default:
+ }
+
write = 0;
if (uap->req == PT_TRACE_ME) {
- p = curp;
+ p = td->td_proc;
PROC_LOCK(p);
} else {
- if ((p = pfind(uap->pid)) == NULL)
+ if ((p = pfind(uap->pid)) == NULL) {
+ if (proctree_locked)
+ sx_xunlock(&proctree_lock);
return (ESRCH);
+ }
}
- if (p_cansee(curp, p)) {
- PROC_UNLOCK(p);
- return (ESRCH);
- }
- if ((error = p_candebug(curp, p)) != 0) {
- PROC_UNLOCK(p);
- return (error);
+ if (p_cansee(td->td_proc, p)) {
+ error = ESRCH;
+ goto fail;
}
+ if ((error = p_candebug(td->td_proc, p)) != 0)
+ goto fail;
+
/*
* System processes can't be debugged.
*/
if ((p->p_flag & P_SYSTEM) != 0) {
- PROC_UNLOCK(p);
- return (EINVAL);
+ error = EINVAL;
+ goto fail;
}
/*
@@ -373,15 +411,15 @@ ptrace(struct thread *td, struct ptrace_args *uap)
case PT_ATTACH:
/* Self */
- if (p->p_pid == curp->p_pid) {
- PROC_UNLOCK(p);
- return (EINVAL);
+ if (p->p_pid == td->td_proc->p_pid) {
+ error = EINVAL;
+ goto fail;
}
/* Already traced */
if (p->p_flag & P_TRACED) {
- PROC_UNLOCK(p);
- return (EBUSY);
+ error = EBUSY;
+ goto fail;
}
/* OK */
@@ -404,35 +442,31 @@ ptrace(struct thread *td, struct ptrace_args *uap)
case PT_SETDBREGS:
/* not being traced... */
if ((p->p_flag & P_TRACED) == 0) {
- PROC_UNLOCK(p);
- return (EPERM);
+ error = EPERM;
+ goto fail;
}
/* not being traced by YOU */
- if (p->p_pptr != curp) {
- PROC_UNLOCK(p);
- return (EBUSY);
+ if (p->p_pptr != td->td_proc) {
+ error = EBUSY;
+ goto fail;
}
/* not currently stopped */
- mtx_lock_spin(&sched_lock);
if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) {
- mtx_unlock_spin(&sched_lock);
- PROC_UNLOCK(p);
- return (EBUSY);
+ error = EBUSY;
+ goto fail;
}
- mtx_unlock_spin(&sched_lock);
/* OK */
break;
default:
- PROC_UNLOCK(p);
- return (EINVAL);
+ error = EINVAL;
+ goto fail;
}
td2 = FIRST_THREAD_IN_PROC(p);
- PROC_UNLOCK(p);
#ifdef FIX_SSTEP
/*
* Single step fixup ala procfs
@@ -449,8 +483,6 @@ ptrace(struct thread *td, struct ptrace_args *uap)
switch (uap->req) {
case PT_TRACE_ME:
/* set my trace flag and "owner" so it can read/write me */
- sx_xlock(&proctree_lock);
- PROC_LOCK(p);
p->p_flag |= P_TRACED;
p->p_oppid = p->p_pptr->p_pid;
PROC_UNLOCK(p);
@@ -459,14 +491,10 @@ ptrace(struct thread *td, struct ptrace_args *uap)
case PT_ATTACH:
/* security check done above */
- sx_xlock(&proctree_lock);
- PROC_LOCK(p);
p->p_flag |= P_TRACED;
p->p_oppid = p->p_pptr->p_pid;
- if (p->p_pptr != curp)
- proc_reparent(p, curp);
- PROC_UNLOCK(p);
- sx_xunlock(&proctree_lock);
+ if (p->p_pptr != td->td_proc)
+ proc_reparent(p, td->td_proc);
uap->data = SIGSTOP;
goto sendsig; /* in PT_CONTINUE below */
@@ -474,38 +502,38 @@ ptrace(struct thread *td, struct ptrace_args *uap)
case PT_CONTINUE:
case PT_DETACH:
/* XXX uap->data is used even in the PT_STEP case. */
- if (uap->req != PT_STEP && (unsigned)uap->data >= NSIG)
- return (EINVAL);
+ if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG)) {
+ error = EINVAL;
+ goto fail;
+ }
- PHOLD(p);
+ _PHOLD(p);
if (uap->req == PT_STEP) {
error = ptrace_single_step(td2);
if (error) {
- PRELE(p);
- return (error);
+ _PRELE(p);
+ goto fail;
}
}
if (uap->addr != (caddr_t)1) {
- PROC_LOCK(p);
fill_kinfo_proc(p, &p->p_uarea->u_kproc);
- PROC_UNLOCK(p);
error = ptrace_set_pc(td2,
(u_long)(uintfptr_t)uap->addr);
if (error) {
- PRELE(p);
- return (error);
+ _PRELE(p);
+ goto fail;
}
}
- PRELE(p);
+ _PRELE(p);
if (uap->req == PT_DETACH) {
/* reset process parent */
- sx_xlock(&proctree_lock);
if (p->p_oppid != p->p_pptr->p_pid) {
struct proc *pp;
+ PROC_UNLOCK(p);
pp = pfind(p->p_oppid);
if (pp == NULL)
pp = initproc;
@@ -513,30 +541,26 @@ ptrace(struct thread *td, struct ptrace_args *uap)
PROC_UNLOCK(pp);
PROC_LOCK(p);
proc_reparent(p, pp);
- } else
- PROC_LOCK(p);
+ }
p->p_flag &= ~(P_TRACED | P_WAITED);
p->p_oppid = 0;
- PROC_UNLOCK(p);
- sx_xunlock(&proctree_lock);
/* should we send SIGCHLD? */
}
sendsig:
+ if (proctree_locked)
+ sx_xunlock(&proctree_lock);
/* deliver or queue signal */
- PROC_LOCK(p);
- mtx_lock_spin(&sched_lock);
if (p->p_stat == SSTOP) {
p->p_xstat = uap->data;
+ mtx_lock_spin(&sched_lock);
setrunnable(td2); /* XXXKSE */
mtx_unlock_spin(&sched_lock);
- } else {
- mtx_unlock_spin(&sched_lock);
- if (uap->data)
- psignal(p, uap->data);
- }
+ } else if (uap->data)
+ psignal(p, uap->data);
PROC_UNLOCK(p);
+
return (0);
case PT_WRITE_I:
@@ -545,6 +569,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
/* fallthrough */
case PT_READ_I:
case PT_READ_D:
+ PROC_UNLOCK(p);
/* write = 0 set above */
iov.iov_base = write ? (caddr_t)&uap->data :
(caddr_t)td->td_retval;
@@ -606,52 +631,49 @@ ptrace(struct thread *td, struct ptrace_args *uap)
goto sendsig; /* in PT_CONTINUE above */
case PT_SETREGS:
- error = copyin(uap->addr, &r.reg, sizeof r.reg);
- if (error == 0) {
- PHOLD(p);
- error = proc_write_regs(td2, &r.reg);
- PRELE(p);
- }
+ _PHOLD(p);
+ error = proc_write_regs(td2, &r.reg);
+ _PRELE(p);
+ PROC_UNLOCK(p);
return (error);
case PT_GETREGS:
- PHOLD(p);
+ _PHOLD(p);
error = proc_read_regs(td2, &r.reg);
- PRELE(p);
+ _PRELE(p);
+ PROC_UNLOCK(p);
if (error == 0)
error = copyout(&r.reg, uap->addr, sizeof r.reg);
return (error);
case PT_SETFPREGS:
- error = copyin(uap->addr, &r.fpreg, sizeof r.fpreg);
- if (error == 0) {
- PHOLD(p);
- error = proc_write_fpregs(td2, &r.fpreg);
- PRELE(p);
- }
+ _PHOLD(p);
+ error = proc_write_fpregs(td2, &r.fpreg);
+ _PRELE(p);
+ PROC_UNLOCK(p);
return (error);
case PT_GETFPREGS:
- PHOLD(p);
+ _PHOLD(p);
error = proc_read_fpregs(td2, &r.fpreg);
- PRELE(p);
+ _PRELE(p);
+ PROC_UNLOCK(p);
if (error == 0)
error = copyout(&r.fpreg, uap->addr, sizeof r.fpreg);
return (error);
case PT_SETDBREGS:
- error = copyin(uap->addr, &r.dbreg, sizeof r.dbreg);
- if (error == 0) {
- PHOLD(p);
- error = proc_write_dbregs(td2, &r.dbreg);
- PRELE(p);
- }
+ _PHOLD(p);
+ error = proc_write_dbregs(td2, &r.dbreg);
+ _PRELE(p);
+ PROC_UNLOCK(p);
return (error);
case PT_GETDBREGS:
- PHOLD(p);
+ _PHOLD(p);
error = proc_read_dbregs(td2, &r.dbreg);
- PRELE(p);
+ _PRELE(p);
+ PROC_UNLOCK(p);
if (error == 0)
error = copyout(&r.dbreg, uap->addr, sizeof r.dbreg);
return (error);
@@ -663,6 +685,12 @@ ptrace(struct thread *td, struct ptrace_args *uap)
KASSERT(0, ("unreachable code\n"));
return (0);
+
+fail:
+ PROC_UNLOCK(p);
+ if (proctree_locked)
+ sx_xunlock(&proctree_lock);
+ return (error);
}
int
OpenPOWER on IntegriCloud