summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2018-11-12 15:09:18 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2018-11-12 15:09:18 +0000
commit77fd9e73582f45aac9306658b8e330cf582b96cf (patch)
treec9ced8835ad9c317aaaa8ceda23630c960677071
parentc331e297d58751510813f05e89fe8f43e6f59c02 (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@
-rw-r--r--sys/kern/kern_exit.c4
-rw-r--r--sys/kern/kern_fork.c3
-rw-r--r--sys/kern/kern_proc.c4
-rw-r--r--sys/kern/kern_sig.c272
-rw-r--r--sys/sys/malloc.h6
-rw-r--r--sys/sys/proc.h5
-rw-r--r--sys/sys/sigio.h95
-rw-r--r--sys/sys/signalvar.h5
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);