/* copy the page tables, and set both pte's flag. * note: on Copy On Write, both parent and child process will be marked * write-protected, and increase the reference count of each shared physical * page. * */ int pt_copy(struct pde *npgd, struct pde *opgd){ struct pde *opde, *npde; struct pte *opte, *npte, *old_pt, *new_pt; struct page *pg; uint pdn, pn; for(pdn=PDX(KMEM_END); pdn<1024; pdn++) { opde = &opgd[pdn]; npde = &npgd[pdn]; npde->pd_flag = opde->pd_flag; if (opde->pd_flag & PTE_P) { old_pt = (struct pte*)(opde->pd_off * PAGE); new_pt = (struct pte*)kmalloc(PAGE); npde->pd_off = PPN(new_pt); for(pn=0; pn<1024; pn++){ opte = &old_pt[pn]; npte = &new_pt[pn]; npte->pt_off = opte->pt_off; npte->pt_flag = opte->pt_flag; if (opte->pt_flag & PTE_P) { // turn off each pte's PTE_W npte->pt_flag &= ~PTE_W; opte->pt_flag &= ~PTE_W; // increase the ref count pg = pgfind(opte->pt_off); pg->pg_count++; } } } } return 0; }
/* * set process group (setpgid/old setpgrp) * * caller does setpgid(targpid, targpgid) * * pid must be caller or child of caller (ESRCH) * if a child * pid must be in same session (EPERM) * pid can't have done an exec (EACCES) * if pgid != pid * there must exist some pid in same session having pgid (EPERM) * pid must not be session leader (EPERM) */ int sys_setpgid(struct setpgid_args *uap) { struct proc *curp = curproc; struct proc *targp; /* target process */ struct pgrp *pgrp = NULL; /* target pgrp */ int error; if (uap->pgid < 0) return (EINVAL); if (uap->pid != 0 && uap->pid != curp->p_pid) { if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { if (targp) PRELE(targp); error = ESRCH; targp = NULL; goto done; } lwkt_gettoken(&targp->p_token); /* targp now referenced and its token is held */ if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) { error = EPERM; goto done; } if (targp->p_flags & P_EXEC) { error = EACCES; goto done; } } else { targp = curp; PHOLD(targp); lwkt_gettoken(&targp->p_token); } if (SESS_LEADER(targp)) { error = EPERM; goto done; } if (uap->pgid == 0) { uap->pgid = targp->p_pid; } else if (uap->pgid != targp->p_pid) { if ((pgrp = pgfind(uap->pgid)) == NULL || pgrp->pg_session != curp->p_session) { error = EPERM; goto done; } } error = enterpgrp(targp, uap->pgid, 0); done: if (pgrp) pgrel(pgrp); if (targp) { lwkt_reltoken(&targp->p_token); PRELE(targp); } return (error); }
/* ARGSUSED */ int sys_setpgid(struct proc *curp, void *v, register_t *retval) { struct sys_setpgid_args /* { syscallarg(pid_t) pid; syscallarg(int) pgid; } */ *uap = v; struct process *curpr = curp->p_p; struct process *targpr; /* target process */ struct pgrp *pgrp, *newpgrp; /* target pgrp */ pid_t pid; int pgid, error; pid = SCARG(uap, pid); pgid = SCARG(uap, pgid); if (pgid < 0) return (EINVAL); newpgrp = pool_get(&pgrp_pool, PR_WAITOK); if (pid != 0 && pid != curpr->ps_pid) { if ((targpr = prfind(pid)) == 0 || !inferior(targpr, curpr)) { error = ESRCH; goto out; } if (targpr->ps_session != curpr->ps_session) { error = EPERM; goto out; } if (targpr->ps_flags & PS_EXEC) { error = EACCES; goto out; } } else targpr = curpr; if (SESS_LEADER(targpr)) { error = EPERM; goto out; } if (pgid == 0) pgid = targpr->ps_pid; else if (pgid != targpr->ps_pid) if ((pgrp = pgfind(pgid)) == 0 || pgrp->pg_session != curpr->ps_session) { error = EPERM; goto out; } return (enterpgrp(targpr, pgid, newpgrp, NULL)); out: pool_put(&pgrp_pool, newpgrp); return (error); }
static int sigqkill(pid_t pid, sigsend_t *sigsend) { proc_t *p; int error; if ((uint_t)sigsend->sig >= NSIG) return (EINVAL); if (pid == -1) { procset_t set; setprocset(&set, POP_AND, P_ALL, P_MYID, P_ALL, P_MYID); error = sigsendset(&set, sigsend); } else if (pid > 0) { mutex_enter(&pidlock); if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) error = ESRCH; else { error = sigsendproc(p, sigsend); if (error == 0 && sigsend->perm == 0) error = EPERM; } mutex_exit(&pidlock); } else { int nfound = 0; pid_t pgid; if (pid == 0) pgid = ttoproc(curthread)->p_pgrp; else pgid = -pid; error = 0; mutex_enter(&pidlock); for (p = pgfind(pgid); p && !error; p = p->p_pglink) { if (p->p_stat != SIDL) { nfound++; error = sigsendproc(p, sigsend); } } mutex_exit(&pidlock); if (nfound == 0) error = ESRCH; else if (error == 0 && sigsend->perm == 0) error = EPERM; } return (error); }
/* * Checks for current use of a pid, either as a pid or pgid. */ int pidtaken(pid_t pid) { struct proc *p; if (pfind(pid) != NULL) return (1); if (pgfind(pid) != NULL) return (1); LIST_FOREACH(p, &zombproc, p_list) if (p->p_pid == pid || p->p_pgid == pid) return (1); return (0); }
int sys_setsid(struct setsid_args *uap) { struct proc *p = curproc; struct pgrp *pg = NULL; int error; lwkt_gettoken(&p->p_token); if (p->p_pgid == p->p_pid || (pg = pgfind(p->p_pid)) != NULL) { error = EPERM; if (pg) pgrel(pg); } else { enterpgrp(p, p->p_pid, 1); uap->sysmsg_result = p->p_pid; error = 0; } lwkt_reltoken(&p->p_token); return (error); }
/* ARGSUSED */ int sys_setsid(struct proc *p, void *v, register_t *retval) { struct session *newsess; struct pgrp *newpgrp; struct process *pr = p->p_p; pid_t pid = pr->ps_pid; newsess = pool_get(&session_pool, PR_WAITOK); newpgrp = pool_get(&pgrp_pool, PR_WAITOK); if (pr->ps_pgid == pid || pgfind(pid)) { pool_put(&pgrp_pool, newpgrp); pool_put(&session_pool, newsess); return (EPERM); } else { (void) enterpgrp(pr, pid, newpgrp, newsess); *retval = pid; return (0); } }
/* decrease all the pages' reference count, and free the page tables. */ int pt_free(struct pde *pgd){ struct pde *pde; struct pte *pte, *pt; struct page *pg; uint pdn, pn; for(pdn=PDX(KMEM_END); pdn<1024; pdn++) { pde = &pgd[pdn]; if (pde->pd_flag & PTE_P) { pt = (struct pte*)(pde->pd_off * PAGE); for(pn=0; pn<1024; pn++) { pte = &pt[pn]; if (pte->pt_flag & PTE_P) { pg = pgfind(pte->pt_off); pgfree(pg); } } kfree(pt, PAGE); } } return 0; }
/* * Move p to a new or existing process group (and session) */ int enterpgrp(proc_p p, pid_t pgid, int mksess) { register pgrp_p pgrp = pgfind(pgid); #ifdef DIAGNOSTIC if (pgrp != NULL && mksess) /* firewalls */ panic("enterpgrp: setsid into non-empty pgrp"); if (SESS_LEADER(p)) panic("enterpgrp: session leader attempted setpgrp"); #endif { extern int getpid(); dprintf("%d enterpgrp(p %p (pid: %d),pgid %d,mksess %d) (pgrp = %p pgid: %d)\n", getpid(),p,p ? p->p_pid : -1,pgid,mksess, pgrp,pgrp ? pgrp->pg_id : -1); } if (pgrp == NULL) { pid_t savepid = p->p_pid; proc_p np; /* * new process group */ #ifdef DIAGNOSTIC if (p->p_pid != pgid) panic("enterpgrp: new pgrp and pid != pgid"); #endif if ((np = __pd_pfind(savepid)) == NULL || np != p) return (ESRCH); pgrp = pgrp_alloc(); if (mksess) { session_p sess; /* * new session */ sess = session_alloc(); sess->s_leader = p; sess->s_count = 1; sess->s_ttyp = (struct tty *)0; bcopy(p->p_session->s_login, sess->s_login, sizeof(sess->s_login)); p->p_flag &= ~P_CONTROLT; pgrp->pg_session = sess; } else { pgrp->pg_session = p->p_session; pgrp->pg_session->s_count++; } pgrp->pg_id = pgid; LIST_INIT(&pgrp->pg_members); pgrp->pg_jobc = 0; } else if (pgrp == p->p_pgrp) return (0); /* * Adjust eligibility of affected pgrps to participate in job control. * Increment eligibility counts before decrementing, otherwise we * could reach 0 spuriously during the first call. */ fixjobc(p, pgrp, 1); fixjobc(p, p->p_pgrp, 0); LIST_REMOVE(p, p_pglist); if (p->p_pgrp->pg_members.lh_first == 0) pgdelete(p->p_pgrp); p->p_pgrp = pgrp; LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); return (0); }
/* ARGSUSED */ int setpgrp(int flag, int pid, int pgid) { register proc_t *p = ttoproc(curthread); register int retval = 0; switch (flag) { case 1: /* setpgrp() */ mutex_enter(&pidlock); if (p->p_sessp->s_sidp != p->p_pidp && !pgmembers(p->p_pid)) { mutex_exit(&pidlock); sess_create(); } else mutex_exit(&pidlock); return (p->p_sessp->s_sid); case 3: /* setsid() */ mutex_enter(&pidlock); if (p->p_pgidp == p->p_pidp || pgmembers(p->p_pid)) { mutex_exit(&pidlock); return (set_errno(EPERM)); } mutex_exit(&pidlock); sess_create(); return (p->p_sessp->s_sid); case 5: /* setpgid() */ { mutex_enter(&pidlock); if (pid == 0) pid = p->p_pid; else if (pid < 0 || pid >= maxpid) { mutex_exit(&pidlock); return (set_errno(EINVAL)); } else if (pid != p->p_pid) { for (p = p->p_child; /* empty */; p = p->p_sibling) { if (p == NULL) { mutex_exit(&pidlock); return (set_errno(ESRCH)); } if (p->p_pid == pid) break; } if (p->p_flag & SEXECED) { mutex_exit(&pidlock); return (set_errno(EACCES)); } if (p->p_sessp != ttoproc(curthread)->p_sessp) { mutex_exit(&pidlock); return (set_errno(EPERM)); } } if (p->p_sessp->s_sid == pid) { mutex_exit(&pidlock); return (set_errno(EPERM)); } if (pgid == 0) pgid = p->p_pid; else if (pgid < 0 || pgid >= maxpid) { mutex_exit(&pidlock); return (set_errno(EINVAL)); } if (p->p_pgrp == pgid) { mutex_exit(&pidlock); break; } else if (p->p_pid == pgid) { /* * We need to protect p_pgidp with p_lock because * /proc looks at it while holding only p_lock. */ mutex_enter(&p->p_lock); pgexit(p); pgjoin(p, p->p_pidp); mutex_exit(&p->p_lock); } else { register proc_t *q; if ((q = pgfind(pgid)) == NULL || q->p_sessp != p->p_sessp) { mutex_exit(&pidlock); return (set_errno(EPERM)); } /* * See comment above about p_lock and /proc */ mutex_enter(&p->p_lock); pgexit(p); pgjoin(p, q->p_pgidp); mutex_exit(&p->p_lock); } mutex_exit(&pidlock); break; } case 0: /* getpgrp() */ mutex_enter(&pidlock); retval = p->p_pgrp; mutex_exit(&pidlock); break; case 2: /* getsid() */ case 4: /* getpgid() */ if (pid < 0 || pid >= maxpid) { return (set_errno(EINVAL)); } mutex_enter(&pidlock); if (pid != 0 && p->p_pid != pid && ((p = prfind(pid)) == NULL || p->p_stat == SIDL)) { mutex_exit(&pidlock); return (set_errno(ESRCH)); } if (flag == 2) retval = p->p_sessp->s_sid; else retval = p->p_pgrp; mutex_exit(&pidlock); break; } return (retval); }
/* ARGSUSED */ int sys_ktrace(struct proc *curp, void *v, register_t *retval) { struct sys_ktrace_args /* { syscallarg(const char *) fname; syscallarg(int) ops; syscallarg(int) facs; syscallarg(pid_t) pid; } */ *uap = v; struct vnode *vp = NULL; struct proc *p = NULL; struct pgrp *pg; int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT); int ops = KTROP(SCARG(uap, ops)); int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; int ret = 0; int error = 0; struct nameidata nd; curp->p_traceflag |= KTRFAC_ACTIVE; if (ops != KTROP_CLEAR) { /* * an operation which requires a file argument. */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), curp); if ((error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0)) != 0) { curp->p_traceflag &= ~KTRFAC_ACTIVE; return (error); } vp = nd.ni_vp; VOP_UNLOCK(vp, 0, curp); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); curp->p_traceflag &= ~KTRFAC_ACTIVE; return (EACCES); } } /* * Clear all uses of the tracefile */ if (ops == KTROP_CLEARFILE) { for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list)) { if (p->p_tracep == vp) { if (ktrcanset(curp, p)) { p->p_traceflag = 0; ktrsettracevnode(p, NULL); } else error = EPERM; } } goto done; } /* * need something to (un)trace (XXX - why is this here?) */ if (!facs) { error = EINVAL; goto done; } /* * do it */ if (SCARG(uap, pid) < 0) { /* * by process group */ pg = pgfind(-SCARG(uap, pid)); if (pg == NULL) { error = ESRCH; goto done; } LIST_FOREACH(p, &pg->pg_members, p_pglist) if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); } else {
static int set_proc_info(pid_t pid, const char *path, core_content_t content) { proc_t *p; counter_t counter; int error = 0; counter.cc_count = 0; /* * Only one of the core file path or content can be set at a time. */ if (path != NULL) { counter.cc_path = corectl_path_alloc(path); counter.cc_content = NULL; } else { counter.cc_path = NULL; counter.cc_content = corectl_content_alloc(content); } if (pid == -1) { procset_t set; setprocset(&set, POP_AND, P_ALL, P_MYID, P_ALL, P_MYID); error = dotoprocs(&set, set_one_proc_info, (char *)&counter); if (error == 0 && counter.cc_count == 0) error = EPERM; } else if (pid > 0) { mutex_enter(&pidlock); if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { error = ESRCH; } else { (void) set_one_proc_info(p, &counter); if (counter.cc_count == 0) error = EPERM; } mutex_exit(&pidlock); } else { int nfound = 0; pid_t pgid; if (pid == 0) pgid = curproc->p_pgrp; else pgid = -pid; mutex_enter(&pidlock); for (p = pgfind(pgid); p != NULL; p = p->p_pglink) { if (p->p_stat != SIDL) { nfound++; (void) set_one_proc_info(p, &counter); } } mutex_exit(&pidlock); if (nfound == 0) error = ESRCH; else if (counter.cc_count == 0) error = EPERM; } if (path != NULL) corectl_path_rele(counter.cc_path); else corectl_content_rele(counter.cc_content); if (error) return (set_errno(error)); return (0); }