Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Sep 1997 01:01:48 -0700 (PDT)
From:      Don Lewis <Don.Lewis@tsc.tdk.com>
To:        freebsd-hackers@freebsd.org
Subject:   F_SETOWN implementation redesign
Message-ID:  <199709270801.BAA00388@salsa.gv.tsc.tdk.com>

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

After hearing about the OpenBSD security fix for F_SETOWN, I went digging
through the FreeBSD mail list archives and stumbled across a lot of
complaints about the current F_SETOWN implementation dating back to the
early part of 1996 (as well as mention of the security flaw).  This inspired
me to revamp the F_SETOWN implementation to address some of these issues.

Security:

	I added credential checking which should work in a similar manner
	as the OpenBSD change.

	I added a restriction that only allows F_SETOWN to specify a
	process or process group in the same session as the caller.
	This change is somewhat debatable, but I can't think of a good
	use for allowing a process in another session to be specified
	and there is some potential for misuse as well as traps for
	the careless.

	When a process exits or a process group loses all it's members,
	any references to it specified by F_SETOWN are revoked even though
	the device or socket has not been closed (it may be held open by
	another process).  The old implementation would start sending
	signals to a new process once the process IDs wrapped around.


Funtionality:

	The old implementation used TIOCSPGRP when used on a tty device.
	This meant that you could only do async I/O on your controlling
	tty, which meant that you were limited to doing async I/O on
	at most one tty device.  My new implementation separates the
	F_SETOWN functionality from TIOCSPGRP on tty devices, so you
	can do async I/O on multiple devices and still have a separate
	control tty.  The only restriction is that these tty devices
	can't be the control ttys for another session.

	The new implementation always returns an error if you specify
	a non-existent process or process group.


Performance:

	The old implemenation needed to search for the process group
	or process whenever it wanted to deliver a signal.  The new
	implementation keeps a pointer, which should reduce the overhead
	for heavy users of async I/O.


The attached patch is relative to my somewhat hacked copy of 2.1-stable,
so it might not apply quite cleanly to a fresh copy.  It'll require even
more changes to make it work with 2.2 or later (for instance the
appropriate changes will need to be made to kern_pipe.c).  I've only done
limited testing so far, but I thought this would be an appropriate time
to share my work.

One thing to consider is whether it is appropriate to remove the
TIOCSPGRP/TIOCGPGRP code from the non-tty drivers.  I left it in in
case anyone is using these ioctl commands instead of F_SETOWN or
F_GETOWN on non-ttys.  Removing this code would reduce the bloat
somewhat.

			---  Truck

Index: lib/libc/sys/fcntl.2
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/lib/libc/sys/fcntl.2,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 fcntl.2
--- fcntl.2	1997/05/09 09:31:04	1.1.1.1
+++ fcntl.2	1997/09/27 01:35:13
@@ -477,29 +477,23 @@
 .Dv F_SETLKW ,
 and satisfying the lock or unlock request would result in the
 number of locked regions in the system exceeding a system-imposed limit.
+.It Bq Er ENOTTY
+.Fa Cmd
+is
+.Dv F_GETOWN
+or
+.Dv F_SETOWN ,
+.Fa fd
+refers to a descriptor open on a terminal device (as opposed to a
+descriptor open on a socket), and the device is the controlling
+terminal for a session other than the session of the calling process.
 .It Bq Er ESRCH
 .Fa Cmd
 is
 .Dv F_SETOWN
 and
-the process ID given as argument is not in use.
+the process ID or process group ID given as argument is not in use.
 .El
-.Pp
-In addition, if 
-.Fa fd
-refers to a descriptor open on a terminal device (as opposed to a
-descriptor open on a socket), a
-.Fa cmd
-of
-.Dv F_SETOWN
-can fail for the same reasons as in
-.Xr tcsetpgrp 3 ,
-and a
-.Fa cmd
-of
-.Dv F_GETOWN
-for the reasons as stated in
-.Xr tcgetpgrp 3 .
 .Sh SEE ALSO
 .Xr close 2 ,
 .Xr execve 2 ,
@@ -507,8 +501,6 @@
 .Xr getdtablesize 2 ,
 .Xr open 2 ,
 .Xr sigvec 2 ,
-.Xr tcgetpgrp 3 ,
-.Xr tcsetpgrp 3
 .Sh HISTORY
 The
 .Nm
Index: sys/kern/kern_descrip.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/kern_descrip.c,v
retrieving revision 1.2
diff -u -r1.2 kern_descrip.c
--- kern_descrip.c	1997/05/13 11:55:43	1.2
+++ kern_descrip.c	1997/09/26 23:24:36
@@ -226,30 +226,13 @@
 		return (error);
 
 	case F_GETOWN:
-		if (fp->f_type == DTYPE_SOCKET) {
-			*retval = ((struct socket *)fp->f_data)->so_pgid;
-			return (0);
-		}
 		error = (*fp->f_ops->fo_ioctl)
-			(fp, (int)TIOCGPGRP, (caddr_t)retval, p);
-		*retval = -*retval;
+			(fp, (int)FIOGETOWN, (caddr_t)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, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
+			(fp, (int)FIOSETOWN, (caddr_t)&uap->arg, p));
 
 	case F_SETLKW:
 		flg |= F_WAIT;
@@ -325,6 +308,94 @@
 		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->sio_pgid == 0)
+		return;
+
+	if (sigio->sio_pgid < 0) {
+		SLIST_REMOVE(&(sigio->sio_pgrp->pg_sigiolst), sigio, sigio,
+			     sio_pgsigio);
+		sigio->sio_pgrp = NULL;
+	} else if (sigio->sio_pgid > 0) {
+		SLIST_REMOVE(&(sigio->sio_proc->p_sigiolst), sigio, sigio,
+			     sio_pgsigio);
+		sigio->sio_proc = NULL;
+	}
+	sigio->sio_pgid = 0;
+	crfree(sigio->sio_ucred);
+	sigio->sio_ucred = NULL;
+}
+
+/*
+ * 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, sigio, funset)
+	register pid_t pgid;
+	register struct sigio *sigio;
+	void (*funset) __P((struct sigio *));
+{
+	if (pgid == 0) {
+		funsetown(sigio);
+		return (0);
+	} else if (pgid > 0) {
+		register struct proc *proc = pfind(pgid);
+
+		if (proc == NULL)
+			return (ESRCH);
+		else if (proc->p_session != curproc->p_session)
+			return (EPERM);
+
+		funsetown(sigio);
+
+		SLIST_INSERT_HEAD(&(proc->p_sigiolst), sigio, sio_pgsigio);
+		sigio->sio_proc = proc;
+	} else /* if (pgid < 0) */ {
+		register struct pgrp *pgrp = pgfind(-pgid);
+
+		if (pgrp == NULL)
+			return (ESRCH);
+		else if (pgrp->pg_session != curproc->p_session)
+			return (EPERM);
+
+		funsetown(sigio);
+
+		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;
+
+	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->sio_pgid);
 }
 
 /*
Index: sys/kern/kern_exit.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/kern_exit.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 kern_exit.c
--- kern_exit.c	1997/05/09 09:34:33	1.1.1.1
+++ kern_exit.c	1997/09/26 23:25:32
@@ -131,6 +131,14 @@
 	untimeout(realitexpire, (caddr_t)p);
 
 	/*
+	 * Reset any sigio structures pointing to us as a result of
+	 * F_SETOWN with our pid
+	 */
+	while (p->p_sigiolst.slh_first != NULL)
+		(*p->p_sigiolst.slh_first->sio_unsetown)
+		    (p->p_sigiolst.slh_first);
+
+	/*
 	 * Close open files and release open-file table.
 	 * This may block!
 	 */
Index: sys/kern/kern_proc.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/kern_proc.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 kern_proc.c
--- kern_proc.c	1997/05/09 09:34:34	1.1.1.1
+++ kern_proc.c	1997/09/27 06:31:39
@@ -49,6 +49,7 @@
 #include <sys/ioctl.h>
 #include <sys/tty.h>
 #include <sys/signalvar.h>
+#include <sys/filedesc.h>
 
 struct prochd qs[NQS];		/* as good a place as any... */
 struct prochd rtqs[NQS];	/* Space for REALTIME queues too */
@@ -246,6 +247,7 @@
 		pgrphash[n] = pgrp;
 		pgrp->pg_jobc = 0;
 		pgrp->pg_mem = NULL;
+		SLIST_INIT(&(pgrp->pg_sigiolst));
 	} else if (pgrp == p->p_pgrp)
 		return (0);
 
@@ -317,6 +319,14 @@
 	register struct pgrp *pgrp;
 {
 	register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
+
+	/*
+	 * Reset any sigio structures pointing to us as a result of
+	 * F_SETOWN with our pgid
+	 */
+	while (pgrp->pg_sigiolst.slh_first != NULL)
+		(*pgrp->pg_sigiolst.slh_first->sio_unsetown)
+		    (pgrp->pg_sigiolst.slh_first);
 
 	if (pgrp->pg_session->s_ttyp != NULL &&
 	    pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
Index: sys/kern/kern_sig.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/kern_sig.c,v
retrieving revision 1.2
diff -u -r1.2 kern_sig.c
--- kern_sig.c	1997/05/13 11:58:02	1.2
+++ kern_sig.c	1997/09/26 13:02:08
@@ -93,6 +93,16 @@
 	    ((signum) == SIGCONT && (q)->p_session == (p)->p_session))
 #endif
 
+/*
+ * 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)
+
 struct sigaction_args {
 	int	signum;
 	struct	sigaction *nsa;
@@ -1241,4 +1251,27 @@
 
 	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
+sigio_p_or_pg(sigio, signum, checkctty)
+	register struct sigio *sigio;
+	int signum, checkctty;
+{
+	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_mem; p != NULL; p = p->p_pgrpnxt)
+			if (CANSIGIO(sigio->sio_ruid, sigio->sio_ucred, p) &&
+			    (checkctty == 0 || (p->p_flag & P_CONTROLT)))
+				psignal(p, signum);
+	}
 }
Index: sys/kern/subr_log.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/subr_log.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 subr_log.c
--- subr_log.c	1997/05/09 09:34:34	1.1.1.1
+++ subr_log.c	1997/09/26 22:45:58
@@ -46,6 +46,7 @@
 #include <sys/msgbuf.h>
 #include <sys/file.h>
 #include <sys/signalvar.h>
+#include <sys/filedesc.h>		/* get fsetown, funsetown, fgetown */
 
 #define LOG_RDPRI	(PZERO + 1)
 
@@ -55,7 +56,8 @@
 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 pointer to proc
+					 * or group for SIGIO */
 } logsoftc;
 
 int	log_open;			/* also used in log() */
@@ -72,7 +74,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);
 }
 
@@ -86,6 +89,7 @@
 
 	log_open = 0;
 	logsoftc.sc_state = 0;
+	funsetown(&logsoftc.sc_sigio);
 	return (0);
 }
 
@@ -166,12 +170,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)
+		sigio_p_or_pg(&(logsoftc.sc_sigio), SIGIO, 0);
 	if (logsoftc.sc_state & LOG_RDWAIT) {
 		wakeup((caddr_t)msgbufp);
 		logsoftc.sc_state &= ~LOG_RDWAIT;
@@ -188,7 +188,7 @@
 	struct proc *p;
 {
 	long l;
-	int s;
+	int s, error;
 
 	switch (com) {
 
@@ -212,12 +212,25 @@
 			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;
+
 	case TIOCSPGRP:
-		logsoftc.sc_pgid = *(int *)data;
+		error = fsetown(-(*(int *)data), &(logsoftc.sc_sigio),
+				funsetown);
+		if (error)
+			return (error);
 		break;
 
 	case TIOCGPGRP:
-		*(int *)data = logsoftc.sc_pgid;
+		*(int *)data = -fgetown(&(logsoftc.sc_sigio));
 		break;
 
 	default:
Index: sys/kern/sys_generic.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/sys_generic.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 sys_generic.c
--- sys_generic.c	1997/05/09 09:34:34	1.1.1.1
+++ sys_generic.c	1997/09/26 10:54:41
@@ -472,36 +472,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);
 		/*
Index: sys/kern/sys_socket.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/sys_socket.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 sys_socket.c
--- sys_socket.c	1997/05/09 09:34:35	1.1.1.1
+++ sys_socket.c	1997/09/26 23:14:42
@@ -76,6 +76,19 @@
 		uio, (struct mbuf *)0, (struct mbuf *)0, 0));
 }
 
+/*
+ * 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;
@@ -84,6 +97,7 @@
 	struct proc *p;
 {
 	register struct socket *so = (struct socket *)fp->f_data;
+	register int s, error;
 
 	switch (cmd) {
 
@@ -110,12 +124,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:
Index: sys/kern/tty.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/tty.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 tty.c
--- tty.c	1997/05/09 09:34:33	1.1.1.1
+++ tty.c	1997/09/26 23:28:11
@@ -86,6 +86,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
@@ -237,10 +238,13 @@
 {
 	int s;
 
+
 	s = spltty();
 	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);
@@ -690,6 +694,19 @@
 }
 
 /*
+ * Callback to undo FIOSETOWN on process or process group death
+ */
+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.
@@ -758,6 +775,21 @@
 		*(int *)data = ttnread(tp);
 		splx(s);
 		break;
+	case FIOSETOWN:
+		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);
@@ -2077,7 +2109,7 @@
 	if (tp->t_rsel.si_pid != 0)
 		selwakeup(&tp->t_rsel);
 	if (ISSET(tp->t_state, TS_ASYNC))
-		pgsignal(tp->t_pgrp, SIGIO, 1);
+		sigio_p_or_pg(&(tp->t_sigio), SIGIO, (tp->t_session != NULL));
 	wakeup(TSA_HUP_OR_INPUT(tp));
 }
 
Index: sys/kern/uipc_socket.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/uipc_socket.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 uipc_socket.c
--- uipc_socket.c	1997/05/09 09:34:35	1.1.1.1
+++ uipc_socket.c	1997/09/26 11:43:25
@@ -166,6 +166,8 @@
 	int s = splnet();		/* conservative */
 	int error = 0;
 
+	funsetown(&(so->so_sigio));
+
 	if (so->so_options & SO_ACCEPTCONN) {
 		while (so->so_q0)
 			(void) soabort(so->so_q0);
@@ -1052,9 +1054,6 @@
 {
 	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);
+	sigio_p_or_pg(&(so->so_sigio), SIGURG, 0);
 	selwakeup(&so->so_rcv.sb_sel);
 }
Index: sys/kern/uipc_socket2.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/kern/uipc_socket2.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 uipc_socket2.c
--- uipc_socket2.c	1997/05/10 08:30:30	1.1.1.2
+++ uipc_socket2.c	1997/09/26 22:50:38
@@ -177,7 +177,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);
 	(void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat);
 	soqinsque(head, so, soqueue);
 	if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH,
@@ -328,10 +328,7 @@
 		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);
+		sigio_p_or_pg(&(so->so_sigio), SIGIO, 0);
 	}
 }
 
Index: sys/net/bpf.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/net/bpf.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 bpf.c
--- bpf.c	1997/05/09 09:34:44	1.1.1.1
+++ bpf.c	1997/09/27 00:11:57
@@ -59,6 +59,7 @@
 #include <sys/proc.h>
 #include <sys/user.h>
 #include <sys/ioctl.h>
+#include <sys/filedesc.h>		/* get fsetown, funsetown, fgetown */
 
 #include <sys/file.h>
 #if defined(sparc) && BSD < 199103
@@ -352,6 +353,7 @@
 	register int s;
 
 	s = splimp();
+	funsetown(&d->bd_sigio);
 	if (d->bd_bif)
 		bpf_detachd(d);
 	splx(s);
@@ -510,10 +512,7 @@
 
 	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);
+		sigio_p_or_pg(&(d->bd_sigio), d->bd_sig, 0);
 
 #if BSD >= 199103
 	selwakeup(&d->bd_sel);
@@ -589,6 +588,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()].
@@ -815,18 +827,28 @@
 		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;
+
+	case TIOCSPGRP:
+		s = splimp();
+		error = fsetown(-(*(int *)addr), &(d->bd_sigio), bpfunsetown);
+		splx(s);
 		break;
 
 	case TIOCGPGRP:
-		*(int *)addr = d->bd_pgid;
+		s = splimp();
+		*(int *)addr = -fgetown(&(d->bd_sigio));
+		splx(s);
 		break;
 
 	case BIOCSRSIG:		/* Set receive signal */
Index: sys/net/bpfdesc.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/net/bpfdesc.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 bpfdesc.h
--- bpfdesc.h	1997/05/09 09:34:45	1.1.1.1
+++ bpfdesc.h	1997/09/26 14:06:51
@@ -44,6 +44,7 @@
 #define _NET_BPFDESC_H_
 
 #include <sys/select.h>
+#include <sys/proc.h>			/* pick up sigio */
 
 /*
  * Descriptor associated with each open bpf file.
@@ -78,7 +79,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 pointer to proc
+					 * or group for SIGIO */
 #if BSD < 199103
 	u_char		bd_selcoll;	/* true if selects collide */
 	int		bd_timedout;
Index: sys/net/if_tun.c
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/net/if_tun.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 if_tun.c
--- if_tun.c	1997/05/09 09:34:46	1.1.1.1
+++ if_tun.c	1997/09/27 00:18:39
@@ -30,6 +30,7 @@
 #include <sys/select.h>
 #include <sys/file.h>
 #include <sys/signalvar.h>
+#include <sys/filedesc.h>
 #ifdef __FreeBSD__
 #include <sys/kernel.h>
 #endif
@@ -194,7 +195,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);
@@ -359,11 +360,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))
-			psignal(p, SIGIO);
+	if (tp->tun_flags & TUN_ASYNC) {
+		sigio_p_or_pg(&(tp->tun_sigio), SIGIO, 0);
 	}
 	selwakeup(&tp->tun_rsel);
 	return 0;
@@ -423,12 +421,20 @@
 			*(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);
+
 	case TIOCSPGRP:
-		tp->tun_pgrp = *(int *)data;
-		break;
+		return (fsetown(-(*(int *)data), &(tp->tun_sigio), funsetown));
+
 	case TIOCGPGRP:
-		*(int *)data = tp->tun_pgrp;
-		break;
+		*(int *)data = -fgetown(&(tp->tun_sigio));
+		return (0);
+
 	default:
 		return (ENOTTY);
 	}
Index: sys/net/if_tun.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/net/if_tun.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 if_tun.h
--- if_tun.h	1997/05/09 09:34:46	1.1.1.1
+++ if_tun.h	1997/09/26 12:25:04
@@ -33,7 +33,8 @@
 #define	TUN_READY	(TUN_OPEN | TUN_INITED | TUN_IASET)
 
 	struct	ifnet tun_if;		/* the interface */
-	int	tun_pgrp;		/* the process group - if any */
+	struct  sigio tun_sigio;	/* credentials and pointer to proc
+					 * or group for SIGIO */
 	struct	selinfo	tun_rsel;	/* read select */
 	struct	selinfo	tun_wsel;	/* write select (not used) */
 #if NBPFILTER > 0
Index: sys/sys/filedesc.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/sys/filedesc.h,v
retrieving revision 1.2
diff -u -r1.2 filedesc.h
--- filedesc.h	1997/05/13 12:05:40	1.2
+++ filedesc.h	1997/09/26 22:39:20
@@ -96,6 +96,9 @@
 /*
  * Kernel global variables and routines.
  */
+void	funsetown __P((struct sigio *));
+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));
Index: sys/sys/proc.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/sys/proc.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 proc.h
--- proc.h	1997/05/09 09:35:08	1.1.1.1
+++ proc.h	1997/09/26 22:37:25
@@ -46,6 +46,7 @@
 #include <sys/rtprio.h>			/* For struct rtprio. */
 #include <sys/select.h>			/* For struct selinfo. */
 #include <sys/time.h>			/* For structs itimerval, timeval. */
+#include <sys/queue.h>			/* For SLIST_HEAD, SLIST_ENTRY. */
 
 /*
  * One structure allocated per session.
@@ -58,6 +59,8 @@
 	char	s_login[MAXLOGNAME];	/* Setlogin() name. */
 };
 
+SLIST_HEAD(sigiolst, sigio);
+
 /*
  * One structure allocated per process group.
  */
@@ -65,6 +68,7 @@
 	struct	pgrp *pg_hforw;		/* Forward link in hash bucket. */
 	struct	proc *pg_mem;		/* 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 */
 };
@@ -136,9 +140,11 @@
 
 	struct	vnode *p_textvp;	/* Vnode of executable. */
 
+	struct  sigiolst p_sigiolst;	/* List of sigio sources */
+
 	char	p_lock;			/* Process lock count. */
 	char	p_pad2[3];		/* alignment */
-	long	p_spare[2];		/* Pad to 256, avoid shifting eproc. XXX */
+	long	p_spare[1];		/* Pad to 256, avoid shifting eproc. XXX */
 
 /* End area that is zeroed on creation. */
 #define	p_endzero	p_startcopy
@@ -221,6 +227,24 @@
 	gid_t	p_svgid;		/* Saved effective group id. */
 	int	p_refcnt;		/* Number of references. */
 };
+
+/*
+ *
+ */
+struct	sigio {
+	struct	ucred *sio_ucred;	/* Current credentials. */
+	uid_t	sio_ruid;		/* Real user id. */
+	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 */
+	pid_t	sio_pgid;		/* pgid for signals */
+};
+#define	sio_proc	sio_u.siu_proc
+#define	sio_pgrp	sio_u.siu_pgrp
+
 
 #ifdef KERNEL
 /*
Index: sys/sys/signalvar.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/sys/signalvar.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 signalvar.h
--- signalvar.h	1997/05/09 09:35:09	1.1.1.1
+++ signalvar.h	1997/09/26 13:24:15
@@ -162,6 +162,7 @@
 void	sigexit	__P((struct proc *, int));
 void	siginit __P((struct proc *p));
 void	trapsignal __P((struct proc *p, int sig, unsigned code));
+void	sigio_p_or_pg __P((struct sigio *, int signum, int checkctty));
 
 /*
  * Machine-dependent functions:
Index: sys/sys/socketvar.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/sys/socketvar.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 socketvar.h
--- socketvar.h	1997/05/09 09:35:09	1.1.1.1
+++ socketvar.h	1997/09/26 22:52:13
@@ -40,6 +40,7 @@
 #include <sys/stat.h>			/* for struct stat */
 #include <sys/filedesc.h>		/* for struct filedesc */
 #include <sys/select.h>			/* for struct selinfo */
+#include <sys/proc.h>			/* for struct sigio */
 
 /*
  * Kernel structure per socket.
@@ -73,7 +74,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 pointer to proc
+					 * or group for SIGIO/SIGURG */
 	u_long	so_oobmark;		/* chars to oob mark */
 /*
  * Variables for socket buffering.
@@ -211,6 +213,7 @@
 int	soo_select __P((struct file *fp, int which, struct proc *p));
 int 	soo_close __P((struct file *fp, struct proc *p));
 int	soo_stat __P((struct socket *, struct stat *));
+void	soo_unsetown __P((struct sigio *));
 
 /*
  * From uipc_socket and friends
Index: sys/sys/tty.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/sys/tty.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 tty.h
--- tty.h	1997/05/09 09:35:10	1.1.1.1
+++ tty.h	1997/09/26 13:00:15
@@ -44,6 +44,7 @@
 
 #include <sys/termios.h>
 #include <sys/select.h>		/* For struct selinfo. */
+#include <sys/proc.h>		/* For struct sigio */
 
 /*
  * Clists are character lists, which is a variable length linked list
@@ -79,6 +80,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 pointer to proc
+					 * or group for SIGIO */
 	struct	selinfo t_rsel;		/* Tty read/oob select. */
 	struct	selinfo t_wsel;		/* Tty write select. */
 	struct	termios t_termios;	/* Termios state. */
Index: sys/sys/types.h
===================================================================
RCS file: /usr/cvs/repository/FreeBSD-2.1/sys/sys/types.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 types.h
--- types.h	1997/05/09 09:35:10	1.1.1.1
+++ types.h	1997/09/26 13:41:46
@@ -157,6 +157,7 @@
  */
 struct	proc;
 struct	pgrp;
+struct	sigio;
 struct	ucred;
 struct	rusage;
 struct	file;



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