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>