diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2018-11-12 15:09:18 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2018-11-12 15:09:18 +0000 |
commit | 77fd9e73582f45aac9306658b8e330cf582b96cf (patch) | |
tree | c9ced8835ad9c317aaaa8ceda23630c960677071 /sys | |
parent | c331e297d58751510813f05e89fe8f43e6f59c02 (diff) |
Add a mechanism for managing asynchronous IO signal registrations.
It centralizes IO signal privilege checking and makes possible to revoke
a registration when the target process or process group is deleted.
Adapted from FreeBSD.
OK kettenis@ mpi@ guenther@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_exit.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 272 | ||||
-rw-r--r-- | sys/sys/malloc.h | 6 | ||||
-rw-r--r-- | sys/sys/proc.h | 5 | ||||
-rw-r--r-- | sys/sys/sigio.h | 95 | ||||
-rw-r--r-- | sys/sys/signalvar.h | 5 |
8 files changed, 385 insertions, 9 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 1526ce6118f..b190eb6a7ac 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exit.c,v 1.170 2018/10/04 20:07:54 kettenis Exp $ */ +/* $OpenBSD: kern_exit.c,v 1.171 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */ /* @@ -186,6 +186,8 @@ exit1(struct proc *p, int rv, int flags) #endif if ((p->p_flag & P_THREAD) == 0) { + sigio_freelist(&pr->ps_sigiolst); + /* close open files and release open-file table */ fdfree(p); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 93d80d221ae..dd26b0ac5c8 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_fork.c,v 1.207 2018/08/30 03:30:25 visa Exp $ */ +/* $OpenBSD: kern_fork.c,v 1.208 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */ /* @@ -208,6 +208,7 @@ process_initialize(struct process *pr, struct proc *p) LIST_INIT(&pr->ps_children); LIST_INIT(&pr->ps_ftlist); LIST_INIT(&pr->ps_kqlist); + LIST_INIT(&pr->ps_sigiolst); timeout_set(&pr->ps_realit_to, realitexpire, pr); } diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 0ce3d285796..934cf455ba1 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_proc.c,v 1.84 2018/06/21 13:58:21 visa Exp $ */ +/* $OpenBSD: kern_proc.c,v 1.85 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: kern_proc.c,v 1.14 1996/02/09 18:59:41 christos Exp $ */ /* @@ -278,6 +278,7 @@ enternewpgrp(struct process *pr, struct pgrp *pgrp, struct session *newsess) } pgrp->pg_id = pr->ps_pid; LIST_INIT(&pgrp->pg_members); + LIST_INIT(&pgrp->pg_sigiolst); LIST_INSERT_HEAD(PGRPHASH(pr->ps_pid), pgrp, pg_hash); pgrp->pg_jobc = 0; @@ -328,6 +329,7 @@ leavepgrp(struct process *pr) void pgdelete(struct pgrp *pgrp) { + sigio_freelist(&pgrp->pg_sigiolst); if (pgrp->pg_session->s_ttyp != NULL && pgrp->pg_session->s_ttyp->t_pgrp == pgrp) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 100615dd9b8..de93fa68682 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.224 2018/08/03 14:47:56 deraadt Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.225 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -87,6 +87,10 @@ int cansignal(struct proc *, struct process *, int); struct pool sigacts_pool; /* memory pool for sigacts structures */ +void sigio_del(struct sigiolst *); +void sigio_unlink(struct sigio_ref *, struct sigiolst *); +struct mutex sigio_lock = MUTEX_INITIALIZER(IPL_HIGH); + /* * Can thread p, send the signal signum to process qr? */ @@ -698,6 +702,9 @@ killpg1(struct proc *cp, int signum, int pgid, int all) (euid) == (pr)->ps_ucred->cr_svuid || \ (euid) == (pr)->ps_ucred->cr_uid) +#define CANSIGIO(cr, pr) \ + CANDELIVER((cr)->cr_ruid, (cr)->cr_uid, (pr)) + /* * Deliver signum to pgid, but first check uid/euid against each * process and see if it is permitted. @@ -753,6 +760,37 @@ pgsignal(struct pgrp *pgrp, int signum, int checkctty) } /* + * Send a SIGIO or SIGURG signal to a process or process group using stored + * credentials rather than those of the current process. + */ +void +pgsigio(struct sigio_ref *sir, int sig, int checkctty) +{ + struct process *pr; + struct sigio *sigio; + + if (sir->sir_sigio == NULL) + return; + + mtx_enter(&sigio_lock); + sigio = sir->sir_sigio; + if (sigio == NULL) + goto out; + if (sigio->sio_pgid > 0) { + if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc)) + prsignal(sigio->sio_proc, sig); + } else if (sigio->sio_pgid < 0) { + LIST_FOREACH(pr, &sigio->sio_pgrp->pg_members, ps_pglist) { + if (CANSIGIO(sigio->sio_ucred, pr) && + (checkctty == 0 || (pr->ps_flags & PS_CONTROLT))) + prsignal(pr, sig); + } + } +out: + mtx_leave(&sigio_lock); +} + +/* * Recalculate the signal mask and reset the signal disposition after * usermode frame for delivery is formed. */ @@ -2047,3 +2085,235 @@ single_thread_clear(struct proc *p, int flag) SCHED_UNLOCK(s); } } + +void +sigio_del(struct sigiolst *rmlist) +{ + struct sigio *sigio; + + while ((sigio = LIST_FIRST(rmlist)) != NULL) { + LIST_REMOVE(sigio, sio_pgsigio); + crfree(sigio->sio_ucred); + free(sigio, M_SIGIO, sizeof(*sigio)); + } +} + +void +sigio_unlink(struct sigio_ref *sir, struct sigiolst *rmlist) +{ + struct sigio *sigio; + + MUTEX_ASSERT_LOCKED(&sigio_lock); + + sigio = sir->sir_sigio; + if (sigio != NULL) { + KASSERT(sigio->sio_myref == sir); + sir->sir_sigio = NULL; + + if (sigio->sio_pgid > 0) + sigio->sio_proc = NULL; + else + sigio->sio_pgrp = NULL; + LIST_REMOVE(sigio, sio_pgsigio); + + LIST_INSERT_HEAD(rmlist, sigio, sio_pgsigio); + } +} + +void +sigio_free(struct sigio_ref *sir) +{ + struct sigiolst rmlist; + + if (sir->sir_sigio == NULL) + return; + + LIST_INIT(&rmlist); + + mtx_enter(&sigio_lock); + sigio_unlink(sir, &rmlist); + mtx_leave(&sigio_lock); + + sigio_del(&rmlist); +} + +void +sigio_freelist(struct sigiolst *sigiolst) +{ + struct sigiolst rmlist; + struct sigio *sigio; + + if (LIST_EMPTY(sigiolst)) + return; + + LIST_INIT(&rmlist); + + mtx_enter(&sigio_lock); + while ((sigio = LIST_FIRST(sigiolst)) != NULL) + sigio_unlink(sigio->sio_myref, &rmlist); + mtx_leave(&sigio_lock); + + sigio_del(&rmlist); +} + +int +sigio_setown(struct sigio_ref *sir, pid_t pgid) +{ + struct sigiolst rmlist; + struct proc *p = curproc; + struct pgrp *pgrp = NULL; + struct process *pr = NULL; + struct sigio *sigio; + int error; + + if (pgid == 0) { + sigio_free(sir); + return (0); + } + + sigio = malloc(sizeof(*sigio), M_SIGIO, M_WAITOK); + sigio->sio_pgid = pgid; + sigio->sio_ucred = crhold(p->p_ucred); + sigio->sio_myref = sir; + + LIST_INIT(&rmlist); + + /* + * The kernel lock, and not sleeping between prfind()/pgfind() and + * linking of the sigio ensure that the process or process group does + * not disappear unexpectedly. + */ + KERNEL_LOCK(); + mtx_enter(&sigio_lock); + + if (pgid > 0) { + pr = prfind(pgid); + if (pr == NULL) { + error = ESRCH; + goto fail; + } + + /* + * 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. + */ + if (pr->ps_session != p->p_p->ps_session) { + error = EPERM; + goto fail; + } + + if ((pr->ps_flags & PS_EXITING) != 0) { + error = ESRCH; + goto fail; + } + } else /* if (pgid < 0) */ { + pgrp = pgfind(-pgid); + if (pgrp == NULL) { + error = ESRCH; + goto fail; + } + + /* + * 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. + */ + if (pgrp->pg_session != p->p_p->ps_session) { + error = EPERM; + goto fail; + } + } + + if (pgid > 0) { + sigio->sio_proc = pr; + LIST_INSERT_HEAD(&pr->ps_sigiolst, sigio, sio_pgsigio); + } else { + sigio->sio_pgrp = pgrp; + LIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio); + } + + sigio_unlink(sir, &rmlist); + sir->sir_sigio = sigio; + + mtx_leave(&sigio_lock); + KERNEL_UNLOCK(); + + sigio_del(&rmlist); + + return (0); + +fail: + mtx_leave(&sigio_lock); + KERNEL_UNLOCK(); + + crfree(sigio->sio_ucred); + free(sigio, M_SIGIO, sizeof(*sigio)); + + return (error); +} + +pid_t +sigio_getown(struct sigio_ref *sir) +{ + struct sigio *sigio; + pid_t pgid = 0; + + mtx_enter(&sigio_lock); + sigio = sir->sir_sigio; + if (sigio != NULL) + pgid = sigio->sio_pgid; + mtx_leave(&sigio_lock); + + return (pgid); +} + +void +sigio_copy(struct sigio_ref *dst, struct sigio_ref *src) +{ + struct sigiolst rmlist; + struct sigio *newsigio, *sigio; + + sigio_free(dst); + + if (src->sir_sigio == NULL) + return; + + newsigio = malloc(sizeof(*newsigio), M_SIGIO, M_WAITOK); + LIST_INIT(&rmlist); + + mtx_enter(&sigio_lock); + + sigio = src->sir_sigio; + if (sigio == NULL) { + mtx_leave(&sigio_lock); + free(newsigio, M_SIGIO, sizeof(*newsigio)); + return; + } + + newsigio->sio_pgid = sigio->sio_pgid; + newsigio->sio_ucred = crhold(sigio->sio_ucred); + newsigio->sio_myref = dst; + if (newsigio->sio_pgid > 0) { + newsigio->sio_proc = sigio->sio_proc; + LIST_INSERT_HEAD(&newsigio->sio_proc->ps_sigiolst, newsigio, + sio_pgsigio); + } else { + newsigio->sio_pgrp = sigio->sio_pgrp; + LIST_INSERT_HEAD(&newsigio->sio_pgrp->pg_sigiolst, newsigio, + sio_pgsigio); + } + + sigio_unlink(dst, &rmlist); + dst->sir_sigio = newsigio; + + mtx_leave(&sigio_lock); + + sigio_del(&rmlist); +} diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index e5fb2caa906..b2b71f9b4d6 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.h,v 1.116 2017/11/27 09:23:44 mpi Exp $ */ +/* $OpenBSD: malloc.h,v 1.117 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: malloc.h,v 1.39 1998/07/12 19:52:01 augustss Exp $ */ /* @@ -97,7 +97,7 @@ /* 35-37 - free */ #define M_FILE 38 /* Open file structure */ #define M_FILEDESC 39 /* Open file descriptor table */ -/* 40 - free */ +#define M_SIGIO 40 /* Sigio structures */ #define M_PROC 41 /* Proc structures */ #define M_SUBPROC 42 /* Proc sub-structures */ #define M_VCLUSTER 43 /* Cluster for VFS */ @@ -224,7 +224,7 @@ NULL, /* 37 */ \ "file", /* 38 M_FILE */ \ "file desc", /* 39 M_FILEDESC */ \ - NULL, /* 40 */ \ + "sigio", /* 40 M_SIGIO */ \ "proc", /* 41 M_PROC */ \ "subproc", /* 42 M_SUBPROC */ \ "VFS cluster", /* 43 M_VCLUSTER */ \ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index f1058ded5c2..5c7f381bb1c 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.260 2018/10/28 22:42:33 beck Exp $ */ +/* $OpenBSD: proc.h,v 1.261 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -49,6 +49,7 @@ #include <sys/mutex.h> /* For struct mutex */ #include <sys/resource.h> /* For struct rusage */ #include <sys/rwlock.h> /* For struct rwlock */ +#include <sys/sigio.h> /* For struct sigio */ #include <sys/tree.h> #ifdef _KERNEL @@ -80,6 +81,7 @@ struct pgrp { LIST_ENTRY(pgrp) pg_hash; /* Hash chain. */ LIST_HEAD(, process) pg_members;/* Pointer to pgrp members. */ struct session *pg_session; /* Pointer to session. */ + struct sigiolst pg_sigiolst; /* List of sigio structures. */ pid_t pg_id; /* Pgrp id. */ int pg_jobc; /* # procs qualifying pgrp for job control */ }; @@ -170,6 +172,7 @@ struct process { LIST_HEAD(, process) ps_children;/* Pointer to list of children. */ LIST_ENTRY(process) ps_hash; /* Hash chain. */ + struct sigiolst ps_sigiolst; /* List of sigio structures. */ struct sigacts *ps_sigacts; /* Signal actions, state */ struct vnode *ps_textvp; /* Vnode of executable. */ struct filedesc *ps_fd; /* Ptr to open files structure */ diff --git a/sys/sys/sigio.h b/sys/sys/sigio.h new file mode 100644 index 00000000000..27371f0e6bc --- /dev/null +++ b/sys/sys/sigio.h @@ -0,0 +1,95 @@ +/* $OpenBSD: sigio.h,v 1.1 2018/11/12 15:09:17 visa Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)filedesc.h 8.1 (Berkeley) 6/2/93 + * $FreeBSD: head/sys/sys/sigio.h 326023 2017-11-20 19:43:44Z pfg $ + */ + +#ifndef _SYS_SIGIO_H_ +#define _SYS_SIGIO_H_ + +struct sigio; +LIST_HEAD(sigiolst, sigio); + +/* + * sigio registration + * + * Locking: + * s sigio_lock + */ +struct sigio_ref { + struct sigio *sir_sigio; /* [s] associated sigio struct */ +}; + +#ifdef _KERNEL + +/* + * This structure holds the information needed to send a SIGIO or + * a SIGURG signal to a process or process group when new data arrives + * on a device or socket. The structure is placed on an LIST belonging + * to the proc or pgrp so that the entire list may be revoked when the + * process exits or the process group disappears. + * + * Locking: + * I immutable after creation + * s sigio_lock + */ +struct sigio { + union { + struct process *siu_proc; + /* [I] process to receive + * SIGIO/SIGURG */ + struct pgrp *siu_pgrp; /* [I] process group to receive ... */ + } sio_u; + LIST_ENTRY(sigio) sio_pgsigio; /* [s] sigio's for process or group */ + struct sigio_ref *sio_myref; /* [I] location of the pointer that + * holds the reference to + * this structure */ + struct ucred *sio_ucred; /* [I] current credentials */ + pid_t sio_pgid; /* [I] pgid for signals */ +}; +#define sio_proc sio_u.siu_proc +#define sio_pgrp sio_u.siu_pgrp + +static inline void +sigio_init(struct sigio_ref *sir) +{ + sir->sir_sigio = NULL; +} + +void sigio_copy(struct sigio_ref *, struct sigio_ref *); +void sigio_free(struct sigio_ref *); +void sigio_freelist(struct sigiolst *); +pid_t sigio_getown(struct sigio_ref *); +int sigio_setown(struct sigio_ref *, pid_t); + +#endif /* _KERNEL */ + +#endif /* _SYS_SIGIO_H_ */ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 91404ebd671..95291a08821 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signalvar.h,v 1.33 2018/07/18 16:55:17 bluhm Exp $ */ +/* $OpenBSD: signalvar.h,v 1.34 2018/11/12 15:09:17 visa Exp $ */ /* $NetBSD: signalvar.h,v 1.17 1996/04/22 01:23:31 christos Exp $ */ /* @@ -147,6 +147,8 @@ int sigprop[NSIG + 1] = { #ifdef _KERNEL enum signal_type { SPROCESS, STHREAD, SPROPAGATED }; +struct sigio_ref; + /* * Machine-independent functions: */ @@ -155,6 +157,7 @@ void execsigs(struct proc *p); void gsignal(int pgid, int sig); void csignal(pid_t pgid, int signum, uid_t uid, uid_t euid); int issignal(struct proc *p); +void pgsigio(struct sigio_ref *sir, int sig, int checkctty); void pgsignal(struct pgrp *pgrp, int sig, int checkctty); void psignal(struct proc *p, int sig); void ptsignal(struct proc *p, int sig, enum signal_type type); |