diff options
author | Dan McDonald <danmcd@joyent.com> | 2021-05-25 14:08:27 -0400 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2021-05-25 14:08:27 -0400 |
commit | f390f85acaffd7dd53796db7f94f4df9523ed09c (patch) | |
tree | 54a128a5b3414b8f1c19455e0aa4ecb05d72ceb3 /usr/src | |
parent | 6a115942cd5340ddb10baaa726ec26d5f707e7fb (diff) | |
parent | 2576a450861a4a608f6bfabf01759987ff4ad97e (diff) | |
download | illumos-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.master | 1 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/Makefile | 2 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/bhyverun.c | 11 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/privileges.c | 191 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/privileges.h | 28 | ||||
-rw-r--r-- | usr/src/lib/libm/Makefile.libm.com | 1 | ||||
-rw-r--r-- | usr/src/lib/libm/common/C/__rem_pio2m.c | 14 | ||||
-rw-r--r-- | usr/src/man/man4/bhyve_config.4 | 17 | ||||
-rw-r--r-- | usr/src/uts/common/os/exit.c | 24 | ||||
-rw-r--r-- | usr/src/uts/common/os/strsubr.c | 18 |
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 } |