int sys_thr_wakeup(struct thr_wakeup_args *uap) { struct proc *p = curproc; struct proc *pSlave = p->p_leader; struct lwp *lpSlave; while(pSlave && (pSlave->p_pid != uap->pid)) pSlave = pSlave->p_peers; if(pSlave == 0) { uap->sysmsg_result = ESRCH; return(0); } lpSlave = FIRST_LWP_IN_PROC(pSlave); pSlave->p_wakeup++; if((lpSlave->lwp_stat == LSSLEEP) && lpSlave->lwp_wchan == pSlave) { wakeup(pSlave); return(0); } uap->sysmsg_result = EAGAIN; return 0; }
static int procfs_readdir_proc(struct vop_readdir_args *ap) { struct pfsnode *pfs; int error, i, retval; struct proc *p; struct lwp *lp; struct proc_target *pt; struct uio *uio = ap->a_uio; pfs = VTOPFS(ap->a_vp); p = pfs_pfind(pfs->pfs_pid); if (p == NULL) return(0); if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) { error = 0; goto done; } /* XXX lwp, not MPSAFE */ lp = FIRST_LWP_IN_PROC(p); error = 0; i = (int)uio->uio_offset; if (i < 0) { error = EINVAL; goto done; } for (pt = &proc_targets[i]; !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) { if (pt->pt_valid && (*pt->pt_valid)(lp) == 0) continue; retval = vop_write_dirent(&error, uio, PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type, pt->pt_namlen, pt->pt_name); if (retval) break; } uio->uio_offset = (off_t)i; error = 0; done: PRELE(p); return error; }
/* * MPALMOSTSAFE */ int sys_linux_ptrace(struct linux_ptrace_args *uap) { struct thread *td = curthread; struct proc *curp = td->td_proc; union { struct linux_pt_reg reg; struct linux_pt_fpreg fpreg; struct linux_pt_fpxreg fpxreg; } r; union { struct reg bsd_reg; struct fpreg bsd_fpreg; struct dbreg bsd_dbreg; } u; void *addr; pid_t pid; int error, req; struct proc *p = NULL; /* held process */ error = 0; /* by default, just copy data intact */ req = uap->req; pid = (pid_t)uap->pid; addr = (void *)uap->addr; switch (req) { case PTRACE_TRACEME: case PTRACE_POKETEXT: case PTRACE_POKEDATA: case PTRACE_KILL: error = kern_ptrace(curp, req, pid, addr, uap->data, &uap->sysmsg_iresult); break; case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: { /* need to preserve return value, use dummy */ l_int rval = 0; error = kern_ptrace(curp, req, pid, addr, 0, &rval); if (error == 0) { error = copyout(&rval, (caddr_t)uap->data, sizeof(l_int)); } break; } case PTRACE_DETACH: error = kern_ptrace(curp, PT_DETACH, pid, (void *)1, map_signum(uap->data), &uap->sysmsg_iresult); break; case PTRACE_SINGLESTEP: case PTRACE_CONT: error = kern_ptrace(curp, req, pid, (void *)1, map_signum(uap->data), &uap->sysmsg_iresult); break; case PTRACE_ATTACH: error = kern_ptrace(curp, PT_ATTACH, pid, addr, uap->data, &uap->sysmsg_iresult); break; case PTRACE_GETREGS: /* Linux is using data where FreeBSD is using addr */ error = kern_ptrace(curp, PT_GETREGS, pid, &u.bsd_reg, 0, &uap->sysmsg_iresult); if (error == 0) { map_regs_to_linux(&u.bsd_reg, &r.reg); error = copyout(&r.reg, (void *)uap->data, sizeof(r.reg)); } break; case PTRACE_SETREGS: /* Linux is using data where FreeBSD is using addr */ error = copyin((caddr_t)uap->data, &r.reg, sizeof(r.reg)); if (error == 0) { map_regs_from_linux(&u.bsd_reg, &r.reg); error = kern_ptrace(curp, PT_SETREGS, pid, &u.bsd_reg, 0, &uap->sysmsg_iresult); } break; case PTRACE_GETFPREGS: /* Linux is using data where FreeBSD is using addr */ error = kern_ptrace(curp, PT_GETFPREGS, pid, &u.bsd_fpreg, 0, &uap->sysmsg_iresult); if (error == 0) { map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg); error = copyout(&r.fpreg, (caddr_t)uap->data, sizeof(r.fpreg)); } break; case PTRACE_SETFPREGS: /* Linux is using data where FreeBSD is using addr */ error = copyin((caddr_t)uap->data, &r.fpreg, sizeof(r.fpreg)); if (error == 0) { map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg); error = kern_ptrace(curp, PT_SETFPREGS, pid, &u.bsd_fpreg, 0, &uap->sysmsg_iresult); } break; case PTRACE_SETFPXREGS: #ifndef CPU_DISABLE_SSE error = copyin((caddr_t)uap->data, &r.fpxreg, sizeof(r.fpxreg)); if (error) break; #endif /* FALL THROUGH */ case PTRACE_GETFPXREGS: { #ifndef CPU_DISABLE_SSE struct proc *p; struct lwp *lp; if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) { static int once = 0; if (!once) { kprintf("linux: savexmm != linux_pt_fpxreg\n"); once = 1; } error = EIO; break; } if ((p = pfind(uap->pid)) == NULL) { error = ESRCH; break; } if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) { error = ESRCH; 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 != curp) { error = EBUSY; goto fail; } /* not currently stopped */ if ((p->p_flag & (P_TRACED|P_WAITED)) == 0) { error = EBUSY; goto fail; } /* XXX lwp */ lp = FIRST_LWP_IN_PROC(p); if (req == PTRACE_GETFPXREGS) { LWPHOLD(lp); error = linux_proc_read_fpxregs(lp, &r.fpxreg); LWPRELE(lp); if (error == 0) error = copyout(&r.fpxreg, (caddr_t)uap->data, sizeof(r.fpxreg)); } else { /* clear dangerous bits exactly as Linux does*/ r.fpxreg.mxcsr &= 0xffbf; LWPHOLD(lp); error = linux_proc_write_fpxregs(lp, &r.fpxreg); LWPRELE(lp); } break; fail: #else error = EIO; #endif break; } case PTRACE_PEEKUSR: case PTRACE_POKEUSR: { error = EIO; /* check addr for alignment */ if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1)) break; /* * Allow linux programs to access register values in * user struct. We simulate this through PT_GET/SETREGS * as necessary. */ if (uap->addr < sizeof(struct linux_pt_reg)) { error = kern_ptrace(curp, PT_GETREGS, pid, &u.bsd_reg, 0, &uap->sysmsg_iresult); if (error != 0) break; map_regs_to_linux(&u.bsd_reg, &r.reg); if (req == PTRACE_PEEKUSR) { error = copyout((char *)&r.reg + uap->addr, (caddr_t)uap->data, sizeof(l_int)); break; } *(l_int *)((char *)&r.reg + uap->addr) = (l_int)uap->data; map_regs_from_linux(&u.bsd_reg, &r.reg); error = kern_ptrace(curp, PT_SETREGS, pid, &u.bsd_reg, 0, &uap->sysmsg_iresult); } /* * Simulate debug registers access */ if (uap->addr >= LINUX_DBREG_OFFSET && uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) { error = kern_ptrace(curp, PT_GETDBREGS, pid, &u.bsd_dbreg, 0, &uap->sysmsg_iresult); if (error != 0) break; uap->addr -= LINUX_DBREG_OFFSET; if (req == PTRACE_PEEKUSR) { error = copyout((char *)&u.bsd_dbreg + uap->addr, (caddr_t)uap->data, sizeof(l_int)); break; } *(l_int *)((char *)&u.bsd_dbreg + uap->addr) = uap->data; error = kern_ptrace(curp, PT_SETDBREGS, pid, &u.bsd_dbreg, 0, &uap->sysmsg_iresult); } break; } case PTRACE_SYSCALL: /* fall through */ default: kprintf("linux: ptrace(%u, ...) not implemented\n", (unsigned int)uap->req); error = EINVAL; break; } /* * Release held proces (if any) before returning. */ if (p) PRELE(p); return (error); }
/* * lookup. this is incredibly complicated in the general case, however * for most pseudo-filesystems very little needs to be done. * * procfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnp) */ static int procfs_lookup(struct vop_old_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; char *pname = cnp->cn_nameptr; /* struct proc *curp = cnp->cn_proc; */ struct proc_target *pt; pid_t pid; struct pfsnode *pfs; struct proc *p; struct lwp *lp; int i; int error; *vpp = NULL; if (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME) return (EROFS); p = NULL; error = 0; if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; vref(*vpp); goto out; } pfs = VTOPFS(dvp); switch (pfs->pfs_type) { case Proot: if (cnp->cn_flags & CNP_ISDOTDOT) return (EIO); if (CNEQ(cnp, "curproc", 7)) { error = procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc); goto out; } pid = atopid(pname, cnp->cn_namelen); if (pid == NO_PID) break; p = pfs_pfind(pid); if (p == NULL) break; if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred)) break; if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 && ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid) break; error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc); goto out; case Pproc: if (cnp->cn_flags & CNP_ISDOTDOT) { error = procfs_root(dvp->v_mount, vpp); goto out; } p = pfs_pfind(pfs->pfs_pid); if (p == NULL) break; /* XXX lwp */ lp = FIRST_LWP_IN_PROC(p); if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred)) break; if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 && ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid) break; for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { if (cnp->cn_namelen == pt->pt_namlen && bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && (pt->pt_valid == NULL || (*pt->pt_valid)(lp))) goto found; } break; found: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, pt->pt_pfstype); goto out; default: error = ENOTDIR; goto out; } if (cnp->cn_nameiop == NAMEI_LOOKUP) error = ENOENT; else error = EROFS; /* * If no error occured *vpp will hold a referenced locked vnode. * dvp was passed to us locked and *vpp must be returned locked. * If *vpp != dvp then we should unlock dvp if (1) this is not the * last component or (2) CNP_LOCKPARENT is not set. */ out: if (error == 0 && *vpp != dvp) { if ((cnp->cn_flags & CNP_LOCKPARENT) == 0) { cnp->cn_flags |= CNP_PDIRUNLOCK; vn_unlock(dvp); } } if (p) PRELE(p); return (error); }