Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Sep 1998 16:53:37 -0700 (PDT)
From:      Don Lewis <Don.Lewis@tsc.tdk.com>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/7899: [PATCH] [SECURITY] SETOWN allows bypass of signal credential checks and has other bugs
Message-ID:  <199809112353.QAA17235@w3.gv.tsc.tdk.com>

next in thread | raw e-mail | index | archive | help

>Number:         7899
>Category:       kern
>Synopsis:       SETOWN allows bypass of signal credential checks and has other bugs
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Sep 11 17:00:01 PDT 1998
>Last-Modified:
>Originator:     Don Lewis
>Organization:
TDK Semiconductor
>Release:        FreeBSD 3.0-CURRENT-19980911 i386
>Environment:

	FreeBSD 2.1.x, 2.2.x, and 3.0-CURRENT

>Description:

[SECURITY] fcntl(fd, F_SETOWN, arg) and ioctl(fd, FIOSETOWN, arg) allow
signals to be sent to arbitrary processes and bypass the credential
checks used by kill().  This isn't as serious as it might be because
normal users can only send SIGIO and SIGURG by this method and the
normal disposition of these signals is to ignore them.  Being able to
send these signals to processes that catch them may cause those processes
to misbehave.  HOWEVER, bpf allows the user to select the signal to
be sent by using the BIOCSRSIG ioctl, but access to bpf is generally
restricted to root.  One could imagine a sneaky attacker opening bpf
as root and then changing uid to avoid suspicion, then using this
facility to nuke various processes on the system.  Since nobody is
calling kill(), you can't ktrace the processes on the system to figure
out where the signals are coming from.

[SECURITY,BUG] Once signalling of a process or process group has been
configured by F_SETOWN, signals will continue to be sent even after this
process or process group has disappeared, until signalling is explicitly
disabled or the fd is closed.  When the pids wrap around, an arbitrary
new process will start receiving these signals.  This could cause
mysterious problems to happen.

[BUG] If you specify a process to F_SETOWN (as opposed to a process group),
it will find the process group of this process and configure signals to
be sent to that process group.  FIOSETOWN and *IOCSPGRP work correctly,
though the sign of the argument is inverted.

[BUG] The log device has processes and process groups reversed when it
tries to figure out where to send signals.

[LIMITATION] In the case of tty devices, it is only possible to get
SIGIO signals from the controlling tty of a process.  This affects
xntpd which may desire to receive SIGIO signals from multiple serially
connected reference clocks, and may not desire to disconnect from its
controlling terminal if it is being debugged.

[ARCHITECTURE] The code to figure out where to send signals is duplicated
in multiple places.


>How-To-Repeat:


>Fix:
	
The attached patch seems to work correctly in 3.0-CURRENT.  I've been
using a similar patch in 2.1.x for quite a while.

There are several places, marked by "Policy" where various restrictions
could be tightened or loosened.

Several of the drivers implemented the TIOCSPGRP and TIOCGPGRP ioctls
in order to support F_SETOWN prior to this patch.  This patch now uses
the FIOSETOWN and FIOGETOWN ioctls, and the TIOC* ioctl implementations
should probably be removed from all but tty.c as a cleanup measure.  I
did not do this in case a userland program happened to be using these
ioctls.

The proc structure got bigger, so various bits of userland that look
at it need to be recompiled.

Having to pass the funset parameter to fsetown is ugly.  Is there a better
way of doing the necessary splXXX()/splx() wrapper that avoids the need
for private callback functions?

This patch needs to be tested with SMP.


--- kern/kern_descrip.c.orig	Fri Sep  4 18:13:51 1998
+++ kern/kern_descrip.c	Fri Sep 11 05:21:34 1998
@@ -46,7 +46,6 @@
 #include <sys/systm.h>
 #include <sys/sysproto.h>
 #include <sys/conf.h>
-#include <sys/filedesc.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
@@ -58,6 +57,7 @@
 #include <sys/ttycom.h>
 #include <sys/fcntl.h>
 #include <sys/malloc.h>
+#include <sys/filedesc.h>
 #include <sys/unistd.h>
 #include <sys/resourcevar.h>
 #include <sys/pipe.h>
@@ -71,6 +71,7 @@
 
 static MALLOC_DEFINE(M_FILEDESC, "file desc", "Open file descriptor table");
 MALLOC_DEFINE(M_FILE, "file", "Open file structure");
+static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures");
 
 
 static	 d_open_t  fdopen;
@@ -257,30 +258,13 @@
 		return (error);
 
 	case F_GETOWN:
-		if (fp->f_type == DTYPE_SOCKET) {
-			p->p_retval[0] = ((struct socket *)fp->f_data)->so_pgid;
-			return (0);
-		}
 		error = (*fp->f_ops->fo_ioctl)
-			(fp, TIOCGPGRP, (caddr_t)p->p_retval, p);
-		p->p_retval[0] = - p->p_retval[0];
+			(fp, FIOGETOWN, (caddr_t)p->p_retval, p);
 		return (error);
 
 	case F_SETOWN:
-		if (fp->f_type == DTYPE_SOCKET) {
-			((struct socket *)fp->f_data)->so_pgid = uap->arg;
-			return (0);
-		}
-		if (uap->arg <= 0) {
-			uap->arg = -uap->arg;
-		} else {
-			struct proc *p1 = pfind(uap->arg);
-			if (p1 == 0)
-				return (ESRCH);
-			uap->arg = p1->p_pgrp->pg_id;
-		}
 		return ((*fp->f_ops->fo_ioctl)
-			(fp, TIOCSPGRP, (caddr_t)&uap->arg, p));
+			(fp, FIOSETOWN, (caddr_t)&uap->arg, p));
 
 	case F_SETLKW:
 		flg |= F_WAIT;
@@ -363,6 +347,129 @@
 		fdp->fd_lastfile = new;
 	*retval = new;
 	return (0);
+}
+
+/*
+ * If sigio is on the list associated with a process or process group,
+ * remove it.
+ */
+void
+funsetown(sigio)
+	register struct sigio *sigio;
+{
+	if (sigio == NULL)
+		return;
+
+	if (sigio->sio_pgid < 0) {
+		SLIST_REMOVE(&(sigio->sio_pgrp->pg_sigiolst), sigio,
+			     sigio, sio_pgsigio);
+	} else /* if ((*sigiop)->sio_pgid > 0) */ {
+		SLIST_REMOVE(&(sigio->sio_proc->p_sigiolst), sigio,
+			     sigio, sio_pgsigio);
+	}
+
+	crfree(sigio->sio_ucred);
+
+	*(sigio->sio_myref) = NULL;
+
+	FREE(sigio, M_SIGIO);
+}
+
+void
+funsetownlst(sigiolst)
+	register struct sigiolst *sigiolst;
+{
+	register struct sigio *sigio;
+
+	while ((sigio = sigiolst->slh_first) != NULL)
+		(*sigio->sio_unsetown)(sigio);
+}
+
+/*
+ * Common code for FIOSETOWN ioctl called by F_SETOWN
+ *
+ * After permission checking, add sigio structure to the sigio list for
+ * the process or process group.
+ */
+int
+fsetown(pgid, sigiop, funset)
+	register pid_t pgid;
+	register struct sigio **sigiop;
+	void (*funset) __P((struct sigio *));
+{
+	register struct proc *proc = NULL;
+	register struct pgrp *pgrp = NULL;
+	register struct sigio *sigio;
+
+	if (pgid == 0) {
+		funsetown(*sigiop);
+		return (0);
+	} else if (pgid > 0) {
+		proc = pfind(pgid);
+		if (proc == NULL)
+			return (ESRCH);
+		/*
+		 * Policy - Don't allow a process to FSETOWN a process
+		 * in another session.
+		 *
+		 * Remove this test to allow maximum flexibility or
+		 * restrict FSETOWN to the current process or process
+		 * group for maximum safety.
+		 */
+		else if (proc->p_session != curproc->p_session)
+			return (EPERM);
+	} else /* if (pgid < 0) */ {
+		pgrp = pgfind(-pgid);
+		if (pgrp == NULL)
+			return (ESRCH);
+		/*
+		 * Policy - Don't allow a process to FSETOWN a process
+		 * in another session.
+		 *
+		 * Remove this test to allow maximum flexibility or
+		 * restrict FSETOWN to the current process or process
+		 * group for maximum safety.
+		 */
+		else if (pgrp->pg_session != curproc->p_session)
+			return (EPERM);
+	}
+
+	funsetown(*sigiop);
+
+	MALLOC(sigio, struct sigio *, sizeof(struct sigio), M_SIGIO,
+	       M_WAITOK);
+
+	if (pgid > 0) {
+		SLIST_INSERT_HEAD(&(proc->p_sigiolst), sigio, sio_pgsigio);
+		sigio->sio_proc = proc;
+	} else {
+		SLIST_INSERT_HEAD(&(pgrp->pg_sigiolst), sigio, sio_pgsigio);
+		sigio->sio_pgrp = pgrp;
+	}
+
+	sigio->sio_pgid = pgid;
+
+	crhold(curproc->p_ucred);
+	sigio->sio_ucred = curproc->p_ucred;
+	sigio->sio_ruid = curproc->p_cred->p_ruid; /* wish this was in ucred */
+
+	sigio->sio_unsetown = funset;
+
+	sigio->sio_myref = sigiop;
+	*sigiop = sigio;
+
+	return (0);
+}
+
+/*
+ * Common code for FIOGETOWN ioctl called by F_GETOWN
+ */
+pid_t
+fgetown(sigio)
+	register struct sigio *sigio;
+{
+	/* we could also return sigio->sio_{proc->p_pid,pgrp->pg_id} */
+	return (sigio != NULL ? sigio->sio_pgid : 0);
 }
 
 /*
--- kern/kern_exit.c.orig	Fri Sep  4 18:13:52 1998
+++ kern/kern_exit.c	Fri Sep 11 03:40:57 1998
@@ -186,6 +186,12 @@
 		untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
 
 	/*
+	 * Reset any sigio structures pointing to us as a result of
+	 * F_SETOWN with our pid
+	 */
+	funsetownlst(&(p->p_sigiolst));
+
+	/*
 	 * Close open files and release open-file table.
 	 * This may block!
 	 */
--- kern/kern_proc.c.orig	Fri Sep  4 18:13:56 1998
+++ kern/kern_proc.c	Fri Sep 11 05:12:51 1998
@@ -48,6 +48,7 @@
 #include <vm/vm_map.h>
 #include <sys/user.h>
 #include <vm/vm_zone.h>
+#include <sys/filedesc.h>
 
 static MALLOC_DEFINE(M_PGRP, "pgrp", "process group header");
 MALLOC_DEFINE(M_SESSION, "session", "session header");
@@ -242,6 +243,7 @@
 		LIST_INIT(&pgrp->pg_members);
 		LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
 		pgrp->pg_jobc = 0;
+		SLIST_INIT(&(pgrp->pg_sigiolst));
 	} else if (pgrp == p->p_pgrp)
 		return (0);
 
@@ -283,6 +285,12 @@
 pgdelete(pgrp)
 	register struct pgrp *pgrp;
 {
+
+	/*
+	 * Reset any sigio structures pointing to us as a result of
+	 * F_SETOWN with our pgid
+	 */
+	funsetownlst(&(pgrp->pg_sigiolst));
 
 	if (pgrp->pg_session->s_ttyp != NULL &&
 	    pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
--- kern/kern_sig.c.orig	Fri Sep  4 18:13:56 1998
+++ kern/kern_sig.c	Fri Sep 11 05:26:34 1998
@@ -96,6 +96,16 @@
 	    (pc)->pc_ucred->cr_uid == (q)->p_ucred->cr_uid || \
 	    ((signum) == SIGCONT && (q)->p_session == (p)->p_session))
 
+/*
+ * Policy -- Can real uid ruid with ucred uc send a signal to process q?
+ */
+#define CANSIGIO(ruid, uc, q) \
+	((uc)->cr_uid == 0 || \
+	    ruid == (q)->p_cred->p_ruid || \
+	    (uc)->cr_uid == (q)->p_cred->p_ruid || \
+	    ruid == (q)->p_ucred->cr_uid || \
+	    (uc)->cr_uid == (q)->p_ucred->cr_uid)
+
 static int sugid_coredump;
 SYSCTL_INT(_kern, OID_AUTO, sugid_coredump, CTLFLAG_RW, &sugid_coredump, 0, "");
 
@@ -1419,4 +1429,31 @@
 
 	psignal(p, SIGSYS);
 	return (EINVAL);
+}
+
+/*
+ * Send a signal to a SIGIO or SIGURG to a process or process group using
+ * stored credentials rather than those of the current process
+ */
+void
+pgsigio(sigio, signum, checkctty)
+	register struct sigio *sigio;
+	int signum, checkctty;
+{
+	if (sigio == NULL)
+		return;
+		
+	if (sigio->sio_pgid > 0) {
+		if (CANSIGIO(sigio->sio_ruid, sigio->sio_ucred,
+		             sigio->sio_proc))
+			psignal(sigio->sio_proc, signum);
+	} else if (sigio->sio_pgid < 0) {
+		register struct proc *p;
+
+		for (p = sigio->sio_pgrp->pg_members.lh_first; p != NULL;
+		     p = p->p_pglist.le_next)
+			if (CANSIGIO(sigio->sio_ruid, sigio->sio_ucred, p) &&
+			    (checkctty == 0 || (p->p_flag & P_CONTROLT)))
+				psignal(p, signum);
+	}
 }
--- kern/subr_log.c.orig	Fri Sep  4 18:14:00 1998
+++ kern/subr_log.c	Fri Sep 11 04:54:01 1998
@@ -51,6 +51,7 @@
 #include <sys/signalvar.h>
 #include <sys/kernel.h>
 #include <sys/poll.h>
+#include <sys/filedesc.h>
 #ifdef DEVFS
 #include <sys/devfsext.h>
 #endif /*DEVFS*/
@@ -75,7 +76,8 @@
 static struct logsoftc {
 	int	sc_state;		/* see above for possibilities */
 	struct	selinfo sc_selp;	/* process waiting on select call */
-	int	sc_pgid;		/* process/group for async I/O */
+	struct  sigio *sc_sigio;	/* credentials and proc * or pgrp *
+					 * for SIGIO/SIGURG */
 } logsoftc;
 
 int	log_open;			/* also used in log() */
@@ -90,7 +92,8 @@
 	if (log_open)
 		return (EBUSY);
 	log_open = 1;
-	logsoftc.sc_pgid = p->p_pid;		/* signal process only */
+	/* signal process only */
+	fsetown(p->p_pid, &logsoftc.sc_sigio, funsetown);
 	return (0);
 }
 
@@ -104,6 +107,7 @@
 
 	log_open = 0;
 	logsoftc.sc_state = 0;
+	funsetown(logsoftc.sc_sigio);
 	return (0);
 }
 
@@ -183,12 +187,8 @@
 	if (!log_open)
 		return;
 	selwakeup(&logsoftc.sc_selp);
-	if (logsoftc.sc_state & LOG_ASYNC) {
-		if (logsoftc.sc_pgid < 0)
-			gsignal(-logsoftc.sc_pgid, SIGIO);
-		else if ((p = pfind(logsoftc.sc_pgid)))
-			psignal(p, SIGIO);
-	}
+	if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL)
+		pgsigio(logsoftc.sc_sigio, SIGIO, 0);
 	if (logsoftc.sc_state & LOG_RDWAIT) {
 		wakeup((caddr_t)msgbufp);
 		logsoftc.sc_state &= ~LOG_RDWAIT;
@@ -205,7 +205,7 @@
 	struct proc *p;
 {
 	long l;
-	int s;
+	int s, error;
 
 	switch (com) {
 
@@ -229,12 +229,27 @@
 			logsoftc.sc_state &= ~LOG_ASYNC;
 		break;
 
+	case FIOSETOWN:
+		error = fsetown(*(int *)data, &(logsoftc.sc_sigio), funsetown);
+		if (error)
+			return (error);
+		break;
+
+	case FIOGETOWN:
+		*(int *)data = fgetown(logsoftc.sc_sigio);
+		break;
+
+	/* Deprecated */
 	case TIOCSPGRP:
-		logsoftc.sc_pgid = *(int *)data;
+		error = fsetown(-(*(int *)data), &(logsoftc.sc_sigio),
+				funsetown);
+		if (error)
+			return (error);
 		break;
 
+	/* Deprecated */
 	case TIOCGPGRP:
-		*(int *)data = logsoftc.sc_pgid;
+		*(int *)data = -fgetown(logsoftc.sc_sigio);
 		break;
 
 	default:
--- kern/sys_generic.c.orig	Sat Sep  5 19:23:02 1998
+++ kern/sys_generic.c	Fri Sep 11 03:40:57 1998
@@ -470,36 +470,8 @@
 		break;
 
 	case FIOSETOWN:
-		tmp = *(int *)data;
-		if (fp->f_type == DTYPE_SOCKET) {
-			((struct socket *)fp->f_data)->so_pgid = tmp;
-			error = 0;
-			break;
-		}
-		if (tmp <= 0) {
-			tmp = -tmp;
-		} else {
-			struct proc *p1 = pfind(tmp);
-			if (p1 == 0) {
-				error = ESRCH;
-				break;
-			}
-			tmp = p1->p_pgrp->pg_id;
-		}
-		error = (*fp->f_ops->fo_ioctl)
-			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
-		break;
-
 	case FIOGETOWN:
-		if (fp->f_type == DTYPE_SOCKET) {
-			error = 0;
-			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
-			break;
-		}
-		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
-		*(int *)data = -*(int *)data;
-		break;
-
+		/* fall through */
 	default:
 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
 		/*
--- kern/sys_socket.c.orig	Fri Sep  4 18:14:02 1998
+++ kern/sys_socket.c	Fri Sep 11 05:38:39 1998
@@ -44,6 +44,7 @@
 #include <sys/sockio.h>
 #include <sys/stat.h>
 #include <sys/uio.h>
+#include <sys/filedesc.h>
 
 #include <net/if.h>
 #include <net/route.h>
@@ -80,6 +81,19 @@
 						    uio->uio_procp);
 }
 
+/*
+ * Callback to undo FIOSETOWN on process or process group death
+ */
+void
+soo_unsetown(sigio)
+	struct sigio *sigio;
+{
+	register int s = splnet();
+
+	funsetown(sigio);
+	splx(s);
+}
+
 int
 soo_ioctl(fp, cmd, data, p)
 	struct file *fp;
@@ -88,6 +102,7 @@
 	struct proc *p;
 {
 	register struct socket *so = (struct socket *)fp->f_data;
+	register int s, error;
 
 	switch (cmd) {
 
@@ -114,12 +129,28 @@
 		*(int *)data = so->so_rcv.sb_cc;
 		return (0);
 
-	case SIOCSPGRP:
-		so->so_pgid = *(int *)data;
+	case FIOSETOWN:
+		s = splnet();
+		error = fsetown(*(int *)data, &(so->so_sigio), soo_unsetown);
+		splx(s);
+		return(error);
+
+	case FIOGETOWN:
+		s = splnet();
+		*(int *)data = fgetown(so->so_sigio);
+		splx(s);
 		return (0);
 
+	case SIOCSPGRP:
+		s = splnet();
+		error = fsetown(-(*(int *)data), &(so->so_sigio), soo_unsetown);
+		splx(s);
+		return(error);
+
 	case SIOCGPGRP:
-		*(int *)data = so->so_pgid;
+		s = splnet();
+		*(int *)data = -fgetown(so->so_sigio);
+		splx(s);
 		return (0);
 
 	case SIOCATMARK:
--- kern/tty.c.orig	Fri Sep  4 18:14:04 1998
+++ kern/tty.c	Fri Sep 11 05:42:54 1998
@@ -90,6 +90,7 @@
 #include <sys/signalvar.h>
 #include <sys/resourcevar.h>
 #include <sys/malloc.h>
+#include <sys/filedesc.h>		/* get fsetown, funsetown, fgetown */
 #if NSNP > 0
 #include <sys/snoop.h>
 #endif
@@ -111,6 +112,7 @@
 static void	ttyrubo __P((struct tty *tp, int cnt));
 static void	ttyunblock __P((struct tty *tp));
 static int	ttywflush __P((struct tty *tp));
+static void	tty_unsetown __P((struct sigio *sigio));
 
 /*
  * Table with character classes and parity. The 8th bit indicates parity,
@@ -234,6 +236,8 @@
 	if (constty == tp)
 		constty = NULL;
 
+	funsetown(tp->t_sigio);
+
 	ttyflush(tp, FREAD | FWRITE);
 	clist_free_cblocks(&tp->t_canq);
 	clist_free_cblocks(&tp->t_outq);
@@ -685,6 +689,19 @@
 }
 
 /*
+ * Callback to undo FIOSETOWN on process or process group death
+ */
+static void
+tty_unsetown(sigio)
+	struct sigio *sigio;
+{
+	register int s = spltty();
+
+	funsetown(sigio);
+	splx(s);
+}
+
+/*
  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
  * has been called to do discipline-specific functions and/or reject any
  * of these ioctl commands.
@@ -756,6 +773,27 @@
 		*(int *)data = ttnread(tp);
 		splx(s);
 		break;
+
+	case FIOSETOWN:
+		/*
+		 * Policy -- Don't allow FIOSETOWN on someone else's 
+		 *           controlling tty
+		 */
+		if (tp->t_session != NULL && !isctty(p, tp))
+			return (ENOTTY);
+
+		s = spltty();
+		error = fsetown(*(int *)data, &(tp->t_sigio), tty_unsetown);
+		splx(s);
+		if (error)
+			return (error);
+		break;
+	case FIOGETOWN:
+		if (tp->t_session != NULL && !isctty(p, tp))
+			return (ENOTTY);
+		*(int *)data = fgetown(tp->t_sigio);
+		break;
+
 	case TIOCEXCL:			/* set exclusive use of tty */
 		s = spltty();
 		SET(tp->t_state, TS_XCLUDE);
@@ -2082,8 +2120,8 @@
 
 	if (tp->t_rsel.si_pid != 0)
 		selwakeup(&tp->t_rsel);
-	if (ISSET(tp->t_state, TS_ASYNC))
-		pgsignal(tp->t_pgrp, SIGIO, 1);
+	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
+		pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
 	wakeup(TSA_HUP_OR_INPUT(tp));
 }
 
--- kern/uipc_socket.c.orig	Fri Sep  4 18:14:06 1998
+++ kern/uipc_socket.c	Fri Sep 11 03:40:58 1998
@@ -218,6 +218,8 @@
 	int s = splnet();		/* conservative */
 	int error = 0;
 
+	funsetown(so->so_sigio);
+
 	if (so->so_options & SO_ACCEPTCONN) {
 		struct socket *sp, *sonext;
 
@@ -1182,10 +1184,8 @@
 {
 	struct proc *p;
 
-	if (so->so_pgid < 0)
-		gsignal(-so->so_pgid, SIGURG);
-	else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
-		psignal(p, SIGURG);
+	if (so->so_sigio != NULL)
+		pgsigio(so->so_sigio, SIGURG, 0);
 	selwakeup(&so->so_rcv.sb_sel);
 }
 
--- kern/uipc_socket2.c.orig	Sat Sep  5 19:23:02 1998
+++ kern/uipc_socket2.c	Fri Sep 11 05:43:16 1998
@@ -213,7 +213,7 @@
 	so->so_state = head->so_state | SS_NOFDREF;
 	so->so_proto = head->so_proto;
 	so->so_timeo = head->so_timeo;
-	so->so_pgid = head->so_pgid;
+	fsetown(fgetown(head->so_sigio), &(so->so_sigio), soo_unsetown);
 	so->so_uid = head->so_uid;
 	(void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat);
 
@@ -321,11 +321,8 @@
 		sb->sb_flags &= ~SB_WAIT;
 		wakeup((caddr_t)&sb->sb_cc);
 	}
-	if (so->so_state & SS_ASYNC) {
-		if (so->so_pgid < 0)
-			gsignal(-so->so_pgid, SIGIO);
-		else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
-			psignal(p, SIGIO);
+	if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) {
+		pgsigio(so->so_sigio, SIGIO, 0);
 	}
 	if (sb->sb_flags & SB_UPCALL)
 		(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
@@ -916,7 +913,7 @@
 	xso->so_qlimit = so->so_qlimit;
 	xso->so_timeo = so->so_timeo;
 	xso->so_error = so->so_error;
-	xso->so_pgid = so->so_pgid;
+	xso->so_pgid = so->so_sigio ? so->so_sigio->sio_pgid : 0;
 	xso->so_oobmark = so->so_oobmark;
 	sbtoxsockbuf(&so->so_snd, &xso->so_snd);
 	sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
--- kern/sys_pipe.c.orig	Fri Sep  4 18:14:02 1998
+++ kern/sys_pipe.c	Fri Sep 11 05:30:45 1998
@@ -256,7 +256,7 @@
 	cpipe->pipe_atime = cpipe->pipe_ctime;
 	cpipe->pipe_mtime = cpipe->pipe_ctime;
 	bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel);
-	cpipe->pipe_pgid = NO_PID;
+	cpipe->pipe_sigio = NULL;
 
 #ifndef PIPE_NODIRECT
 	/*
@@ -315,11 +315,8 @@
 		cpipe->pipe_state &= ~PIPE_SEL;
 		selwakeup(&cpipe->pipe_sel);
 	}
-	if (cpipe->pipe_state & PIPE_ASYNC) {
-		if (cpipe->pipe_pgid < 0)
-			gsignal(-cpipe->pipe_pgid, SIGIO);
-		else if ((p = pfind(cpipe->pipe_pgid)) != NULL)
-			psignal(p, SIGIO);
+	if ((cpipe->pipe_state & PIPE_ASYNC) && cpipe->pipe_sigio) {
+		pgsigio(cpipe->pipe_sigio, SIGIO, 0);
 	}
 }
 
@@ -953,12 +950,22 @@
 			*(int *)data = mpipe->pipe_buffer.cnt;
 		return (0);
 
-	case TIOCSPGRP:
-		mpipe->pipe_pgid = *(int *)data;
+	case FIOSETOWN:
+		return (fsetown(*(int *)data, &(mpipe->pipe_sigio),
+		                funsetown));
+
+	case FIOGETOWN:
+		*(int *)data = fgetown(mpipe->pipe_sigio);
 		return (0);
 
+	/* Deprecated */
+	case TIOCSPGRP:
+		return (fsetown(-(*(int *)data), &(mpipe->pipe_sigio),
+		                funsetown));
+
+	/* Deprecated */
 	case TIOCGPGRP:
-		*(int *)data = mpipe->pipe_pgid;
+		*(int *)data = -fgetown(mpipe->pipe_sigio);
 		return (0);
 
 	}
@@ -1038,6 +1045,7 @@
 {
 	struct pipe *cpipe = (struct pipe *)fp->f_data;
 
+	funsetown(cpipe->pipe_sigio);
 	pipeclose(cpipe);
 	fp->f_data = NULL;
 	return 0;
--- net/bpf.c.orig	Fri Sep  4 18:14:51 1998
+++ net/bpf.c	Fri Sep 11 05:48:18 1998
@@ -61,6 +61,7 @@
 #include <sys/filio.h>
 #include <sys/sockio.h>
 #include <sys/ttycom.h>
+#include <sys/filedesc.h>	/* get fsetown, funsetown, fgetown */
 
 #if defined(sparc) && BSD < 199103
 #include <sys/stream.h>
@@ -132,6 +133,7 @@
 		    u_int, void (*)(const void *, void *, u_int)));
 static void	reset_d __P((struct bpf_d *));
 static int	 bpf_setf __P((struct bpf_d *, struct bpf_program *));
+static void	bpfunsetown __P((struct sigio *sigio));
 
 static	d_open_t	bpfopen;
 static	d_close_t	bpfclose;
@@ -380,6 +382,7 @@
 	register int s;
 
 	s = splimp();
+	funsetown(d->bd_sigio);
 	if (d->bd_bif)
 		bpf_detachd(d);
 	splx(s);
@@ -537,11 +540,8 @@
 	struct proc *p;
 
 	wakeup((caddr_t)d);
-	if (d->bd_async && d->bd_sig)
-		if (d->bd_pgid > 0)
-			gsignal (d->bd_pgid, d->bd_sig);
-		else if (p = pfind (-d->bd_pgid))
-			psignal (p, d->bd_sig);
+	if (d->bd_async && d->bd_sig && d->bd_sigio)
+		pgsigio(d->bd_sigio, d->bd_sig, 0);
 
 #if BSD >= 199103
 	selwakeup(&d->bd_sel);
@@ -617,6 +617,19 @@
 }
 
 /*
+ * Callback to undo FIOSETOWN on process or process group death
+ */
+static void
+bpfunsetown(sigio)
+	struct sigio *sigio;
+{
+	register int s = splimp();
+
+	funsetown(sigio);
+	splx(s);
+}
+
+/*
  *  FIONREAD		Check for read packet available.
  *  SIOCGIFADDR		Get interface address - convenient hook to driver.
  *  BIOCGBLEN		Get buffer len [for read()].
@@ -838,18 +851,30 @@
 		d->bd_async = *(int *)addr;
 		break;
 
-/* N.B.  ioctl (FIOSETOWN) and fcntl (F_SETOWN) both end up doing the
-   equivalent of a TIOCSPGRP and hence end up here.  *However* TIOCSPGRP's arg
-   is a process group if it's positive and a process id if it's negative.  This
-   is exactly the opposite of what the other two functions want!  Therefore
-   there is code in ioctl and fcntl to negate the arg before calling here. */
+	case FIOSETOWN:
+		s = splimp();
+		error = fsetown(*(int *)addr, &(d->bd_sigio), bpfunsetown);
+		splx(s);
+		break;
 
-	case TIOCSPGRP:		/* Process or group to send signals to */
-		d->bd_pgid = *(int *)addr;
+	case FIOGETOWN:
+		s = splimp();
+		*(int *)addr = fgetown(d->bd_sigio);
+		splx(s);
 		break;
 
+	/* Deprecated */
+	case TIOCSPGRP:
+		s = splimp();
+		error = fsetown(-(*(int *)addr), &(d->bd_sigio), bpfunsetown);
+		splx(s);
+		break;
+
+	/* Deprecated */
 	case TIOCGPGRP:
-		*(int *)addr = d->bd_pgid;
+		s = splimp();
+		*(int *)addr = -fgetown(d->bd_sigio);
+		splx(s);
 		break;
 
 	case BIOCSRSIG:		/* Set receive signal */
--- net/bpfdesc.h.orig	Sat Feb 22 01:40:57 1997
+++ net/bpfdesc.h	Fri Sep 11 03:40:58 1998
@@ -78,7 +78,8 @@
 	u_char		bd_immediate;	/* true to return on packet arrival */
 	int		bd_async;	/* non-zero if packet reception should generate signal */
 	int		bd_sig;		/* signal to send upon packet reception */
-	pid_t		bd_pgid;	/* process or group id for signal */
+	struct sigio *	bd_sigio;	/* credentials and proc * or pgrp *
+					 * for SIGIO/SIGURG */
 #if BSD < 199103
 	u_char		bd_selcoll;	/* true if selects collide */
 	int		bd_timedout;
--- net/if_tun.c.orig	Fri Sep  4 18:15:00 1998
+++ net/if_tun.c	Fri Sep 11 04:53:33 1998
@@ -30,6 +30,7 @@
 #include <sys/ttycom.h>
 #include <sys/poll.h>
 #include <sys/signalvar.h>
+#include <sys/filedesc.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
 #ifdef DEVFS
@@ -215,7 +216,7 @@
 		}
 		splx(s);
 	}
-	tp->tun_pgrp = 0;
+	funsetown(tp->tun_sigio);
 	selwakeup(&tp->tun_rsel);
 
 	TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
@@ -372,11 +373,8 @@
 		tp->tun_flags &= ~TUN_RWAIT;
 		wakeup((caddr_t)tp);
 	}
-	if (tp->tun_flags & TUN_ASYNC && tp->tun_pgrp) {
-		if (tp->tun_pgrp > 0)
-			gsignal(tp->tun_pgrp, SIGIO);
-		else if ((p = pfind(-tp->tun_pgrp)) != 0) 
-			psignal(p, SIGIO);
+	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) {
+		pgsigio(tp->tun_sigio, SIGIO, 0);
 	}
 	selwakeup(&tp->tun_rsel);
 	return 0;
@@ -434,12 +432,22 @@
 			*(int *)data = 0;
 		splx(s);
 		break;
+	case FIOSETOWN:
+		return (fsetown(*(int *)data, &(tp->tun_sigio), funsetown));
+
+	case FIOGETOWN:
+		*(int *)data = fgetown(tp->tun_sigio);
+		return (0);
+
+	/* Deprecated */
 	case TIOCSPGRP:
-		tp->tun_pgrp = *(int *)data;
-		break;
+		return (fsetown(-(*(int *)data), &(tp->tun_sigio), funsetown));
+
+	/* Deprecated */
 	case TIOCGPGRP:
-		*(int *)data = tp->tun_pgrp;
-		break;
+		*(int *)data = -fgetown(tp->tun_sigio);
+		return (0);
+
 	default:
 		return (ENOTTY);
 	}
--- net/if_tunvar.h.orig	Fri Sep 11 04:13:34 1998
+++ net/if_tunvar.h	Fri Sep 11 04:13:23 1998
@@ -42,7 +42,8 @@
 #define TUN_READY       (TUN_OPEN | TUN_INITED)
 
 	struct	ifnet tun_if;		/* the interface */
-	int	tun_pgrp;		/* the process group - if any */
+	struct  sigio *tun_sigio;	/* credentials and proc * or pgrp *
+					 * for SIGIO/SIGURG */
 	struct	selinfo	tun_rsel;	/* read select */
 	struct	selinfo	tun_wsel;	/* write select (not used) */
 };
--- net/if_sl.c.orig	Fri Sep  4 18:14:57 1998
+++ net/if_sl.c	Fri Sep 11 15:41:59 1998
@@ -1016,7 +1016,7 @@
 
 	if (sc->sc_keepalive) {
 		if (sc->sc_flags & SC_KEEPALIVE)
-			pgsignal (sc->sc_ttyp->t_pgrp, SIGURG, 1);
+			pgsigio (sc->sc_ttyp->t_sigio, SIGURG, 1);
 		else
 			sc->sc_flags |= SC_KEEPALIVE;
 		sc->sc_kahandle = timeout(sl_keepalive, sc, sc->sc_keepalive);
--- sys/filedesc.h.orig	Fri Sep  4 18:17:03 1998
+++ sys/filedesc.h	Fri Sep 11 05:16:47 1998
@@ -37,6 +37,8 @@
 #ifndef _SYS_FILEDESC_H_
 #define _SYS_FILEDESC_H_
 
+#include <sys/queue.h>			/* For SLIST_HEAD, SLIST_ENTRY */
+
 /*
  * This structure is used for the management of descriptors.  It may be
  * shared by multiple processes.
@@ -91,10 +93,41 @@
  */
 #define OFILESIZE (sizeof(struct file *) + sizeof(char))
 
+/*
+ * Structure that holds
+ *	The pgid used as an argument to F_SETOWN
+ *	The credentials of the caller
+ *	A pointer to the process or process group referenced by the pgid
+ * This structure is placed on an SLIST belonging to the proc or pgrp
+ * so that the entire list may be revoked when the process exits or the
+ * process group disappears.
+ */
+struct	sigio {
+	union {
+		struct	proc *siu_proc; /* Process to receive SIGIO/SIGURG */
+		struct	pgrp *siu_pgrp; /* Process group to receive ... */
+	} sio_u;
+	void	(*sio_unsetown) __P((struct sigio *));
+	SLIST_ENTRY(sigio) sio_pgsigio;	/* sigio's for process or group */
+	struct	sigio **sio_myref;	/* location of the pointer that holds
+					 * the reference */
+	struct	ucred *sio_ucred;	/* Current credentials */
+	uid_t	sio_ruid;		/* Real user id */
+	pid_t	sio_pgid;		/* pgid for signals */
+};
+#define	sio_proc	sio_u.siu_proc
+#define	sio_pgrp	sio_u.siu_pgrp
+
+SLIST_HEAD(sigiolst, sigio);
+
 #ifdef KERNEL
 /*
  * Kernel global variables and routines.
  */
+void	funsetown __P((struct sigio *));
+void	funsetownlst __P((struct sigiolst *));
+int	fsetown __P((pid_t, struct sigio **, void (*) (struct sigio *) ));
+pid_t	fgetown __P((struct sigio *));
 int	dupfdopen __P((struct filedesc *, int, int, int, int));
 int	fdalloc __P((struct proc *p, int want, int *result));
 int	fdavail __P((struct proc *p, int n));
@@ -109,6 +142,10 @@
 int	getvnode __P((struct filedesc *fdp, int fd, struct file **fpp));
 int	fdissequential __P((struct file *));
 void	fdsequential __P((struct file *, int));
+#endif
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_SIGIO);
 #endif
 
 #endif
--- sys/pipe.h.orig	Fri Sep  4 18:17:06 1998
+++ sys/pipe.h	Fri Sep 11 04:39:16 1998
@@ -102,7 +102,8 @@
 	struct	timespec pipe_atime;	/* time of last access */
 	struct	timespec pipe_mtime;	/* time of last modify */
 	struct	timespec pipe_ctime;	/* time of status change */
-	int	pipe_pgid;		/* process/group for async I/O */
+	struct	sigio *pipe_sigio;	/* credentials and proc * or pgrp *
+					 * for SIGIO/SIGURG */
 	struct	pipe *pipe_peer;	/* link with other direction */
 	u_int	pipe_state;		/* pipe status info */
 	int	pipe_busy;		/* busy flag, mostly to handle rundown sanely */
--- sys/proc.h.orig	Fri Sep  4 18:17:07 1998
+++ sys/proc.h	Fri Sep 11 04:23:59 1998
@@ -52,6 +52,7 @@
 #endif
 #include <sys/ucred.h>
 #include <sys/queue.h>
+#include <sys/filedesc.h>		/* For struct sigiolst */
 
 /*
  * One structure allocated per session.
@@ -71,6 +72,7 @@
 	LIST_ENTRY(pgrp) pg_hash;	/* Hash chain. */
 	LIST_HEAD(, proc) pg_members;	/* Pointer to pgrp members. */
 	struct	session *pg_session;	/* Pointer to session. */
+	struct  sigiolst pg_sigiolst;	/* List of sigio sources */
 	pid_t	pg_id;			/* Pgrp id. */
 	int	pg_jobc;	/* # procs qualifying pgrp for job control */
 };
@@ -160,6 +162,7 @@
 	unsigned char	p_pfsflags;	/* procfs flags */
 	char	p_pad3[2];		/* padding for alignment */
 	register_t p_retval[2];		/* syscall aux returns */
+	struct	sigiolst p_sigiolst;	/* List of sigio sources */
 
 /* End area that is zeroed on creation. */
 #define	p_endzero	p_startcopy
--- sys/signalvar.h.orig	Fri Sep  4 18:17:08 1998
+++ sys/signalvar.h	Fri Sep 11 05:07:14 1998
@@ -152,6 +152,7 @@
 #ifdef KERNEL
 struct pgrp;
 struct proc;
+struct sigio;
 
 /*
  * Machine-independent functions:
@@ -166,6 +167,7 @@
 void	sigexit __P((struct proc *p, int signum));
 void	siginit __P((struct proc *p));
 void	trapsignal __P((struct proc *p, int sig, u_long code));
+void	pgsigio __P((struct sigio *, int signum, int checkctty));
 
 /*
  * Machine-dependent functions:
--- sys/socketvar.h.orig	Fri Sep  4 18:17:09 1998
+++ sys/socketvar.h	Fri Sep 11 04:26:20 1998
@@ -77,7 +77,8 @@
 	short	so_qlimit;		/* max number queued connections */
 	short	so_timeo;		/* connection timeout */
 	u_short	so_error;		/* error affecting connection */
-	pid_t	so_pgid;		/* pgid for signals */
+	struct  sigio *so_sigio;	/* credentials and proc * or pgrp *
+					 * for SIGIO/SIGURG */
 	u_long	so_oobmark;		/* chars to oob mark */
 /*
  * Variables for socket buffering.
@@ -282,6 +283,7 @@
 int	soo_poll __P((struct file *fp, int events, struct ucred *cred,
 	    struct proc *p));
 int	soo_stat __P((struct socket *so, struct stat *ub));
+void	soo_unsetown __P((struct sigio *));
 
 /*
  * From uipc_socket and friends
--- sys/tty.h.orig	Fri Sep  4 18:17:12 1998
+++ sys/tty.h	Fri Sep 11 03:40:59 1998
@@ -79,6 +79,8 @@
 	int     t_timeout;              /* Timeout for ttywait() */
 	struct	pgrp *t_pgrp;		/* Foreground process group. */
 	struct	session *t_session;	/* Enclosing session. */
+	struct  sigio *t_sigio;		/* credentials and proc * or pgrp *
+					 * for SIGIO/SIGURG */
 	struct	selinfo t_rsel;		/* Tty read/oob select. */
 	struct	selinfo t_wsel;		/* Tty write select. */
 	struct	termios t_termios;	/* Termios state. */
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199809112353.QAA17235>