Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144899555
D27157.id79414.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D27157.id79414.diff
View Options
Index: sys/kern/kern_descrip.c
===================================================================
--- sys/kern/kern_descrip.c
+++ sys/kern/kern_descrip.c
@@ -1001,6 +1001,40 @@
return (error);
}
+static void
+sigiofree(struct sigio *sigio)
+{
+ crfree(sigio->sio_ucred);
+ free(sigio, M_SIGIO);
+}
+
+static struct sigio *
+funsetown_locked(struct sigio *sigio)
+{
+ struct proc *p;
+ struct pgrp *pg;
+
+ SIGIO_ASSERT_LOCKED();
+
+ if (sigio == NULL)
+ return (NULL);
+ *(sigio->sio_myref) = NULL;
+ if (sigio->sio_pgid < 0) {
+ pg = sigio->sio_pgrp;
+ PGRP_LOCK(pg);
+ SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
+ sigio, sio_pgsigio);
+ PGRP_UNLOCK(pg);
+ } else {
+ p = sigio->sio_proc;
+ PROC_LOCK(p);
+ SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
+ sigio, sio_pgsigio);
+ PROC_UNLOCK(p);
+ }
+ return (sigio);
+}
+
/*
* If sigio is on the list associated with a process or process group,
* disable signalling from the device, remove sigio from the list and
@@ -1011,92 +1045,82 @@
{
struct sigio *sigio;
+ /* Racy check, consumers must provide synchronization. */
if (*sigiop == NULL)
return;
+
SIGIO_LOCK();
- sigio = *sigiop;
- if (sigio == NULL) {
- SIGIO_UNLOCK();
- return;
- }
- *(sigio->sio_myref) = NULL;
- if ((sigio)->sio_pgid < 0) {
- struct pgrp *pg = (sigio)->sio_pgrp;
- PGRP_LOCK(pg);
- SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
- sigio, sio_pgsigio);
- PGRP_UNLOCK(pg);
- } else {
- struct proc *p = (sigio)->sio_proc;
- PROC_LOCK(p);
- SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
- sigio, sio_pgsigio);
- PROC_UNLOCK(p);
- }
+ sigio = funsetown_locked(*sigiop);
SIGIO_UNLOCK();
- crfree(sigio->sio_ucred);
- free(sigio, M_SIGIO);
+ if (sigio != NULL)
+ sigiofree(sigio);
}
/*
- * Free a list of sigio structures.
- * We only need to lock the SIGIO_LOCK because we have made ourselves
- * inaccessible to callers of fsetown and therefore do not need to lock
- * the proc or pgrp struct for the list manipulation.
+ * Free a list of sigio structures. The caller must ensure that new sigio
+ * structures cannot be added after this point. For process groups this is
+ * guaranteed using the proctree lock; for processes, the P_WEXIT flag serves
+ * as an interlock.
*/
void
funsetownlst(struct sigiolst *sigiolst)
{
struct proc *p;
struct pgrp *pg;
- struct sigio *sigio;
+ struct sigio *sigio, *tmp;
+ /* Racy check. */
sigio = SLIST_FIRST(sigiolst);
if (sigio == NULL)
return;
+
p = NULL;
pg = NULL;
+ SIGIO_LOCK();
+ sigio = SLIST_FIRST(sigiolst);
+ if (sigio == NULL) {
+ SIGIO_UNLOCK();
+ return;
+ }
+
/*
- * Every entry of the list should belong
- * to a single proc or pgrp.
+ * Every entry of the list should belong to a single proc or pgrp.
*/
if (sigio->sio_pgid < 0) {
pg = sigio->sio_pgrp;
- PGRP_LOCK_ASSERT(pg, MA_NOTOWNED);
+ sx_assert(&proctree_lock, SX_XLOCKED);
+ PGRP_LOCK(pg);
} else /* if (sigio->sio_pgid > 0) */ {
p = sigio->sio_proc;
- PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+ PROC_LOCK(p);
+ KASSERT((p->p_flag & P_WEXIT) != 0,
+ ("%s: process %p is not exiting", __func__, p));
}
- SIGIO_LOCK();
- while ((sigio = SLIST_FIRST(sigiolst)) != NULL) {
- *(sigio->sio_myref) = NULL;
+ SLIST_FOREACH(sigio, sigiolst, sio_pgsigio) {
+ *sigio->sio_myref = NULL;
if (pg != NULL) {
KASSERT(sigio->sio_pgid < 0,
("Proc sigio in pgrp sigio list"));
KASSERT(sigio->sio_pgrp == pg,
("Bogus pgrp in sigio list"));
- PGRP_LOCK(pg);
- SLIST_REMOVE(&pg->pg_sigiolst, sigio, sigio,
- sio_pgsigio);
- PGRP_UNLOCK(pg);
} else /* if (p != NULL) */ {
KASSERT(sigio->sio_pgid > 0,
("Pgrp sigio in proc sigio list"));
KASSERT(sigio->sio_proc == p,
("Bogus proc in sigio list"));
- PROC_LOCK(p);
- SLIST_REMOVE(&p->p_sigiolst, sigio, sigio,
- sio_pgsigio);
- PROC_UNLOCK(p);
}
- SIGIO_UNLOCK();
- crfree(sigio->sio_ucred);
- free(sigio, M_SIGIO);
- SIGIO_LOCK();
}
+
+ if (pg != NULL)
+ PGRP_UNLOCK(pg);
+ else
+ PROC_UNLOCK(p);
SIGIO_UNLOCK();
+
+ SLIST_FOREACH_SAFE(sigio, sigiolst, sio_pgsigio, tmp)
+ sigiofree(sigio);
}
/*
@@ -1110,7 +1134,7 @@
{
struct proc *proc;
struct pgrp *pgrp;
- struct sigio *sigio;
+ struct sigio *osigio, *sigio;
int ret;
if (pgid == 0) {
@@ -1120,13 +1144,14 @@
ret = 0;
- /* Allocate and fill in the new sigio out of locks. */
sigio = malloc(sizeof(struct sigio), M_SIGIO, M_WAITOK);
sigio->sio_pgid = pgid;
sigio->sio_ucred = crhold(curthread->td_ucred);
sigio->sio_myref = sigiop;
sx_slock(&proctree_lock);
+ SIGIO_LOCK();
+ osigio = funsetown_locked(*sigiop);
if (pgid > 0) {
proc = pfind(pgid);
if (proc == NULL) {
@@ -1142,20 +1167,21 @@
* restrict FSETOWN to the current process or process
* group for maximum safety.
*/
- PROC_UNLOCK(proc);
if (proc->p_session != curthread->td_proc->p_session) {
+ PROC_UNLOCK(proc);
ret = EPERM;
goto fail;
}
- pgrp = NULL;
+ sigio->sio_proc = proc;
+ SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio);
+ PROC_UNLOCK(proc);
} else /* if (pgid < 0) */ {
pgrp = pgfind(-pgid);
if (pgrp == NULL) {
ret = ESRCH;
goto fail;
}
- PGRP_UNLOCK(pgrp);
/*
* Policy - Don't allow a process to FSETOWN a process
@@ -1166,44 +1192,28 @@
* group for maximum safety.
*/
if (pgrp->pg_session != curthread->td_proc->p_session) {
+ PGRP_UNLOCK(pgrp);
ret = EPERM;
goto fail;
}
- proc = NULL;
- }
- funsetown(sigiop);
- if (pgid > 0) {
- PROC_LOCK(proc);
- /*
- * Since funsetownlst() is called without the proctree
- * locked, we need to check for P_WEXIT.
- * XXX: is ESRCH correct?
- */
- if ((proc->p_flag & P_WEXIT) != 0) {
- PROC_UNLOCK(proc);
- ret = ESRCH;
- goto fail;
- }
- SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio);
- sigio->sio_proc = proc;
- PROC_UNLOCK(proc);
- } else {
- PGRP_LOCK(pgrp);
SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio);
sigio->sio_pgrp = pgrp;
PGRP_UNLOCK(pgrp);
}
sx_sunlock(&proctree_lock);
- SIGIO_LOCK();
*sigiop = sigio;
SIGIO_UNLOCK();
+ if (osigio != NULL)
+ sigiofree(osigio);
return (0);
fail:
+ SIGIO_UNLOCK();
sx_sunlock(&proctree_lock);
- crfree(sigio->sio_ucred);
- free(sigio, M_SIGIO);
+ sigiofree(sigio);
+ if (osigio != NULL)
+ sigiofree(osigio);
return (ret);
}
Index: sys/kern/kern_exit.c
===================================================================
--- sys/kern/kern_exit.c
+++ sys/kern/kern_exit.c
@@ -358,7 +358,7 @@
/*
* Reset any sigio structures pointing to us as a result of
- * F_SETOWN with our pid.
+ * F_SETOWN with our pid. The P_WEXIT flag interlocks with fsetown().
*/
funsetownlst(&p->p_sigiolst);
Index: sys/kern/kern_proc.c
===================================================================
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -774,7 +774,8 @@
/*
* Reset any sigio structures pointing to us as a result of
- * F_SETOWN with our pgid.
+ * F_SETOWN with our pgid. The proctree lock ensures that
+ * new sigio structures will not be added after this point.
*/
funsetownlst(&pgrp->pg_sigiolst);
Index: sys/sys/signalvar.h
===================================================================
--- sys/sys/signalvar.h
+++ sys/sys/signalvar.h
@@ -337,7 +337,7 @@
#define SIGIO_TRYLOCK() mtx_trylock(&sigio_lock)
#define SIGIO_UNLOCK() mtx_unlock(&sigio_lock)
#define SIGIO_LOCKED() mtx_owned(&sigio_lock)
-#define SIGIO_ASSERT(type) mtx_assert(&sigio_lock, type)
+#define SIGIO_ASSERT_LOCKED(type) mtx_assert(&sigio_lock, MA_OWNED)
extern struct mtx sigio_lock;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 14, 9:57 PM (6 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28716620
Default Alt Text
D27157.id79414.diff (7 KB)
Attached To
Mode
D27157: Fix a pair of races in sigio handling
Attached
Detach File
Event Timeline
Log In to Comment