On 20/10/17(Fri) 11:50, Martin Pieuchot wrote:
> On 14/10/17(Sat) 22:07, Philip Guenther wrote:
> >
> > The diff below adds proctreelk, an rwlock protecting the links of the
> > process tree and related bits, as well as uidinfolk, an rwlock protecting
> > the uidinfo hash table.
> >
> > Parts of this are based on FreeBSD's proctree_lock, particularly the
> > reorganization of enterpgrp() into enternewpgrp() and enterthispgrp() and
> > the splitting out of killjobc() from exit1().
> >
> > This diff should address the previously reported crashes seen when using
> > ktrace(2) while creating/exiting processes.
> >
> > This has been stable for quite a while under my usage; please test and
> > report any issues.
>
> First of all, I'm very happy to see this diff. Thanks Philip.
>
> I have been running this diff on my amd64 NFS client/server build
> machine since you posted it. So far no issue, so it is stable for
> this usage as well.
>
> I'd however appreciate if you could commit the killjobc() and
> enter*grp() refactoring first. Because in case of revert this
> would be less pain.
I've done that.
> That's also for this reason that I introduced a macro for the
> NET_LOCK(). So I could enable/disable it without having to revert
> N files. No idea if this could be useful there two.
>
> I like the way you annotate the protected elements in the structure.
> I'll try to do the same for bpf.
>
> I'm also suggesting you commit the `uidinfolk' bits first. This seems
> quite safe. In this exact part, what about introducing a uid_release(),
> a wrapper around rw_exit_write(&uidinfolk), to be called after uid_find()?
> This way you can keep the lock local.
And that too, here's an updated/rebased diff.
Index: sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.247
diff -u -p -r1.247 proc.h
--- sys/proc.h 26 Feb 2018 13:43:51 -0000 1.247
+++ sys/proc.h 26 Feb 2018 16:47:58 -0000
@@ -44,6 +44,7 @@
#include <sys/selinfo.h> /* For struct selinfo */
#include <sys/syslimits.h> /* For LOGIN_NAME_MAX */
#include <sys/queue.h>
+#include <sys/rwlock.h> /* For struct rwlock */
#include <sys/timeout.h> /* For struct timeout */
#include <sys/event.h> /* For struct klist */
#include <sys/mutex.h> /* For struct mutex */
@@ -55,16 +56,25 @@
#endif
/*
+ * Locks used to protect struct members in this file:
+ * I immutable after creation
+ * t proctreelk
+ *
+ * If multiple locks are listed then all are required for writes,
+ * but any one of them is sufficient for reads.
+ */
+
+/*
* One structure allocated per session.
*/
struct process;
struct session {
int s_count; /* Ref cnt; pgrps in session. */
- struct process *s_leader; /* Session leader. */
+ struct process *s_leader; /* [t] Session leader. */
struct vnode *s_ttyvp; /* Vnode of controlling terminal. */
- struct tty *s_ttyp; /* Controlling terminal. */
- char s_login[LOGIN_NAME_MAX]; /* Setlogin() name. */
- pid_t s_verauthppid;
+ struct tty *s_ttyp; /* [t] Controlling terminal. */
+ char s_login[LOGIN_NAME_MAX];/* setlogin() name. */
+ pid_t s_verauthppid; /* TIOCSETVERAUTH info */
uid_t s_verauthuid;
struct timeout s_verauthto;
};
@@ -75,10 +85,10 @@ void zapverauth(/* struct session */ voi
* One structure allocated per process group.
*/
struct pgrp {
- LIST_ENTRY(pgrp) pg_hash; /* Hash chain. */
- LIST_HEAD(, process) pg_members;/* Pointer to pgrp members. */
- struct session *pg_session; /* Pointer to session. */
- pid_t pg_id; /* Pgrp id. */
+ LIST_ENTRY(pgrp) pg_hash; /* [t] Hash chain. */
+ LIST_HEAD(, process) pg_members;/* [t] Pointer to pgrp members. */
+ struct session *pg_session; /* [I] Pointer to session. */
+ pid_t pg_id; /* [I] Pgrp id. */
int pg_jobc; /* # procs qualifying pgrp for job control */
};
@@ -156,17 +166,17 @@ struct process {
LIST_ENTRY(process) ps_list; /* List of all processes. */
TAILQ_HEAD(,proc) ps_threads; /* Threads in this process. */
- LIST_ENTRY(process) ps_pglist; /* List of processes in pgrp. */
- struct process *ps_pptr; /* Pointer to parent process. */
- LIST_ENTRY(process) ps_sibling; /* List of sibling processes. */
- LIST_HEAD(, process) ps_children;/* Pointer to list of children. */
+ LIST_ENTRY(process) ps_pglist; /* [t] List of processes in pgrp. */
+ struct process *ps_pptr; /* [t] Pointer to parent process. */
+ LIST_ENTRY(process) ps_sibling; /* [t] List of sibling processes. */
+ LIST_HEAD(, process) ps_children;/* [t] Pointer to list of children. */
LIST_ENTRY(process) ps_hash; /* Hash chain. */
struct sigacts *ps_sigacts; /* Signal actions, state */
struct vnode *ps_textvp; /* Vnode of executable. */
struct filedesc *ps_fd; /* Ptr to open files structure */
struct vmspace *ps_vmspace; /* Address space */
- pid_t ps_pid; /* Process identifier. */
+ pid_t ps_pid; /* [I] Process identifier. */
/* The following fields are all zeroed upon creation in process_new. */
#define ps_startzero ps_klist
@@ -180,7 +190,7 @@ struct process {
struct vnode *ps_tracevp; /* Trace to vnode. */
struct ucred *ps_tracecred; /* Creds for writing trace */
- pid_t ps_oppid; /* Save parent pid during ptrace. */
+ pid_t ps_oppid; /* [t] Save parent pid during ptrace. */
int ps_ptmask; /* Ptrace event mask */
struct ptrace_state *ps_ptstat;/* Ptrace state */
@@ -197,7 +207,7 @@ struct process {
/* The following fields are all copied upon creation in process_new. */
#define ps_startcopy ps_limit
struct plimit *ps_limit; /* Process limits. */
- struct pgrp *ps_pgrp; /* Pointer to process group. */
+ struct pgrp *ps_pgrp; /* [t] Pointer to process group. */
struct emul *ps_emul; /* Emulation information */
char ps_comm[MAXCOMLEN+1];
@@ -475,6 +485,7 @@ LIST_HEAD(processlist, process);
extern struct processlist allprocess; /* List of all processes. */
extern struct processlist zombprocess; /* List of zombie processes. */
extern struct proclist allproc; /* List of all threads. */
+extern struct rwlock proctreelk; /* parent/child, pgrp, session */
extern struct process *initprocess; /* Process slot for init. */
extern struct proc *reaperproc; /* Thread slot for reaper. */
Index: sys/ucred.h
===================================================================
RCS file: /cvs/src/sys/sys/ucred.h,v
retrieving revision 1.12
diff -u -p -r1.12 ucred.h
--- sys/ucred.h 19 Feb 2018 08:59:53 -0000 1.12
+++ sys/ucred.h 26 Feb 2018 16:47:58 -0000
@@ -67,8 +67,10 @@ struct xucred {
gid_t cr_groups[NGROUPS_MAX]; /* groups */
};
-#ifdef _KERNEL
-#define crhold(cr) (cr)->cr_ref++
+#if defined(_KERNEL) && !defined(_STANDALONE)
+#include <sys/atomic.h>
+
+#define crhold(cr) atomic_inc_int(&(cr)->cr_ref)
int crfromxucred(struct ucred *, const struct xucred *);
void crset(struct ucred *, const struct ucred *);
@@ -79,6 +81,6 @@ struct ucred *crget(void);
int suser(struct proc *p);
int suser_ucred(struct ucred *cred);
-#endif /* _KERNEL */
+#endif /* _KERNEL && !_STANDALONE */
#endif /* !_SYS_UCRED_H_ */
Index: kern/exec_elf.c
===================================================================
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.142
diff -u -p -r1.142 exec_elf.c
--- kern/exec_elf.c 30 Dec 2017 23:08:29 -0000 1.142
+++ kern/exec_elf.c 26 Feb 2018 16:47:57 -0000
@@ -1168,12 +1168,14 @@ coredump_notes_elf(struct proc *p, void
cpi.cpi_sigcatch = pr->ps_sigacts->ps_sigcatch;
cpi.cpi_pid = pr->ps_pid;
+ rw_enter_read(&proctreelk);
cpi.cpi_ppid = pr->ps_pptr->ps_pid;
cpi.cpi_pgrp = pr->ps_pgid;
if (pr->ps_session->s_leader)
cpi.cpi_sid = pr->ps_session->s_leader->ps_pid;
else
cpi.cpi_sid = 0;
+ rw_exit_read(&proctreelk);
cpi.cpi_ruid = p->p_ucred->cr_ruid;
cpi.cpi_euid = p->p_ucred->cr_uid;
Index: kern/kern_acct.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_acct.c,v
retrieving revision 1.35
diff -u -p -r1.35 kern_acct.c
--- kern/kern_acct.c 19 Feb 2018 08:59:52 -0000 1.35
+++ kern/kern_acct.c 26 Feb 2018 16:47:57 -0000
@@ -206,11 +206,13 @@ acct_process(struct proc *p)
acct.ac_gid = pr->ps_ucred->cr_rgid;
/* (7) The terminal from which the process was started */
+ rw_enter_read(&proctreelk);
if ((pr->ps_flags & PS_CONTROLT) &&
pr->ps_pgrp->pg_session->s_ttyp)
acct.ac_tty = pr->ps_pgrp->pg_session->s_ttyp->t_dev;
else
acct.ac_tty = NODEV;
+ rw_exit_read(&proctreelk);
/* (8) The boolean flags that tell how the process terminated, etc. */
acct.ac_flag = pr->ps_acflag;
Index: kern/kern_exec.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.193
diff -u -p -r1.193 kern_exec.c
--- kern/kern_exec.c 2 Jan 2018 06:38:45 -0000 1.193
+++ kern/kern_exec.c 26 Feb 2018 16:47:57 -0000
@@ -509,9 +509,11 @@ sys_execve(struct proc *p, void *v, regi
atomic_setbits_int(&pr->ps_flags, PS_EXEC);
if (pr->ps_flags & PS_PPWAIT) {
+ rw_enter_read(&proctreelk);
atomic_clearbits_int(&pr->ps_flags, PS_PPWAIT);
atomic_clearbits_int(&pr->ps_pptr->ps_flags, PS_ISPWAIT);
wakeup(pr->ps_pptr);
+ rw_exit_read(&proctreelk);
}
/*
Index: kern/kern_exit.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exit.c,v
retrieving revision 1.164
diff -u -p -r1.164 kern_exit.c
--- kern/kern_exit.c 10 Feb 2018 10:32:51 -0000 1.164
+++ kern/kern_exit.c 26 Feb 2018 16:47:58 -0000
@@ -212,11 +212,7 @@ exit1(struct proc *p, int rv, int flags)
* thread of a process that isn't PS_NOZOMBIE, we'll put
* the process on the zombprocess list below.
*/
- /*
- * NOTE: WE ARE NO LONGER ALLOWED TO SLEEP!
- */
- p->p_stat = SDEAD;
-
+ rw_enter_write(&proctreelk);
LIST_REMOVE(p, p_hash);
LIST_REMOVE(p, p_list);
@@ -264,6 +260,7 @@ exit1(struct proc *p, int rv, int flags)
}
}
}
+ rw_exit_write(&proctreelk);
/* add thread's accumulated rusage into the process's total */
ruadd(rup, &p->p_ru);
@@ -292,9 +289,13 @@ exit1(struct proc *p, int rv, int flags)
* wait4() to return ECHILD.
*/
if (pr->ps_flags & PS_NOZOMBIE) {
- struct process *ppr = pr->ps_pptr;
+ struct process *ppr;
+
+ rw_enter_write(&proctreelk);
+ ppr = pr->ps_pptr;
proc_reparent(pr, initprocess);
wakeup(ppr);
+ rw_exit_write(&proctreelk);
}
/*
@@ -312,6 +313,11 @@ exit1(struct proc *p, int rv, int flags)
}
/*
+ * NOTE: WE ARE NO LONGER ALLOWED TO SLEEP!
+ */
+ p->p_stat = SDEAD;
+
+ /*
* Other substructures are freed from reaper and wait().
*/
@@ -413,6 +419,7 @@ reaper(void)
/* Release the rest of the process's vmspace */
uvm_exit(pr);
+ rw_enter_write(&proctreelk);
if ((pr->ps_flags & PS_NOZOMBIE) == 0) {
/* Process is now a true zombie. */
atomic_setbits_int(&pr->ps_flags, PS_ZOMBIE);
@@ -420,6 +427,7 @@ reaper(void)
/* Wake up the parent so it can get exit
status. */
wakeup(pr->ps_pptr);
+ rw_exit_write(&proctreelk);
} else {
/* No one will wait for us. Just zap the
process now */
process_zap(pr);
@@ -473,6 +481,7 @@ dowait4(struct proc *q, pid_t pid, int *
return (EINVAL);
loop:
+ rw_enter_write(&proctreelk);
nfound = 0;
LIST_FOREACH(pr, &q->p_p->ps_children, ps_sibling) {
if ((pr->ps_flags & PS_NOZOMBIE) ||
@@ -498,6 +507,7 @@ loop:
(pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
pr->ps_single->p_stat == SSTOP &&
(pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
+ rw_exit_write(&proctreelk);
single_thread_wait(pr);
atomic_setbits_int(&pr->ps_flags, PS_WAITED);
@@ -521,6 +531,7 @@ loop:
*statusp = W_STOPCODE(p->p_xstat);
if (rusage != NULL)
memset(rusage, 0, sizeof(*rusage));
+ rw_exit_write(&proctreelk);
return (0);
}
if ((options & WCONTINUED) && (p->p_flag & P_CONTINUED)) {
@@ -531,16 +542,21 @@ loop:
*statusp = _WCONTINUED;
if (rusage != NULL)
memset(rusage, 0, sizeof(*rusage));
+ rw_exit_write(&proctreelk);
return (0);
}
}
- if (nfound == 0)
+ if (nfound == 0) {
+ rw_exit_write(&proctreelk);
return (ECHILD);
+ }
if (options & WNOHANG) {
+ rw_exit_write(&proctreelk);
retval[0] = 0;
return (0);
}
- if ((error = tsleep(q->p_p, PWAIT | PCATCH, "wait", 0)) != 0)
+ if ((error = rwsleep(q->p_p, &proctreelk, PWAIT | PCATCH | PNORELOCK,
+ "wait", 0)) != 0)
return (error);
goto loop;
}
@@ -551,6 +567,8 @@ proc_finish_wait(struct proc *waiter, st
struct process *pr, *tr;
struct rusage *rup;
+ rw_assert_wrlock(&proctreelk);
+
/*
* If we got the child via a ptrace 'attach',
* we need to give it back to the old parent.
@@ -562,6 +580,7 @@ proc_finish_wait(struct proc *waiter, st
proc_reparent(pr, tr);
prsignal(tr, SIGCHLD);
wakeup(tr);
+ rw_exit_write(&proctreelk);
} else {
scheduler_wait_hook(waiter, p);
p->p_xstat = 0;
@@ -580,6 +599,7 @@ void
proc_reparent(struct process *child, struct process *parent)
{
+ rw_assert_wrlock(&proctreelk);
if (child->ps_pptr == parent)
return;
@@ -594,12 +614,15 @@ process_zap(struct process *pr)
struct vnode *otvp;
struct proc *p = pr->ps_mainproc;
+ rw_assert_wrlock(&proctreelk);
+
/*
* Finally finished with old proc entry.
* Unlink it from its process group and free it.
*/
leavepgrp(pr);
LIST_REMOVE(pr, ps_sibling);
+ rw_exit_write(&proctreelk);
/*
* Decrement the count of procs running with this uid.
Index: kern/kern_fork.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.202
diff -u -p -r1.202 kern_fork.c
--- kern/kern_fork.c 30 Dec 2017 20:47:00 -0000 1.202
+++ kern/kern_fork.c 26 Feb 2018 16:47:58 -0000
@@ -224,7 +224,6 @@ process_new(struct proc *p, struct proce
(caddr_t)&pr->ps_endcopy - (caddr_t)&pr->ps_startcopy);
process_initialize(pr, p);
- pr->ps_pid = allocpid();
/* post-copy fixups */
pr->ps_pptr = parent;
@@ -269,10 +268,9 @@ process_new(struct proc *p, struct proce
/* mark as embryo to protect against others */
pr->ps_flags |= PS_EMBRYO;
- /* Force visibility of all of the above changes */
- membar_producer();
-
/* it's sufficiently inited to be globally visible */
+ rw_enter_write(&proctreelk);
+ pr->ps_pid = allocpid();
LIST_INSERT_HEAD(&allprocess, pr, ps_list);
return pr;
@@ -373,6 +371,7 @@ fork1(struct proc *curp, int flags, void
/*
* From now on, we're committed to the fork and cannot fail.
+ * process_new() returns with proctreelk held!
*/
p = thread_new(curp, uaddr);
pr = process_new(p, curpr, flags);
@@ -447,6 +446,7 @@ fork1(struct proc *curp, int flags, void
pr->ps_ptstat->pe_other_pid = curpr->ps_pid;
}
}
+ rw_exit_write(&proctreelk);
/*
* For new processes, set accounting bits and mark as complete.
Index: kern/kern_ktrace.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_ktrace.c,v
retrieving revision 1.95
diff -u -p -r1.95 kern_ktrace.c
--- kern/kern_ktrace.c 19 Feb 2018 08:59:52 -0000 1.95
+++ kern/kern_ktrace.c 26 Feb 2018 16:47:58 -0000
@@ -448,6 +448,7 @@ doktrace(struct vnode *vp, int ops, int
/*
* do it
*/
+ rw_enter_read(&proctreelk);
if (pid < 0) {
/*
* by process group
@@ -455,7 +456,7 @@ doktrace(struct vnode *vp, int ops, int
pg = pgfind(-pid);
if (pg == NULL) {
error = ESRCH;
- goto done;
+ goto done2;
}
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
if (descend)
@@ -471,7 +472,7 @@ doktrace(struct vnode *vp, int ops, int
pr = prfind(pid);
if (pr == NULL) {
error = ESRCH;
- goto done;
+ goto done2;
}
if (descend)
ret |= ktrsetchildren(p, pr, ops, facs, vp, cred);
@@ -480,6 +481,8 @@ doktrace(struct vnode *vp, int ops, int
}
if (!ret)
error = EPERM;
+done2:
+ rw_exit_read(&proctreelk);
done:
return (error);
}
@@ -548,6 +551,8 @@ ktrsetchildren(struct proc *curp, struct
{
struct process *pr;
int ret = 0;
+
+ rw_assert_rdlock(&proctreelk);
pr = top;
for (;;) {
Index: kern/kern_proc.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_proc.c,v
retrieving revision 1.82
diff -u -p -r1.82 kern_proc.c
--- kern/kern_proc.c 26 Feb 2018 13:43:51 -0000 1.82
+++ kern/kern_proc.c 26 Feb 2018 16:47:58 -0000
@@ -67,6 +67,8 @@ u_long pgrphash;
struct processlist allprocess;
struct processlist zombprocess;
struct proclist allproc;
+struct rwlock proctreelk;
+struct rwlock uidinfolk;
struct pool proc_pool;
struct pool process_pool;
@@ -93,6 +95,7 @@ procinit(void)
LIST_INIT(&zombprocess);
LIST_INIT(&allproc);
+ rw_init(&proctreelk, "proctree");
rw_init(&uidinfolk, "uidinfo");
tidhashtbl = hashinit(maxthread / 4, M_PROC, M_NOWAIT, &tidhash);
@@ -140,6 +143,7 @@ uid_find(uid_t uid)
if (uip->ui_uid == uid)
break;
if (uip) {
+ /* XXX unlock uidinfolk across the free()? */
free(nuip, M_PROC, sizeof(*nuip));
return (uip);
}
@@ -180,6 +184,7 @@ int
inferior(struct process *pr, struct process *parent)
{
+ rw_assert_wrlock(&proctreelk);
for (; pr != parent; pr = pr->ps_pptr)
if (pr->ps_pid == 0 || pr->ps_pid == 1)
return (0);
@@ -222,6 +227,7 @@ pgfind(pid_t pgid)
{
struct pgrp *pgrp;
+ rw_assert_anylock(&proctreelk);
LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash)
if (pgrp->pg_id == pgid)
return (pgrp);
@@ -250,6 +256,8 @@ zombiefind(pid_t pid)
void
enternewpgrp(struct process *pr, struct pgrp *pgrp, struct session *newsess)
{
+ rw_assert_wrlock(&proctreelk);
+
#ifdef DIAGNOSTIC
if (SESS_LEADER(pr))
panic("%s: session leader attempted setpgrp", __func__);
@@ -292,6 +300,8 @@ enterthispgrp(struct process *pr, struct
{
struct pgrp *savepgrp = pr->ps_pgrp;
+ rw_assert_wrlock(&proctreelk);
+
/*
* Adjust eligibility of affected pgrps to participate in job control.
* Increment eligibility counts before decrementing, otherwise we
@@ -302,6 +312,7 @@ enterthispgrp(struct process *pr, struct
LIST_REMOVE(pr, ps_pglist);
pr->ps_pgrp = pgrp;
+
LIST_INSERT_HEAD(&pgrp->pg_members, pr, ps_pglist);
if (LIST_EMPTY(&savepgrp->pg_members))
pgdelete(savepgrp);
@@ -314,6 +325,7 @@ void
leavepgrp(struct process *pr)
{
+ rw_assert_wrlock(&proctreelk);
if (pr->ps_session->s_verauthppid == pr->ps_pid)
zapverauth(pr->ps_session);
LIST_REMOVE(pr, ps_pglist);
@@ -329,6 +341,7 @@ void
pgdelete(struct pgrp *pgrp)
{
+ rw_assert_wrlock(&proctreelk);
if (pgrp->pg_session->s_ttyp != NULL &&
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
@@ -362,6 +375,8 @@ fixjobc(struct process *pr, struct pgrp
struct pgrp *hispgrp;
struct session *mysession = pgrp->pg_session;
+ rw_assert_wrlock(&proctreelk);
+
/*
* Check pr's parent to see whether pr qualifies its own process
* group; if so, adjust count for pr's process group.
@@ -393,6 +408,7 @@ fixjobc(struct process *pr, struct pgrp
void
killjobc(struct process *pr)
{
+ rw_enter_write(&proctreelk);
if (SESS_LEADER(pr)) {
struct session *sp = pr->ps_session;
@@ -430,6 +446,7 @@ killjobc(struct process *pr)
sp->s_leader = NULL;
}
fixjobc(pr, pr->ps_pgrp, 0);
+ rw_exit_write(&proctreelk);
}
/*
@@ -442,6 +459,7 @@ orphanpg(struct pgrp *pg)
{
struct process *pr;
+ rw_assert_wrlock(&proctreelk);
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
if (pr->ps_mainproc->p_stat == SSTOP) {
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
Index: kern/kern_prot.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_prot.c,v
retrieving revision 1.73
diff -u -p -r1.73 kern_prot.c
--- kern/kern_prot.c 20 Feb 2018 12:38:58 -0000 1.73
+++ kern/kern_prot.c 26 Feb 2018 16:47:58 -0000
@@ -83,7 +83,9 @@ int
sys_getppid(struct proc *p, void *v, register_t *retval)
{
+ rw_enter_read(&proctreelk);
*retval = p->p_p->ps_pptr->ps_pid;
+ rw_exit_read(&proctreelk);
return (0);
}
@@ -92,7 +94,9 @@ int
sys_getpgrp(struct proc *p, void *v, register_t *retval)
{
+ rw_enter_read(&proctreelk);
*retval = p->p_p->ps_pgrp->pg_id;
+ rw_exit_read(&proctreelk);
return (0);
}
@@ -106,16 +110,23 @@ sys_getpgid(struct proc *curp, void *v,
syscallarg(pid_t) pid;
} */ *uap = v;
struct process *targpr = curp->p_p;
+ int error = 0;
- if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
- goto found;
+ if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid) {
+ rw_enter_read(&proctreelk);
+ *retval = targpr->ps_pgid;
+ rw_exit_read(&proctreelk);
+ return 0;
+ }
+ rw_enter_read(&proctreelk);
if ((targpr = prfind(SCARG(uap, pid))) == NULL)
- return (ESRCH);
- if (targpr->ps_session != curp->p_p->ps_session)
- return (EPERM);
-found:
- *retval = targpr->ps_pgid;
- return (0);
+ error = ESRCH;
+ else if (targpr->ps_session != curp->p_p->ps_session)
+ error = EPERM;
+ else
+ *retval = targpr->ps_pgid;
+ rw_exit_read(&proctreelk);
+ return error;
}
int
@@ -125,7 +136,9 @@ sys_getsid(struct proc *curp, void *v, r
syscallarg(pid_t) pid;
} */ *uap = v;
struct process *targpr = curp->p_p;
+ int error = 0;
+ rw_enter_read(&proctreelk);
if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
goto found;
if ((targpr = prfind(SCARG(uap, pid))) == NULL)
@@ -135,9 +148,12 @@ sys_getsid(struct proc *curp, void *v, r
found:
/* Skip exiting processes */
if (targpr->ps_pgrp->pg_session->s_leader == NULL)
- return (ESRCH);
- *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
- return (0);
+ error = ESRCH;
+ else
+ *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
+ rw_exit_read(&proctreelk);
+
+ return error;
}
int
@@ -224,12 +240,15 @@ sys_setsid(struct proc *p, void *v, regi
newsess = pool_get(&session_pool, PR_WAITOK);
newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
+ rw_enter_write(&proctreelk);
if (pr->ps_pgid == pid || pgfind(pid) != NULL) {
+ rw_exit_write(&proctreelk);
pool_put(&pgrp_pool, newpgrp);
pool_put(&session_pool, newsess);
return (EPERM);
} else {
enternewpgrp(pr, newpgrp, newsess);
+ rw_exit_write(&proctreelk);
*retval = pid;
return (0);
}
@@ -269,6 +288,7 @@ sys_setpgid(struct proc *curp, void *v,
newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
+ rw_enter_write(&proctreelk);
if (pid != 0 && pid != curpr->ps_pid) {
if ((targpr = prfind(pid)) == 0 || !inferior(targpr, curpr)) {
error = ESRCH;
@@ -307,7 +327,8 @@ sys_setpgid(struct proc *curp, void *v,
else
enterthispgrp(targpr, pgrp);
}
- out:
+out:
+ rw_exit_write(&proctreelk);
if (newpgrp != NULL)
pool_put(&pgrp_pool, newpgrp);
return (error);
Index: kern/kern_resource.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.58
diff -u -p -r1.58 kern_resource.c
--- kern/kern_resource.c 19 Feb 2018 08:59:52 -0000 1.58
+++ kern/kern_resource.c 26 Feb 2018 16:47:58 -0000
@@ -90,13 +90,17 @@ sys_getpriority(struct proc *curp, void
case PRIO_PGRP: {
struct pgrp *pg;
+ rw_enter_read(&proctreelk);
if (SCARG(uap, who) == 0)
pg = curp->p_p->ps_pgrp;
- else if ((pg = pgfind(SCARG(uap, who))) == NULL)
+ else if ((pg = pgfind(SCARG(uap, who))) == NULL) {
+ rw_exit_read(&proctreelk);
break;
+ }
LIST_FOREACH(pr, &pg->pg_members, ps_pglist)
if (pr->ps_nice < low)
low = pr->ps_nice;
+ rw_exit_read(&proctreelk);
break;
}
@@ -145,14 +149,18 @@ sys_setpriority(struct proc *curp, void
case PRIO_PGRP: {
struct pgrp *pg;
+ rw_enter_read(&proctreelk);
if (SCARG(uap, who) == 0)
pg = curp->p_p->ps_pgrp;
- else if ((pg = pgfind(SCARG(uap, who))) == NULL)
+ else if ((pg = pgfind(SCARG(uap, who))) == NULL) {
+ rw_exit_read(&proctreelk);
break;
+ }
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
error = donice(curp, pr, SCARG(uap, prio));
found++;
}
+ rw_exit_read(&proctreelk);
break;
}
Index: kern/kern_sig.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.216
diff -u -p -r1.216 kern_sig.c
--- kern/kern_sig.c 26 Feb 2018 13:33:25 -0000 1.216
+++ kern/kern_sig.c 26 Feb 2018 16:47:58 -0000
@@ -662,6 +662,7 @@ killpg1(struct proc *cp, int signum, int
prsignal(pr, signum);
}
} else {
+ rw_enter_read(&proctreelk);
if (pgid == 0)
/*
* zero pgid means send to my process group.
@@ -669,8 +670,10 @@ killpg1(struct proc *cp, int signum, int
pgrp = cp->p_p->ps_pgrp;
else {
pgrp = pgfind(pgid);
- if (pgrp == NULL)
+ if (pgrp == NULL) {
+ rw_exit_read(&proctreelk);
return (ESRCH);
+ }
}
LIST_FOREACH(pr, &pgrp->pg_members, ps_pglist) {
if (pr->ps_pid <= 1 || pr->ps_flags & PS_SYSTEM ||
@@ -680,6 +683,7 @@ killpg1(struct proc *cp, int signum, int
if (signum)
prsignal(pr, signum);
}
+ rw_exit_read(&proctreelk);
}
return (nfound ? 0 : ESRCH);
}
@@ -1329,6 +1333,7 @@ proc_stop_sweep(void *v)
{
struct process *pr;
+ rw_enter_read(&proctreelk);
LIST_FOREACH(pr, &allprocess, ps_list) {
if ((pr->ps_flags & PS_STOPPED) == 0)
continue;
@@ -1338,6 +1343,7 @@ proc_stop_sweep(void *v)
prsignal(pr->ps_pptr, SIGCHLD);
wakeup(pr->ps_pptr);
}
+ rw_exit_read(&proctreelk);
}
/*
Index: kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.332
diff -u -p -r1.332 kern_sysctl.c
--- kern/kern_sysctl.c 19 Feb 2018 08:59:52 -0000 1.332
+++ kern/kern_sysctl.c 26 Feb 2018 16:47:58 -0000
@@ -1507,6 +1507,7 @@ again:
break;
case KERN_PROC_TTY:
+ /* XXX proctreelk? */
if ((pr->ps_flags & PS_CONTROLT) == 0 ||
pr->ps_session->s_ttyp == NULL ||
pr->ps_session->s_ttyp->t_dev != (dev_t)arg)
@@ -1613,6 +1614,7 @@ fill_kproc(struct process *pr, struct ki
if (s->s_leader)
ki->p_sid = s->s_leader->ps_pid;
+ /* XXX proctreelk */
if ((pr->ps_flags & PS_CONTROLT) && (tp = s->s_ttyp)) {
ki->p_tdev = tp->t_dev;
ki->p_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : -1;
Index: kern/subr_prf.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_prf.c,v
retrieving revision 1.93
diff -u -p -r1.93 subr_prf.c
--- kern/subr_prf.c 5 Jan 2018 11:10:25 -0000 1.93
+++ kern/subr_prf.c 26 Feb 2018 16:47:58 -0000
@@ -362,6 +362,7 @@ uprintf(const char *fmt, ...)
struct process *pr = curproc->p_p;
va_list ap;
+ /* XXX proctreelk? */
if (pr->ps_flags & PS_CONTROLT && pr->ps_session->s_ttyvp) {
va_start(ap, fmt);
kprintf(fmt, TOTTY, pr->ps_session->s_ttyp, NULL, ap);
Index: kern/sys_process.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_process.c,v
retrieving revision 1.80
diff -u -p -r1.80 sys_process.c
--- kern/sys_process.c 19 Feb 2018 09:25:13 -0000 1.80
+++ kern/sys_process.c 26 Feb 2018 16:47:58 -0000
@@ -276,8 +276,13 @@ ptrace_ctrl(struct proc *p, int req, pid
struct proc *t; /* target thread */
struct process *tr; /* target process */
int error = 0;
+ int proctree_locked;
int s;
+ /* Lock proctree before looking up the process. */
+ rw_enter_write(&proctreelk);
+ proctree_locked = 1;
+
switch (req) {
case PT_TRACE_ME:
/* Just set the trace flag. */
@@ -288,6 +293,7 @@ ptrace_ctrl(struct proc *p, int req, pid
tr->ps_ptstat = malloc(sizeof(*tr->ps_ptstat),
M_SUBPROC, M_WAITOK);
memset(tr->ps_ptstat, 0, sizeof(*tr->ps_ptstat));
+ rw_exit_write(&proctreelk);
return 0;
/* calls that only operate on the PID */
@@ -487,6 +493,10 @@ ptrace_ctrl(struct proc *p, int req, pid
atomic_clearbits_int(&tr->ps_flags, PS_TRACED|PS_WAITED);
sendsig:
+ KASSERT(proctree_locked);
+ proctree_locked = 0;
+ rw_exit_write(&proctreelk);
+
memset(tr->ps_ptstat, 0, sizeof(*tr->ps_ptstat));
/* Finally, deliver the requested signal (or none). */
@@ -534,6 +544,8 @@ ptrace_ctrl(struct proc *p, int req, pid
}
fail:
+ if (proctree_locked)
+ rw_exit_write(&proctreelk);
return error;
}
Index: kern/syscalls.master
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.master,v
retrieving revision 1.180
diff -u -p -r1.180 syscalls.master
--- kern/syscalls.master 12 Dec 2017 01:12:34 -0000 1.180
+++ kern/syscalls.master 26 Feb 2018 16:47:58 -0000
@@ -107,7 +107,7 @@
36 STD { void sys_sync(void); }
37 OBSOL o58_kill
38 STD { int sys_stat(const char *path, struct stat *ub); }
-39 STD { pid_t sys_getppid(void); }
+39 STD NOLOCK { pid_t sys_getppid(void); }
40 STD { int sys_lstat(const char *path, struct stat *ub); }
41 STD { int sys_dup(int fd); }
42 STD { int sys_fstatat(int fd, const char *path, \
@@ -185,7 +185,7 @@
gid_t *gidset); }
80 STD { int sys_setgroups(int gidsetsize, \
const gid_t *gidset); }
-81 STD { int sys_getpgrp(void); }
+81 STD NOLOCK { int sys_getpgrp(void); }
82 STD { int sys_setpgid(pid_t pid, pid_t pgid); }
83 STD NOLOCK { int sys_futex(uint32_t *f, int op, int val, \
const struct timespec *timeout, uint32_t *g); }
Index: kern/tty.c
===================================================================
RCS file: /cvs/src/sys/kern/tty.c,v
retrieving revision 1.137
diff -u -p -r1.137 tty.c
--- kern/tty.c 19 Feb 2018 08:59:52 -0000 1.137
+++ kern/tty.c 26 Feb 2018 16:47:58 -0000
@@ -973,10 +973,13 @@ ttioctl(struct tty *tp, u_long cmd, cadd
break;
case TIOCSCTTY: /* become controlling tty */
/* Session ctty vnode pointer set in vnode layer. */
+ rw_enter_write(&proctreelk);
if (!SESS_LEADER(pr) ||
((pr->ps_session->s_ttyvp || tp->t_session) &&
- (tp->t_session != pr->ps_session)))
+ (tp->t_session != pr->ps_session))) {
+ rw_exit_write(&proctreelk);
return (EPERM);
+ }
if (tp->t_session)
SESSRELE(tp->t_session);
SESSHOLD(pr->ps_session);
@@ -984,10 +987,14 @@ ttioctl(struct tty *tp, u_long cmd, cadd
tp->t_pgrp = pr->ps_pgrp;
pr->ps_session->s_ttyp = tp;
atomic_setbits_int(&pr->ps_flags, PS_CONTROLT);
+ rw_exit_write(&proctreelk);
break;
case TIOCSPGRP: { /* set pgrp of tty */
- struct pgrp *pgrp = pgfind(*(int *)data);
+ struct pgrp *pgrp;
+ rw_enter_write(&proctreelk);
+ pgrp = pgfind(*(int *)data);
+ rw_exit_write(&proctreelk);
if (!isctty(pr, tp))
return (ENOTTY);
else if (pgrp == NULL)
@@ -2126,6 +2133,7 @@ process_sum(struct process *pr, fixpt_t
/*
* Report on state of foreground process group.
+ * XXX needs proctreelk?
*/
void
ttyinfo(struct tty *tp)