o Fix race condition caused by doing ptrace() for permission

checking, followed by a lookup of the process. Do not call
   ptrace() for permission checking, but do it inline.
   Spotted by: rwatson

o  While here, copy-in arguments before we lock. This fixes
   a possible permanent lock.

Reviewed by: rwatson
This commit is contained in:
marcel 2002-05-19 19:35:36 +00:00
parent b834e5849a
commit 982963acb9

View File

@ -360,11 +360,17 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
break;
}
case PTRACE_SETFPXREGS:
#ifdef CPU_ENABLE_SSA
error = copyin((caddr_t)uap->data, &r.fpxreg,
sizeof(r.fpxreg));
if (error)
break;
#endif
/* FALL THROUGH */
case PTRACE_GETFPXREGS: {
#ifdef CPU_ENABLE_SSE
struct proc *p;
struct thread *td2;
struct fpreg *bsd_r;
if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) {
static int once = 0;
@ -376,23 +382,38 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
break;
}
/*
* Use FreeBSD PT_GETFPREGS for permisson testing. If it
* fails, PTRACE_GETFPXREGS should fail for the same reason.
*/
bsd_r = (struct fpreg*)stackgap_alloc(&sg, sizeof(*bsd_r));
bsd_args.req = PT_GETFPREGS;
bsd_args.addr = (caddr_t)bsd_r;
bsd_args.data = 0;
error = ptrace(td, &bsd_args);
if (error != 0)
break;
if ((p = pfind(uap->pid)) == NULL) {
error = ESRCH;
break;
}
if ((error = p_candebug(td, p)) != 0)
goto fail;
/* System processes can't be debugged. */
if ((p->p_flag & P_SYSTEM) != 0) {
error = EINVAL;
goto fail;
}
/* not being traced... */
if ((p->p_flag & P_TRACED) == 0) {
error = EPERM;
goto fail;
}
/* not being traced by YOU */
if (p->p_pptr != td->td_proc) {
error = EBUSY;
goto fail;
}
/* not currently stopped */
if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) {
error = EBUSY;
goto fail;
}
td2 = FIRST_THREAD_IN_PROC(p);
if (uap->req == PTRACE_GETFPXREGS) {
_PHOLD(p);
@ -403,18 +424,17 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
error = copyout(&r.fpxreg, (caddr_t)uap->data,
sizeof(r.fpxreg));
} else {
error = copyin((caddr_t)uap->data, &r.fpxreg,
sizeof(r.fpxreg));
if (error == 0) {
/* clear dangerous bits exactly as Linux does*/
r.fpxreg.mxcsr &= 0xffbf;
_PHOLD(p);
error = linux_proc_write_fpxregs(
td2, &r.fpxreg);
_PRELE(p);
PROC_UNLOCK(p);
}
/* clear dangerous bits exactly as Linux does*/
r.fpxreg.mxcsr &= 0xffbf;
_PHOLD(p);
error = linux_proc_write_fpxregs(td2, &r.fpxreg);
_PRELE(p);
PROC_UNLOCK(p);
}
break;
fail:
PROC_UNLOCK(p);
#else
error = EIO;
#endif