summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Levon <john.levon@joyent.com>2018-06-13 22:54:04 +0000
committerJohn Levon <john.levon@joyent.com>2018-06-13 22:54:04 +0000
commit8118caaf6ac0df6a54351bfd800aea92a6ac3cca (patch)
tree63e49c5d6e729f04dfecc1927e6d154ef5241ff2
parentf48e1a4f1d835afe9a2607058270907434313e19 (diff)
downloadillumos-joyent-8118caaf6ac0df6a54351bfd800aea92a6ac3cca.tar.gz
OS-6967 LDT still not happy under KPTI
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Alex Wilson <alex.wilson@joyent.com> Approved by: Jerry Jelinek <jerry.jelinek@joyent.com> Approved by: Alex Wilson <alex.wilson@joyent.com>
-rw-r--r--usr/src/pkg/manifests/system-test-ostest.mf4
-rw-r--r--usr/src/test/os-tests/runfiles/default.run7
-rw-r--r--usr/src/test/os-tests/tests/Makefile7
-rw-r--r--usr/src/test/os-tests/tests/i386/Makefile46
-rwxr-xr-xusr/src/test/os-tests/tests/i386/ldt.c80
-rw-r--r--usr/src/test/test-runner/cmd/run7
-rw-r--r--usr/src/uts/common/sys/proc.h5
-rw-r--r--usr/src/uts/i86pc/ml/offsets.in2
-rw-r--r--usr/src/uts/i86pc/os/mlsetup.c5
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c6
-rw-r--r--usr/src/uts/intel/ia32/os/sysi86.c121
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h4
12 files changed, 203 insertions, 91 deletions
diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf
index fc56278749..c2fda43f31 100644
--- a/usr/src/pkg/manifests/system-test-ostest.mf
+++ b/usr/src/pkg/manifests/system-test-ostest.mf
@@ -12,7 +12,7 @@
#
# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
# Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
-# Copyright 2017 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
#
set name=pkg.fmri value=pkg:/system/test/ostest@$(PKGVERS)
@@ -26,6 +26,7 @@ dir path=opt/os-tests/bin
dir path=opt/os-tests/runfiles
dir path=opt/os-tests/tests
dir path=opt/os-tests/tests/file-locking
+$(i386_ONLY)dir path=opt/os-tests/tests/i386
dir path=opt/os-tests/tests/pf_key
dir path=opt/os-tests/tests/sdevfs
dir path=opt/os-tests/tests/secflags
@@ -40,6 +41,7 @@ file path=opt/os-tests/tests/file-locking/acquire-lock.32 mode=0555
file path=opt/os-tests/tests/file-locking/acquire-lock.64 mode=0555
file path=opt/os-tests/tests/file-locking/runtests.32 mode=0555
file path=opt/os-tests/tests/file-locking/runtests.64 mode=0555
+$(i386_ONLY)file path=opt/os-tests/tests/i386/ldt mode=0555
file path=opt/os-tests/tests/pf_key/acquire-compare mode=0555
file path=opt/os-tests/tests/pf_key/acquire-spray mode=0555
file path=opt/os-tests/tests/pf_key/eacq-enabler mode=0555
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run
index c52364877e..fb79a8de19 100644
--- a/usr/src/test/os-tests/runfiles/default.run
+++ b/usr/src/test/os-tests/runfiles/default.run
@@ -11,7 +11,7 @@
#
# Copyright (c) 2012 by Delphix. All rights reserved.
-# Copyright 2017 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
#
[DEFAULT]
@@ -73,3 +73,8 @@ tests = ['acquire-compare', 'acquire-spray']
[/opt/os-tests/tests/OS-6097.32]
[/opt/os-tests/tests/OS-6097.64]
+
+[/opt/os-tests/tests/i386]
+user = root
+arch = i86pc
+tests = ['ldt']
diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile
index 9424fa157e..34ad160684 100644
--- a/usr/src/test/os-tests/tests/Makefile
+++ b/usr/src/test/os-tests/tests/Makefile
@@ -11,11 +11,14 @@
#
# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
-# Copyright 2017 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
#
+
+SUBDIRS_i386 = i386
+
SUBDIRS = poll secflags sigqueue spoof-ras sdevfs sockfs stress timer tmpfs \
- file-locking pf_key
+ file-locking pf_key $(SUBDIRS_$(MACH))
PROGS = \
OS-6097
diff --git a/usr/src/test/os-tests/tests/i386/Makefile b/usr/src/test/os-tests/tests/i386/Makefile
new file mode 100644
index 0000000000..6c1f480b88
--- /dev/null
+++ b/usr/src/test/os-tests/tests/i386/Makefile
@@ -0,0 +1,46 @@
+#
+# 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 2018 Joyent, Inc.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG += ldt
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests/i386
+
+CSTD = $(CSTD_GNU99)
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROG)
+
+install: all $(CMDS)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/os-tests/tests/i386/ldt.c b/usr/src/test/os-tests/tests/i386/ldt.c
new file mode 100755
index 0000000000..dbe816b19c
--- /dev/null
+++ b/usr/src/test/os-tests/tests/i386/ldt.c
@@ -0,0 +1,80 @@
+/*
+ * 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 2018 Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/sysi86.h>
+#include <sys/segments.h>
+#include <sys/segment.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <err.h>
+
+char foo[4096];
+
+static void *
+donothing(void *nothing)
+{
+ sleep(5);
+ return (NULL);
+}
+
+int
+main(void)
+{
+ pthread_t tid;
+
+ /*
+ * This first is similar to what sbcl does in some variants. Note the
+ * SDT_MEMRW (not SDT_MEMRWA) so we check that the kernel is forcing the
+ * 'accessed' bit too.
+ */
+ int sel = SEL_LDT(7);
+
+ struct ssd ssd = { sel, (unsigned long)&foo, 4096,
+ SDT_MEMRW | (SEL_UPL << 5) | (1 << 7), 0x4 };
+
+ if (sysi86(SI86DSCR, &ssd) < 0)
+ err(-1, "failed to setup segment");
+
+ __asm__ __volatile__("mov %0, %%fs" : : "r" (sel));
+
+ ssd.acc1 = 0;
+
+ if (sysi86(SI86DSCR, &ssd) == 0)
+ errx(-1, "removed in-use segment?");
+
+ __asm__ __volatile__("mov %0, %%fs" : : "r" (0));
+
+ if (sysi86(SI86DSCR, &ssd) < 0)
+ err(-1, "failed to remove segment");
+
+ for (int i = 0; i < MAXNLDT; i++) {
+ ssd.sel = SEL_LDT(i);
+ (void) sysi86(SI86DSCR, &ssd);
+ }
+
+ for (int i = 0; i < 10; i++)
+ pthread_create(&tid, NULL, donothing, NULL);
+
+ if (forkall() == 0) {
+ sleep(2);
+ _exit(0);
+ }
+
+ sleep(6);
+ return (0);
+}
diff --git a/usr/src/test/test-runner/cmd/run b/usr/src/test/test-runner/cmd/run
index 1e0d90c563..6b76686fe0 100644
--- a/usr/src/test/test-runner/cmd/run
+++ b/usr/src/test/test-runner/cmd/run
@@ -12,7 +12,7 @@
#
#
-# Copyright 2017 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
# Copyright (c) 2017, Chris Fraire <cfraire@me.com>.
#
@@ -20,6 +20,7 @@
import ConfigParser
import os
import logging
+import platform
from logging.handlers import WatchedFileHandler
from datetime import datetime
from optparse import OptionParser
@@ -588,6 +589,10 @@ class TestRun(object):
self.outputdir = os.path.join(self.outputdir, self.timestamp)
for section in config.sections():
+ if ('arch' in config.options(section) and
+ platform.machine() != config.get(section, 'arch')):
+ continue
+
if 'tests' in config.options(section):
testgroup = TestGroup(section)
for prop in TestGroup.props:
diff --git a/usr/src/uts/common/sys/proc.h b/usr/src/uts/common/sys/proc.h
index a7fff4e5ab..7d2209132d 100644
--- a/usr/src/uts/common/sys/proc.h
+++ b/usr/src/uts/common/sys/proc.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2018 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -308,7 +308,8 @@ typedef struct proc {
*/
kmutex_t p_ldtlock; /* protects the following fields */
user_desc_t *p_ldt; /* Pointer to private LDT */
- system_desc_t p_ldt_desc; /* segment descriptor for private LDT */
+ uint64_t p_unused1; /* no longer used */
+ uint64_t p_unused2; /* no longer used */
ushort_t p_ldtlimit; /* highest selector used */
#endif
size_t p_swrss; /* resident set size before last swap */
diff --git a/usr/src/uts/i86pc/ml/offsets.in b/usr/src/uts/i86pc/ml/offsets.in
index d4534662b3..8390ba0fc9 100644
--- a/usr/src/uts/i86pc/ml/offsets.in
+++ b/usr/src/uts/i86pc/ml/offsets.in
@@ -75,8 +75,6 @@ proc PROCSIZE
p_as
p_lockp
p_user
- p_ldt
- p_ldt_desc
p_model
p_pctx
p_agenttp
diff --git a/usr/src/uts/i86pc/os/mlsetup.c b/usr/src/uts/i86pc/os/mlsetup.c
index 09bf07848c..601c6937fd 100644
--- a/usr/src/uts/i86pc/os/mlsetup.c
+++ b/usr/src/uts/i86pc/os/mlsetup.c
@@ -362,11 +362,6 @@ mlsetup(struct regs *rp)
CPU->cpu_pri = 12; /* initial PIL for the boot CPU */
/*
- * The kernel doesn't use LDTs unless a process explicitly requests one.
- */
- p0.p_ldt_desc = null_sdesc;
-
- /*
* Initialize thread/cpu microstate accounting
*/
init_mstate(&t0, LMS_SYSTEM);
diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c
index f1a243343a..b1100377eb 100644
--- a/usr/src/uts/i86pc/os/mp_startup.c
+++ b/usr/src/uts/i86pc/os/mp_startup.c
@@ -2054,9 +2054,8 @@ mp_cpu_faulted_exit(struct cpu *cp)
* syscall features.
*/
-/*ARGSUSED*/
void
-cpu_fast_syscall_disable(void *arg)
+cpu_fast_syscall_disable(void)
{
if (is_x86_feature(x86_featureset, X86FSET_MSR) &&
is_x86_feature(x86_featureset, X86FSET_SEP))
@@ -2066,9 +2065,8 @@ cpu_fast_syscall_disable(void *arg)
cpu_asysc_disable();
}
-/*ARGSUSED*/
void
-cpu_fast_syscall_enable(void *arg)
+cpu_fast_syscall_enable(void)
{
if (is_x86_feature(x86_featureset, X86FSET_MSR) &&
is_x86_feature(x86_featureset, X86FSET_SEP))
diff --git a/usr/src/uts/intel/ia32/os/sysi86.c b/usr/src/uts/intel/ia32/os/sysi86.c
index e3f4e2608c..bdb66e3e1f 100644
--- a/usr/src/uts/intel/ia32/os/sysi86.c
+++ b/usr/src/uts/intel/ia32/os/sysi86.c
@@ -348,8 +348,7 @@ static void
ldt_load(void)
{
#if defined(__xpv)
- xen_set_ldt(get_ssd_base(&curproc->p_ldt_desc),
- curproc->p_ldtlimit + 1);
+ xen_set_ldt(curproc->p_ldt, curproc->p_ldtlimit + 1);
#else
size_t len;
system_desc_t desc;
@@ -415,7 +414,7 @@ ldt_savectx(proc_t *p)
#endif
ldt_unload();
- cpu_fast_syscall_enable(NULL);
+ cpu_fast_syscall_enable();
}
static void
@@ -425,30 +424,34 @@ ldt_restorectx(proc_t *p)
ASSERT(p == curproc);
ldt_load();
- cpu_fast_syscall_disable(NULL);
+ cpu_fast_syscall_disable();
}
/*
- * When a process with a private LDT execs, fast syscalls must be enabled for
- * the new process image.
+ * At exec time, we need to clear up our LDT context and re-enable fast syscalls
+ * for the new process image.
+ *
+ * The same is true for the other case, where we have:
+ *
+ * proc_exit()
+ * ->exitpctx()->ldt_savectx()
+ * ->freepctx()->ldt_freectx()
+ *
+ * Because pre-emption is not prevented between the two callbacks, we could have
+ * come off CPU, and brought back LDT context when coming back on CPU via
+ * ldt_restorectx().
*/
/* ARGSUSED */
static void
ldt_freectx(proc_t *p, int isexec)
{
- ASSERT(p->p_ldt);
-
- if (isexec) {
- kpreempt_disable();
- cpu_fast_syscall_enable(NULL);
- kpreempt_enable();
- }
+ ASSERT(p->p_ldt != NULL);
+ ASSERT(p == curproc);
- /*
- * ldt_free() will free the memory used by the private LDT, reset the
- * process's descriptor, and re-program the LDTR.
- */
+ kpreempt_disable();
ldt_free(p);
+ cpu_fast_syscall_enable();
+ kpreempt_enable();
}
/*
@@ -500,10 +503,10 @@ ldt_installctx(proc_t *p, proc_t *cp)
int
setdscr(struct ssd *ssd)
{
- ushort_t seli; /* selector index */
+ ushort_t seli; /* selector index */
user_desc_t *ldp; /* descriptor pointer */
user_desc_t ndesc; /* new descriptor */
- proc_t *pp = ttoproc(curthread);
+ proc_t *pp = curproc;
int rc = 0;
/*
@@ -544,11 +547,12 @@ setdscr(struct ssd *ssd)
*/
kpreempt_disable();
ldt_installctx(pp, NULL);
- cpu_fast_syscall_disable(NULL);
+ cpu_fast_syscall_disable();
ASSERT(curthread->t_post_sys != 0);
kpreempt_enable();
} else if (seli > pp->p_ldtlimit) {
+ ASSERT(pp->p_pctx != NULL);
/*
* Increase size of ldt to include seli.
@@ -650,10 +654,14 @@ setdscr(struct ssd *ssd)
}
/*
- * If acc1 is zero, clear the descriptor (including the 'present' bit)
+ * If acc1 is zero, clear the descriptor (including the 'present' bit).
+ * Make sure we update the CPU-private copy of the LDT.
*/
if (ssd->acc1 == 0) {
rc = ldt_update_segd(ldp, &null_udesc);
+ kpreempt_disable();
+ ldt_load();
+ kpreempt_enable();
mutex_exit(&pp->p_ldtlock);
return (rc);
}
@@ -667,7 +675,6 @@ setdscr(struct ssd *ssd)
return (EINVAL);
}
-#if defined(__amd64)
/*
* Do not allow 32-bit applications to create 64-bit mode code
* segments.
@@ -677,50 +684,34 @@ setdscr(struct ssd *ssd)
mutex_exit(&pp->p_ldtlock);
return (EINVAL);
}
-#endif /* __amd64 */
/*
- * Set up a code or data user segment descriptor.
+ * Set up a code or data user segment descriptor, making sure to update
+ * the CPU-private copy of the LDT.
*/
if (SI86SSD_ISUSEG(ssd)) {
ssd_to_usd(ssd, &ndesc);
rc = ldt_update_segd(ldp, &ndesc);
+ kpreempt_disable();
+ ldt_load();
+ kpreempt_enable();
mutex_exit(&pp->p_ldtlock);
return (rc);
}
-#if defined(__i386)
- /*
- * Allow a call gate only if the destination is in the LDT
- * and the system is running in 32-bit legacy mode.
- *
- * In long mode 32-bit call gates are redefined as 64-bit call
- * gates and the hw enforces that the target code selector
- * of the call gate must be 64-bit selector. A #gp fault is
- * generated if otherwise. Since we do not allow 32-bit processes
- * to switch themselves to 64-bits we never allow call gates
- * on 64-bit system system.
- */
- if (SI86SSD_TYPE(ssd) == SDT_SYSCGT && SELISLDT(ssd->ls)) {
-
-
- ssd_to_sgd(ssd, (gate_desc_t *)&ndesc);
- rc = ldt_update_segd(ldp, &ndesc);
- mutex_exit(&pp->p_ldtlock);
- return (rc);
- }
-#endif /* __i386 */
-
mutex_exit(&pp->p_ldtlock);
return (EINVAL);
}
/*
- * Allocate new LDT for process just large enough to contain seli.
- * Note we allocate and grow LDT in PAGESIZE chunks. We do this
- * to simplify the implementation and because on the hypervisor it's
- * required, since the LDT must live on pages that have PROT_WRITE
- * removed and which are given to the hypervisor.
+ * Allocate new LDT for process just large enough to contain seli. Note we
+ * allocate and grow LDT in PAGESIZE chunks. We do this to simplify the
+ * implementation and because on the hypervisor it's required, since the LDT
+ * must live on pages that have PROT_WRITE removed and which are given to the
+ * hypervisor.
+ *
+ * Note that we don't actually load the LDT into the current CPU here: it's done
+ * later by our caller.
*/
static void
ldt_alloc(proc_t *pp, uint_t seli)
@@ -751,13 +742,6 @@ ldt_alloc(proc_t *pp, uint_t seli)
pp->p_ldt = ldt;
pp->p_ldtlimit = nsels - 1;
- set_syssegd(&pp->p_ldt_desc, ldt, ldtsz - 1, SDT_SYSLDT, SEL_KPL);
-
- if (pp == curproc) {
- kpreempt_disable();
- ldt_load();
- kpreempt_enable();
- }
}
static void
@@ -776,7 +760,6 @@ ldt_free(proc_t *pp)
pp->p_ldt = NULL;
pp->p_ldtlimit = 0;
- pp->p_ldt_desc = null_sdesc;
mutex_exit(&pp->p_ldtlock);
if (pp == curproc) {
@@ -841,6 +824,14 @@ ldt_dup(proc_t *pp, proc_t *cp)
}
+/*
+ * Note that we don't actually load the LDT into the current CPU here: it's done
+ * later by our caller - unless we take an error. This works out because
+ * ldt_load() does a copy of ->p_ldt instead of directly loading it into the GDT
+ * (and therefore can't be using the freed old LDT), and by definition if the
+ * new entry didn't pass validation, then the proc shouldn't be referencing an
+ * entry in the extended region.
+ */
static void
ldt_grow(proc_t *pp, uint_t seli)
{
@@ -891,17 +882,5 @@ ldt_grow(proc_t *pp, uint_t seli)
pp->p_ldt = nldt;
pp->p_ldtlimit = nsels - 1;
- /*
- * write new ldt segment descriptor.
- */
- set_syssegd(&pp->p_ldt_desc, nldt, nldtsz - 1, SDT_SYSLDT, SEL_KPL);
-
- /*
- * load the new ldt.
- */
- kpreempt_disable();
- ldt_load();
- kpreempt_enable();
-
kmem_free(oldt, oldtsz);
}
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index 499d254608..bbb7d4fa63 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -787,8 +787,8 @@ extern void setcr4(ulong_t);
extern void mtrr_sync(void);
-extern void cpu_fast_syscall_enable(void *);
-extern void cpu_fast_syscall_disable(void *);
+extern void cpu_fast_syscall_enable(void);
+extern void cpu_fast_syscall_disable(void);
struct cpu;