diff options
author | John Levon <john.levon@joyent.com> | 2018-07-30 08:39:37 +0000 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2018-07-30 08:52:35 +0000 |
commit | 1d0338f3f33eec2ed45ec5a6cae30c399a3ef769 (patch) | |
tree | 17d963f3fc9f20d729955159bc70802e40fbbd14 | |
parent | 5a38f11740e61db1a5560cc3bb03bebdbd684845 (diff) | |
download | illumos-joyent-1d0338f3f33eec2ed45ec5a6cae30c399a3ef769.tar.gz |
OS-7090 GDT limit reset to 0xffff
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r-- | usr/src/cmd/mdb/i86pc/modules/unix/unix.c | 12 | ||||
-rw-r--r-- | usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h | 2 | ||||
-rw-r--r-- | usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s | 47 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-test-ostest.mf | 1 | ||||
-rw-r--r-- | usr/src/test/os-tests/runfiles/default.run | 2 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/i386/Makefile | 15 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/i386/badseg.c | 146 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/intel/vmx.c | 2 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/vmm.c | 30 | ||||
-rw-r--r-- | usr/src/uts/intel/ia32/os/desctbls.c | 22 | ||||
-rw-r--r-- | usr/src/uts/intel/sys/x86_archext.h | 4 |
11 files changed, 216 insertions, 67 deletions
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c index 224cfb4a18..a66ecbe8a3 100644 --- a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c +++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c @@ -961,9 +961,11 @@ x86_featureset_cmd(uintptr_t addr, uint_t flags, int argc, #ifdef _KMDB /* ARGSUSED */ static int -crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { ulong_t cr0, cr2, cr3, cr4; + desctbr_t gdtr; + static const mdb_bitmask_t cr0_flag_bits[] = { { "PE", CR0_PE, CR0_PE }, { "MP", CR0_MP, CR0_MP }, @@ -1010,6 +1012,9 @@ crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) cr2 = kmdb_unix_getcr2(); cr3 = kmdb_unix_getcr3(); cr4 = kmdb_unix_getcr4(); + + kmdb_unix_getgdtr(&gdtr); + mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits); mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2); @@ -1023,6 +1028,9 @@ crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits); + mdb_printf("%%gdtr.base = 0x%lx, %%gdtr.limit = 0x%hx\n", + gdtr.dtr_base, gdtr.dtr_limit); + return (DCMD_OK); } #endif @@ -1054,7 +1062,7 @@ static const mdb_dcmd_t dcmds[] = { { "x86_featureset", NULL, "dump the x86_featureset vector", x86_featureset_cmd }, #ifdef _KMDB - { "crregs", NULL, "dump control registers", crregs_dcmd }, + { "sysregs", NULL, "dump system registers", sysregs_dcmd }, #endif { NULL } }; diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h index 4c155373ea..0c9d2e68ec 100644 --- a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h +++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h @@ -21,6 +21,7 @@ */ #include <sys/types.h> +#include <sys/segments.h> #ifdef __cplusplus extern "C" { @@ -30,6 +31,7 @@ extern ulong_t kmdb_unix_getcr0(void); extern ulong_t kmdb_unix_getcr2(void); extern ulong_t kmdb_unix_getcr3(void); extern ulong_t kmdb_unix_getcr4(void); +extern void kmdb_unix_getgdtr(desctbr_t *); #ifdef __cplusplus } diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s index 38ddf5cf44..5984a12132 100644 --- a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s +++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s @@ -13,35 +13,20 @@ * Copyright 2018 Joyent, Inc. */ -#if !defined(__lint) - .file "unix_sup.s" -#endif /* __lint */ - /* * Support routines for the unix kmdb module */ -#include <sys/asm_linkage.h> - #if defined(__lint) #include <sys/types.h> -ulong_t -kmdb_unix_getcr0(void) -{ return (0); } - -ulong_t -kmdb_unix_getcr3(void) -{ return (0); } +#else -ulong_t -kmdb_unix_getcr4(void) -{ return (0); } +#include <sys/asm_linkage.h> -#else /* __lint */ + .file "unix_sup.s" -#if defined(__amd64) ENTRY(kmdb_unix_getcr0) movq %cr0, %rax ret @@ -62,27 +47,9 @@ kmdb_unix_getcr4(void) ret SET_SIZE(kmdb_unix_getcr4) -#elif defined (__i386) - ENTRY(kmdb_unix_getcr0) - movl %cr0, %eax - ret - SET_SIZE(kmdb_unix_getcr0) - - ENTRY(kmdb_unix_getcr2) - movl %cr2, %eax - ret - SET_SIZE(kmdb_unix_getcr2) - - ENTRY(kmdb_unix_getcr3) - movl %cr3, %eax + ENTRY(kmdb_unix_getgdtr) + sgdt (%rdi) ret - SET_SIZE(kmdb_unix_getcr3) - - ENTRY(kmdb_unix_getcr4) - movl %cr4, %eax - ret - SET_SIZE(kmdb_unix_getcr4) - -#endif /* __i386 */ + SET_SIZE(kmdb_unix_getgdtr) -#endif /* __lint */ +#endif /* !__lint */ diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf index c2fda43f31..70e9d378c1 100644 --- a/usr/src/pkg/manifests/system-test-ostest.mf +++ b/usr/src/pkg/manifests/system-test-ostest.mf @@ -41,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/badseg 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 diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run index fb79a8de19..974829b1f6 100644 --- a/usr/src/test/os-tests/runfiles/default.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -77,4 +77,4 @@ tests = ['acquire-compare', 'acquire-spray'] [/opt/os-tests/tests/i386] user = root arch = i86pc -tests = ['ldt'] +tests = ['ldt', 'badseg'] diff --git a/usr/src/test/os-tests/tests/i386/Makefile b/usr/src/test/os-tests/tests/i386/Makefile index 6c1f480b88..4933cf6e02 100644 --- a/usr/src/test/os-tests/tests/i386/Makefile +++ b/usr/src/test/os-tests/tests/i386/Makefile @@ -16,28 +16,29 @@ include $(SRC)/cmd/Makefile.cmd include $(SRC)/test/Makefile.com -PROG += ldt +PROGS += ldt badseg ROOTOPTPKG = $(ROOT)/opt/os-tests TESTDIR = $(ROOTOPTPKG)/tests/i386 +ROOTOPTPROGS = $(PROGS:%=$(TESTDIR)/%) CSTD = $(CSTD_GNU99) -CMDS = $(PROG:%=$(TESTDIR)/%) -$(CMDS) := FILEMODE = 0555 +# for badseg +COPTFLAG = -all: $(PROG) +all: $(PROGS) -install: all $(CMDS) +install: all $(ROOTOPTPROGS) lint: clobber: clean - -$(RM) $(PROG) + -$(RM) $(PROGS) clean: -$(CMDS): $(TESTDIR) $(PROG) +$(ROOTOPTPROGS): $(TESTDIR) $(PROGS) $(TESTDIR): $(INS.dir) diff --git a/usr/src/test/os-tests/tests/i386/badseg.c b/usr/src/test/os-tests/tests/i386/badseg.c new file mode 100644 index 0000000000..6bf4e0260f --- /dev/null +++ b/usr/src/test/os-tests/tests/i386/badseg.c @@ -0,0 +1,146 @@ +/* + * 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 <stdlib.h> +#include <ucontext.h> +#include <sys/wait.h> +#include <unistd.h> +#include <sys/regset.h> + +/* + * Load a bunch of bad selectors into the seg regs: this will typically cause + * the child process to core dump, but it shouldn't panic the kernel... + * + * It's especially interesting to run this on CPU0. + */ + +unsigned short selector; + +static void badds(void) +{ + __asm__ volatile("movw %0, %%ds" : : "r" (selector)); +} + +static void bades(void) +{ + __asm__ volatile("movw %0, %%es" : : "r" (selector)); +} + +static void badfs(void) +{ + __asm__ volatile("movw %0, %%fs" : : "r" (selector)); +} + +static void badgs(void) +{ + __asm__ volatile("movw %0, %%gs" : : "r" (selector)); +} + +static void badss(void) +{ + __asm__ volatile("movw %0, %%ss" : : "r" (selector)); +} + +static void +resetseg(uint_t seg) +{ + ucontext_t ucp; + int done = 0; + + int rc = getcontext(&ucp); + if (done) { + rc = getcontext(&ucp); + return; + } + + done = 1; + ucp.uc_mcontext.gregs[seg] = selector; + setcontext(&ucp); + abort(); +} + +static void +resetcs(void) +{ + return (resetseg(CS)); +} + +static void +resetds(void) +{ + return (resetseg(DS)); +} + +static void +resetes(void) +{ + return (resetseg(ES)); +} + +static void +resetfs(void) +{ + return (resetseg(FS)); +} + +static void +resetgs(void) +{ + return (resetseg(GS)); +} + +static void +resetss(void) +{ + return (resetseg(SS)); +} + +static void +inchild(void (*func)()) +{ + pid_t pid; + + switch ((pid = fork())) { + case 0: + func(); + exit(0); + case -1: + exit(1); + default: + (void) waitpid(pid, NULL, 0); + return; + } + +} + +int +main(int argc, char *argv[]) +{ + for (selector = 0; selector < 8194; selector++) { + inchild(resetcs); + inchild(resetds); + inchild(resetes); + inchild(resetfs); + inchild(resetgs); + inchild(resetss); + inchild(badds); + inchild(bades); + inchild(badfs); + inchild(badgs); + inchild(badss); + } + + exit(0); +} diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx.c b/usr/src/uts/i86pc/io/vmm/intel/vmx.c index eaad8864c2..9ad232a612 100644 --- a/usr/src/uts/i86pc/io/vmm/intel/vmx.c +++ b/usr/src/uts/i86pc/io/vmm/intel/vmx.c @@ -3942,6 +3942,8 @@ vmx_savectx(void *arg, int vcpu) VERIFY3U(vmclear(vmcs), ==, 0); vmx_msr_guest_exit(vmx, vcpu); } + + reset_gdtr_limit(); } static void diff --git a/usr/src/uts/i86pc/io/vmm/vmm.c b/usr/src/uts/i86pc/io/vmm/vmm.c index a4b669ab81..bcb6b77cea 100644 --- a/usr/src/uts/i86pc/io/vmm/vmm.c +++ b/usr/src/uts/i86pc/io/vmm/vmm.c @@ -1932,7 +1932,7 @@ vm_localize_resources(struct vm *vm, struct vcpu *vcpu) vcpu->lastloccpu = curcpu; } -void +static void vmm_savectx(void *arg) { vm_thread_ctx_t *vtc = arg; @@ -1955,7 +1955,7 @@ vmm_savectx(void *arg) } } -void +static void vmm_restorectx(void *arg) { vm_thread_ctx_t *vtc = arg; @@ -1986,6 +1986,15 @@ vmm_restorectx(void *arg) } +/* + * If we're in removectx(), we might still have state to tidy up. + */ +static void +vmm_freectx(void *arg, int isexec) +{ + vmm_savectx(arg); +} + #endif /* __FreeBSD */ @@ -2030,7 +2039,7 @@ vm_run(struct vm *vm, struct vm_run *vmrun) vtc.vtc_status = 0; installctx(curthread, &vtc, vmm_savectx, vmm_restorectx, NULL, NULL, - NULL, NULL); + NULL, vmm_freectx); #endif restart: @@ -2147,21 +2156,8 @@ restart: goto restart; #ifndef __FreeBSD__ - /* - * Before returning to userspace, explicitly restore the host FPU state - * (saving the guest state). This is done with kpreempt disabled to - * ensure it is not interrupted, potentially confusing the soon-to-be - * removed savectx/restorectx handlers. - */ - kpreempt_disable(); - if ((vtc.vtc_status & VTCS_FPU_RESTORED) != 0) { - save_guest_fpustate(vcpu); - vtc.vtc_status &= ~VTCS_FPU_RESTORED; - } - kpreempt_enable(); - removectx(curthread, &vtc, vmm_savectx, vmm_restorectx, NULL, NULL, - NULL, NULL); + NULL, vmm_freectx); #endif VCPU_CTR2(vm, vcpuid, "retu %d/%d", error, vme->exitcode); diff --git a/usr/src/uts/intel/ia32/os/desctbls.c b/usr/src/uts/intel/ia32/os/desctbls.c index 66b14377a6..8e0a4edd61 100644 --- a/usr/src/uts/intel/ia32/os/desctbls.c +++ b/usr/src/uts/intel/ia32/os/desctbls.c @@ -1304,6 +1304,28 @@ init_desctbls(void) #endif /* __xpv */ +#ifndef __xpv +/* + * As per Intel Vol 3 27.5.2, the GDTR limit is reset to 64Kb on a VM exit, so + * we have to manually fix it up ourselves. + * + * The caller may still need to make sure that it can't go off-CPU with the + * incorrect limit, before calling this (such as disabling pre-emption). + */ +void +reset_gdtr_limit(void) +{ + ulong_t flags = intr_clear(); + desctbr_t gdtr; + + rd_gdtr(&gdtr); + gdtr.dtr_limit = (sizeof (user_desc_t) * NGDT) - 1; + wr_gdtr(&gdtr); + + intr_restore(flags); +} +#endif /* __xpv */ + /* * In the early kernel, we need to set up a simple GDT to run on. * diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h index 07f88edd01..c6d696dc6e 100644 --- a/usr/src/uts/intel/sys/x86_archext.h +++ b/usr/src/uts/intel/sys/x86_archext.h @@ -961,6 +961,10 @@ extern void enable_pcid(void); extern void xsave_setup_msr(struct cpu *); +#if !defined(__xpv) +extern void reset_gdtr_limit(void); +#endif + /* * Hypervisor signatures */ |