summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorDan McDonald <danmcd@joyent.com>2021-05-25 14:08:27 -0400
committerDan McDonald <danmcd@joyent.com>2021-05-25 14:08:27 -0400
commitf390f85acaffd7dd53796db7f94f4df9523ed09c (patch)
tree54a128a5b3414b8f1c19455e0aa4ecb05d72ceb3 /usr/src
parent6a115942cd5340ddb10baaa726ec26d5f707e7fb (diff)
parent2576a450861a4a608f6bfabf01759987ff4ad97e (diff)
downloadillumos-joyent-f390f85acaffd7dd53796db7f94f4df9523ed09c.tar.gz
[illumos-gate merge]
commit 2576a450861a4a608f6bfabf01759987ff4ad97e 13829 genunix: cast between incompatible function types commit 2817ebc2366683391690bbd0e0dd2e82aaa281f7 13764 bhyve could reduce privileges(5) commit 90d74ed67b4bac801bf06d75825d9a9e4bd458d0 13786 bhyve could use ASLR commit 2851030d1db57fd5488bc19a8da8147d79711654 13788 restart of privilege-aware zone init fails commit 7c94ff60ae7c4cbdb9496a43a9d9eb85568413e3 13566 libm: 'fq[0]' may be used uninitialized
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.master1
-rw-r--r--usr/src/cmd/bhyve/Makefile2
-rw-r--r--usr/src/cmd/bhyve/bhyverun.c11
-rw-r--r--usr/src/cmd/bhyve/privileges.c191
-rw-r--r--usr/src/cmd/bhyve/privileges.h28
-rw-r--r--usr/src/lib/libm/Makefile.libm.com1
-rw-r--r--usr/src/lib/libm/common/C/__rem_pio2m.c14
-rw-r--r--usr/src/man/man4/bhyve_config.417
-rw-r--r--usr/src/uts/common/os/exit.c24
-rw-r--r--usr/src/uts/common/os/strsubr.c18
10 files changed, 287 insertions, 20 deletions
diff --git a/usr/src/Makefile.master b/usr/src/Makefile.master
index d65f527dfd..1e66090aec 100644
--- a/usr/src/Makefile.master
+++ b/usr/src/Makefile.master
@@ -1060,6 +1060,7 @@ ZVERBOSE= -Wl,-zverbose
ZASSERTDEFLIB= -Wl,-zassert-deflib
ZGUIDANCE= -Wl,-zguidance
ZFATALWARNINGS= -Wl,-zfatal-warnings
+ZASLR= -Wl,-zaslr
GSHARED= -shared
CCMT= -mt
diff --git a/usr/src/cmd/bhyve/Makefile b/usr/src/cmd/bhyve/Makefile
index 866f3773f4..6485a00b1c 100644
--- a/usr/src/cmd/bhyve/Makefile
+++ b/usr/src/cmd/bhyve/Makefile
@@ -64,6 +64,7 @@ SRCS = acpi.c \
pctestdev.c \
pm.c \
post.c \
+ privileges.c \
ps2kbd.c \
ps2mouse.c \
rfb.c \
@@ -157,6 +158,7 @@ $(PROG) := LDLIBS += \
NATIVE_LIBS += libz.so libsunw_crypto.so
$(ZHYVE_PROG) := LDLIBS += -lnvpair
$(MEVENT_TEST_PROG) := LDLIBS += -lsocket
+$(PROG) := LDFLAGS += $(ZASLR)
.KEEP_STATE:
diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c
index ca6a1bded6..6d966dc90f 100644
--- a/usr/src/cmd/bhyve/bhyverun.c
+++ b/usr/src/cmd/bhyve/bhyverun.c
@@ -114,6 +114,9 @@ __FBSDID("$FreeBSD$");
#include "rtc.h"
#include "vga.h"
#include "vmgenc.h"
+#ifndef __FreeBSD__
+#include "privileges.h"
+#endif
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
@@ -1545,6 +1548,10 @@ main(int argc, char *argv[])
exit(1);
}
+#ifndef __FreeBSD__
+ illumos_priv_init();
+#endif
+
calc_topolopgy();
#ifdef __FreeBSD__
build_vcpumaps();
@@ -1713,6 +1720,10 @@ main(int argc, char *argv[])
errx(EX_OSERR, "cap_enter() failed");
#endif
+#ifndef __FreeBSD__
+ illumos_priv_lock();
+#endif
+
#ifdef __FreeBSD__
/*
* Add CPU 0
diff --git a/usr/src/cmd/bhyve/privileges.c b/usr/src/cmd/bhyve/privileges.c
new file mode 100644
index 0000000000..fb370c029a
--- /dev/null
+++ b/usr/src/cmd/bhyve/privileges.c
@@ -0,0 +1,191 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+/*
+ * Two privilege sets are maintained. One which is the minimal privileges
+ * necessary to run bhyve - 'bhyve_priv_min' - and one which is the maximum
+ * privileges required - 'bhyve_priv_max'. This second set starts off identical
+ * to the first, and is added to by modules during initialisation depending on
+ * their requirements and their configuration.
+ * Once all modules are initialised, and before the VM is set running, the
+ * privileges are locked by setting the 'Permitted' privilege set from the
+ * contents of the maximum set, which is now the upper bound, and dropping back
+ * to the minimum set.
+ *
+ * Privileges are process wide, and this framework does not support threaded
+ * access. The ID of the thread that first initialises privileges is recorded,
+ * and all subsequent privilege operations must be done by the same thread.
+ */
+
+#include <err.h>
+#include <pthread.h>
+#include <priv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <upanic.h>
+#include <sys/debug.h>
+#include "config.h"
+#include "debug.h"
+#include "privileges.h"
+
+static pthread_t priv_thread;
+static priv_set_t *bhyve_priv_init;
+static priv_set_t *bhyve_priv_min;
+static priv_set_t *bhyve_priv_max;
+static bool priv_debug = false;
+
+#define DPRINTF(params) \
+ if (priv_debug) do { PRINTLN params; fflush(stdout); } while (0)
+
+static void
+illumos_priv_printset(const char *tag, priv_set_t *set)
+{
+ char *s;
+
+ s = priv_set_to_str(set, ',', PRIV_STR_LIT);
+ if (s == NULL) {
+ warn("priv_set_to_str(%s) failed", tag);
+ return;
+ }
+ DPRINTF((" + %s: %s", tag, s));
+ free(s);
+}
+
+void
+illumos_priv_reduce(void)
+{
+ VERIFY3S(pthread_equal(pthread_self(), priv_thread), !=, 0);
+ DPRINTF((" + Reducing privileges to minimum"));
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, bhyve_priv_min) != 0)
+ err(4, "failed to reduce privileges");
+}
+
+static void
+illumos_priv_add_set(priv_set_t *set, const char *priv, const char *src)
+{
+ VERIFY3S(pthread_equal(pthread_self(), priv_thread), !=, 0);
+ DPRINTF((" + Adding privilege %s (%s)", priv, src));
+ if (!priv_ismember(bhyve_priv_init, priv))
+ errx(4, "Privilege %s (for %s) not in initial set", priv, src);
+ if (priv_addset(set, priv) != 0)
+ err(4, "Failed to add %s privilege for %s", priv, src);
+}
+void
+illumos_priv_add(const char *priv, const char *src)
+{
+ illumos_priv_add_set(bhyve_priv_max, priv, src);
+}
+
+void
+illumos_priv_add_min(const char *priv, const char *src)
+{
+ illumos_priv_add_set(bhyve_priv_min, priv, src);
+ illumos_priv_add_set(bhyve_priv_max, priv, src);
+}
+
+void
+illumos_priv_init(void)
+{
+ priv_debug = get_config_bool_default("privileges.debug", false);
+
+ DPRINTF((" + Initialising privileges."));
+
+ if (priv_debug)
+ (void) setpflags(PRIV_DEBUG, 1);
+
+ priv_thread = pthread_self();
+
+ if ((bhyve_priv_init = priv_allocset()) == NULL)
+ err(4, "failed to allocate memory for initial priv set");
+ if ((bhyve_priv_min = priv_allocset()) == NULL)
+ err(4, "failed to allocate memory for minimum priv set");
+ if ((bhyve_priv_max = priv_allocset()) == NULL)
+ err(4, "failed to allocate memory for maximum priv set");
+
+ if (getppriv(PRIV_EFFECTIVE, bhyve_priv_init) != 0)
+ err(4, "failed to fetch current privileges");
+
+ if (priv_debug)
+ illumos_priv_printset("initial", bhyve_priv_init);
+
+ /*
+ * file_read is left in the minimum set to allow for lazy library
+ * loading.
+ */
+ priv_basicset(bhyve_priv_min);
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_FILE_LINK_ANY));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_FILE_WRITE));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_NET_ACCESS));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_PROC_EXEC));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_PROC_FORK));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_PROC_INFO));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_PROC_SECFLAGS));
+ VERIFY0(priv_delset(bhyve_priv_min, PRIV_PROC_SESSION));
+
+ priv_intersect(bhyve_priv_init, bhyve_priv_min);
+ priv_copyset(bhyve_priv_min, bhyve_priv_max);
+
+ /*
+ * These are privileges that we know will always be needed.
+ * Other privileges may be added by modules as necessary during
+ * initialisation.
+ */
+
+ illumos_priv_add(PRIV_FILE_WRITE, "init");
+
+ /*
+ * bhyve can work without proc_clock_highres so don't enforce that
+ * it is present.
+ */
+ if (priv_ismember(bhyve_priv_init, PRIV_PROC_CLOCK_HIGHRES))
+ illumos_priv_add_min(PRIV_PROC_CLOCK_HIGHRES, "init");
+ else
+ warnx("The 'proc_clock_highres' privilege is not available");
+}
+
+void
+illumos_priv_lock(void)
+{
+ VERIFY3S(pthread_equal(pthread_self(), priv_thread), !=, 0);
+
+ if (bhyve_priv_init == NULL) {
+ const char *msg = "attempted to re-lock privileges";
+ upanic(msg, strlen(msg));
+ }
+
+ priv_intersect(bhyve_priv_init, bhyve_priv_max);
+
+ if (priv_debug) {
+ DPRINTF((" + Locking privileges"));
+
+ illumos_priv_printset("min", bhyve_priv_min);
+ illumos_priv_printset("max", bhyve_priv_max);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, bhyve_priv_max) != 0) {
+ const char *fail = "failed to reduce permitted privileges";
+ upanic(fail, strlen(fail));
+ }
+
+ if (setppriv(PRIV_SET, PRIV_LIMIT, bhyve_priv_max) != 0) {
+ const char *fail = "failed to reduce limit privileges";
+ upanic(fail, strlen(fail));
+ }
+
+ illumos_priv_reduce();
+
+ priv_freeset(bhyve_priv_init);
+ bhyve_priv_init = NULL;
+}
diff --git a/usr/src/cmd/bhyve/privileges.h b/usr/src/cmd/bhyve/privileges.h
new file mode 100644
index 0000000000..e115c45164
--- /dev/null
+++ b/usr/src/cmd/bhyve/privileges.h
@@ -0,0 +1,28 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#ifndef _BHYVE_PRIVILEGES_H
+#define _BHYVE_PRIVILEGES_H
+
+#include <priv.h>
+#include <stdbool.h>
+
+void illumos_priv_init(void);
+void illumos_priv_lock(void);
+void illumos_priv_add(const char *, const char *);
+void illumos_priv_add_min(const char *, const char *);
+void illumos_priv_reduce(void);
+
+#endif /* _BHYVE_PRIVILEGES_H */
diff --git a/usr/src/lib/libm/Makefile.libm.com b/usr/src/lib/libm/Makefile.libm.com
index 5d404bd423..f282d4ee4d 100644
--- a/usr/src/lib/libm/Makefile.libm.com
+++ b/usr/src/lib/libm/Makefile.libm.com
@@ -52,6 +52,7 @@ sparc_CFLAGS += -Wa,-xarch=v8plus
CPPFLAGS += -I$(LIBMSRC)/C \
-I$(LIBMSRC)/$(LDBLDIR) -I$(LIBMDIR)/$(TARGET_ARCH)/src
+$(RELEASE_BUILD)CPPFLAGS += -DNDEBUG
# GCC needs __C99FEATURES__ such that the implementations of isunordered,
# isgreaterequal, islessequal, etc, exist. This is basically equivalent to
diff --git a/usr/src/lib/libm/common/C/__rem_pio2m.c b/usr/src/lib/libm/common/C/__rem_pio2m.c
index e9b4589e95..967f699252 100644
--- a/usr/src/lib/libm/common/C/__rem_pio2m.c
+++ b/usr/src/lib/libm/common/C/__rem_pio2m.c
@@ -44,7 +44,7 @@
* Here PI could as well be a machine value pi.
*
* Input parameters:
- * x[] The input value (must be positive) is broken into nx
+ * x[] The input value (must be positive) is broken into nx
* pieces of 24-bit integers in double precision format.
* x[i] will be the i-th 24 bit of x. The scaled exponent
* of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
@@ -77,7 +77,7 @@
*
* nx dimension of x[]
*
- * prec an interger indicating the precision:
+ * prec an interger indicating the precision:
* 0 24 bits (single)
* 1 53 bits (double)
* 2 64 bits (extended)
@@ -96,11 +96,11 @@
*
* Here is the description of some local variables:
*
- * jk jk+1 is the initial number of terms of ipio2[] needed
+ * jk jk+1 is the initial number of terms of ipio2[] needed
* in the computation. The recommended value is 3,4,4,
* 6 for single, double, extended,and quad.
*
- * jz local integer variable indicating the number of
+ * jz local integer variable indicating the number of
* terms of ipio2[] used.
*
* jx nx - 1
@@ -114,7 +114,7 @@
*
* jp jp+1 is the number of terms in pio2[] needed, jp = jk.
*
- * q[] double array with integral value, representing the
+ * q[] double array with integral value, representing the
* 24-bits chunk of the product of x and 2/pi.
*
* q0 the corresponding exponent of q[0]. Note that the
@@ -134,6 +134,7 @@
*
*/
+#include <assert.h>
#include "libm.h"
#if defined(__i386) && !defined(__amd64)
@@ -174,6 +175,7 @@ __rem_pio2m(double *x, double *y, int e0, int nx, int prec, const int *ipio2)
rp = __swapRP(fp_extended);
#endif
+ fq[0] = NAN; /* Make gcc happy */
/* initialize jk */
jp = jk = init_jk[prec];
@@ -326,6 +328,8 @@ recompute:
for (i = jz; i >= 0; i--)
fw += fq[i];
y[0] = (ih == 0)? fw : -fw;
+
+ assert(!isnan(fq[0]));
fw = fq[0] - fw;
for (i = 1; i <= jz; i++)
fw += fq[i];
diff --git a/usr/src/man/man4/bhyve_config.4 b/usr/src/man/man4/bhyve_config.4
index b3d4252a8c..b2d563cf8f 100644
--- a/usr/src/man/man4/bhyve_config.4
+++ b/usr/src/man/man4/bhyve_config.4
@@ -25,7 +25,7 @@
.\"
.\" Portions Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
.\"
-.Dd March 24, 2021
+.Dd May 6, 2021
.Dt BHYVE_CONFIG 4
.Os
.Sh NAME
@@ -147,8 +147,13 @@ If set to false, MSI interrupts are used instead.
.It Va config.dump Ta bool Ta false Ta
If this value is set to true, then
.Xr bhyve 1M
-will write all of its configuration variables to stdout and exit
-after it has finished parsing command line options.
+will write all of its configuration variables to
+.Dv stdout
+and exit after it has finished parsing command line options.
+.It Va privileges.debug Ta bool Ta false Ta
+Enable debug messages relating to privilege management.
+These messages are sent to
+.Dv stdout .
.El
.Ss x86-Specific Settings
.Bl -column "x86.vmexit_on_pause" "integer" "Default"
@@ -357,7 +362,7 @@ TCP address to listen on for remote connections.
The IP address must be given as a numeric address.
IPv6 addresses must be enclosed in square brackets and
support scoped identifiers as described in
-.Xr getaddrinfo 3socket .
+.Xr getaddrinfo 3SOCKET .
A bare port number may be given in which case the IPv4
localhost address is used.
.It Va unix Ta string Ta Ta
@@ -470,5 +475,5 @@ The path of a UNIX domain socket providing the host connection for the port.
.El
.Sh SEE ALSO
.Xr bhyve 1M ,
-.Xr strtoul 3c ,
-.Xr getaddrinfo 3socket
+.Xr strtoul 3C ,
+.Xr getaddrinfo 3SOCKET
diff --git a/usr/src/uts/common/os/exit.c b/usr/src/uts/common/os/exit.c
index 5563c0f4ab..46e588c926 100644
--- a/usr/src/uts/common/os/exit.c
+++ b/usr/src/uts/common/os/exit.c
@@ -23,6 +23,7 @@
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2018 Joyent, Inc.
* Copyright 2020 Oxide Computer Company
+ * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -178,6 +179,7 @@ restart_init(int what, int why)
kthread_t *t = curthread;
klwp_t *lwp = ttolwp(t);
proc_t *p = ttoproc(t);
+ proc_t *pp = p->p_zone->zone_zsched;
user_t *up = PTOU(p);
vnode_t *oldcd, *oldrd;
@@ -272,6 +274,11 @@ restart_init(int what, int why)
up->u_cwd = NULL;
}
+ /* Reset security flags */
+ mutex_enter(&pp->p_lock);
+ p->p_secflags = pp->p_secflags;
+ mutex_exit(&pp->p_lock);
+
mutex_exit(&p->p_lock);
if (oldrd != NULL)
@@ -279,6 +286,23 @@ restart_init(int what, int why)
if (oldcd != NULL)
VN_RELE(oldcd);
+ /*
+ * It's possible that a zone's init will have become privilege aware
+ * and modified privilege sets; reset them.
+ */
+ cred_t *oldcr, *newcr;
+
+ mutex_enter(&p->p_crlock);
+ oldcr = p->p_cred;
+ mutex_enter(&pp->p_crlock);
+ crhold(newcr = p->p_cred = pp->p_cred);
+ mutex_exit(&pp->p_crlock);
+ mutex_exit(&p->p_crlock);
+ crfree(oldcr);
+ /* Additional hold for the current thread - expected by crset() */
+ crhold(newcr);
+ crset(p, newcr);
+
/* Free the controlling tty. (freectty() always assumes curproc.) */
ASSERT(p == curproc);
(void) freectty(B_TRUE);
diff --git a/usr/src/uts/common/os/strsubr.c b/usr/src/uts/common/os/strsubr.c
index 1e18a0ce9e..9357e6a234 100644
--- a/usr/src/uts/common/os/strsubr.c
+++ b/usr/src/uts/common/os/strsubr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
@@ -3007,7 +3007,7 @@ strwaitbuf(size_t size, int pri)
* GETWAIT Check for read side errors, no M_READ
* WRITEWAIT Check for write side errors.
* NOINTR Do not return error if nonblocking or timeout.
- * STR_NOERROR Ignore all errors except STPLEX.
+ * STR_NOERROR Ignore all errors except STPLEX.
* STR_NOSIG Ignore/hold signals during the duration of the call.
* STR_PEEK Pass through the strgeterr().
*/
@@ -6631,9 +6631,9 @@ drain_syncq(syncq_t *sq)
*
* qdrain_syncq can be called (currently) from only one of two places:
* drain_syncq
- * putnext (or some variation of it).
+ * putnext (or some variation of it).
* and eventually
- * qwait(_sig)
+ * qwait(_sig)
*
* If called from drain_syncq, we found it in the list of queues needing
* service, so there is work to be done (or it wouldn't be in the list).
@@ -6653,8 +6653,8 @@ drain_syncq(syncq_t *sq)
*
* ASSUMES:
* One claim
- * QLOCK held
- * SQLOCK not held
+ * QLOCK held
+ * SQLOCK not held
* Will release QLOCK before returning
*/
void
@@ -7108,11 +7108,11 @@ static int
propagate_syncq(queue_t *qp)
{
mblk_t *bp, *head, *tail, *prev, *next;
- syncq_t *sq;
+ syncq_t *sq;
queue_t *nqp;
syncq_t *nsq;
boolean_t isdriver;
- int moved = 0;
+ int moved = 0;
uint16_t flags;
pri_t priority = curthread->t_pri;
#ifdef DEBUG
@@ -7145,7 +7145,7 @@ propagate_syncq(queue_t *qp)
/* debug macro */
SQ_PUTLOCKS_HELD(nsq);
#ifdef DEBUG
- func = (void (*)())nqp->q_qinfo->qi_putp;
+ func = (void (*)())(uintptr_t)nqp->q_qinfo->qi_putp;
#endif
}