Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-8]: src/sys Pull up following revision(s) (requested by maxv):



details:   https://anonhg.NetBSD.org/src/rev/9bdeb15ad991
branches:  netbsd-8
changeset: 852322:9bdeb15ad991
user:      martin <martin%NetBSD.org@localhost>
date:      Fri Apr 05 07:48:05 2019 +0000

description:
Pull up following revision(s) (requested by maxv):

        sys/arch/amd64/amd64/netbsd32_machdep.c: revision 1.120
        sys/compat/linux/arch/amd64/linux_machdep.c: revision 1.57
        sys/compat/linux32/arch/amd64/linux32_machdep.c: revision 1.44
        sys/arch/amd64/amd64/machdep.c: revision 1.328
        sys/arch/amd64/amd64/machdep.c: revision 1.329

Fix a tiny race in setregs and linux_setregs. Between the moment we set
pcb_flags to zero, and the moment cpu_segregs64_zero resets pcb_gs, we may
be preempted.

If this happens, and if the calling LWP was a 32bit thread, when switching
back to that LWP, the context switcher sees that PCB_COMPAT32 is not set in
pcb_flags and tries to perform a 64bit context switch; but pcb_gs contains
a 32bit GDT descriptor, and not a 64bit GS.base value. The wrmsr therefore
faults because the value is non-canonical, and this fault is fatal.

Rearrange the code so that the update of pcb_flags and pcb_gs/pcb_fs is non
interruptible. This fixes the problem, tested with a reproducer (which
therefore doesn't work anymore).

Likely fixes PR/53993.

Disable preemption when setting PCB_COMPAT32, to prevent a context switch
before cpu_fsgs_reload() finishes, otherwise we write garbage in the GDT.

On NetBSD-current it is harmless, however in NetBSD-8 it might cause
panics, because NetBSD-8 uses the old SegRegs model and under this model
we reload %fs and %gs during switches.

diffstat:

 sys/arch/amd64/amd64/machdep.c                  |  12 +++++++-----
 sys/arch/amd64/amd64/netbsd32_machdep.c         |  16 +++++++++-------
 sys/compat/linux/arch/amd64/linux_machdep.c     |  11 ++++++-----
 sys/compat/linux32/arch/amd64/linux32_machdep.c |  14 ++++++++------
 4 files changed, 30 insertions(+), 23 deletions(-)

diffs (179 lines):

diff -r 223ec6a3ad99 -r 9bdeb15ad991 sys/arch/amd64/amd64/machdep.c
--- a/sys/arch/amd64/amd64/machdep.c    Mon Apr 01 12:36:44 2019 +0000
+++ b/sys/arch/amd64/amd64/machdep.c    Fri Apr 05 07:48:05 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: machdep.c,v 1.255.6.8 2018/11/29 08:51:01 martin Exp $ */
+/*     $NetBSD: machdep.c,v 1.255.6.9 2019/04/05 07:48:05 martin Exp $ */
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -111,7 +111,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.255.6.8 2018/11/29 08:51:01 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.255.6.9 2019/04/05 07:48:05 martin Exp $");
 
 /* #define XENDEBUG_LOW  */
 
@@ -1350,20 +1350,22 @@
 
        fpu_save_area_clear(l, pack->ep_osversion >= 699002600
            ? __NetBSD_NPXCW__ : __NetBSD_COMPAT_NPXCW__);
-       pcb->pcb_flags = 0;
+
        if (pcb->pcb_dbregs != NULL) {
                pool_put(&x86_dbregspl, pcb->pcb_dbregs);
                pcb->pcb_dbregs = NULL;
        }
 
+       kpreempt_disable();
+       pcb->pcb_flags = 0;
        l->l_proc->p_flag &= ~PK_32;
-
        l->l_md.md_flags = MDL_IRET;
+       cpu_fsgs_zero(l);
+       kpreempt_enable();
 
        tf = l->l_md.md_regs;
        tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
        tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
-       cpu_fsgs_zero(l);
        tf->tf_rdi = 0;
        tf->tf_rsi = 0;
        tf->tf_rbp = 0;
diff -r 223ec6a3ad99 -r 9bdeb15ad991 sys/arch/amd64/amd64/netbsd32_machdep.c
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c   Mon Apr 01 12:36:44 2019 +0000
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c   Fri Apr 05 07:48:05 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: netbsd32_machdep.c,v 1.105.2.2 2019/01/27 18:43:08 martin Exp $        */
+/*     $NetBSD: netbsd32_machdep.c,v 1.105.2.3 2019/04/05 07:48:05 martin Exp $        */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.105.2.2 2019/01/27 18:43:08 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.105.2.3 2019/04/05 07:48:05 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -132,9 +132,6 @@
 
        netbsd32_adjust_limits(p);
 
-       l->l_md.md_flags |= MDL_COMPAT32;       /* Force iret not sysret */
-       pcb->pcb_flags = PCB_COMPAT32;
-
        fpu_save_area_clear(l, pack->ep_osversion >= 699002600
            ?  __NetBSD_NPXCW__ : __NetBSD_COMPAT_NPXCW__);
 
@@ -143,13 +140,18 @@
                pcb->pcb_dbregs = NULL;
        }
 
+       kpreempt_disable();
+       pcb->pcb_flags = PCB_COMPAT32;
        p->p_flag |= PK_32;
+       l->l_md.md_flags = MDL_COMPAT32;        /* force iret not sysret */
+       cpu_fsgs_zero(l);
+       cpu_fsgs_reload(l, LSEL(LUDATA32_SEL, SEL_UPL),
+           LSEL(LUDATA32_SEL, SEL_UPL));
+       kpreempt_enable();
 
        tf = l->l_md.md_regs;
        tf->tf_ds = LSEL(LUDATA32_SEL, SEL_UPL);
        tf->tf_es = LSEL(LUDATA32_SEL, SEL_UPL);
-       cpu_fsgs_zero(l);
-       cpu_fsgs_reload(l, tf->tf_ds, tf->tf_es);
        tf->tf_rdi = 0;
        tf->tf_rsi = 0;
        tf->tf_rbp = 0;
diff -r 223ec6a3ad99 -r 9bdeb15ad991 sys/compat/linux/arch/amd64/linux_machdep.c
--- a/sys/compat/linux/arch/amd64/linux_machdep.c       Mon Apr 01 12:36:44 2019 +0000
+++ b/sys/compat/linux/arch/amd64/linux_machdep.c       Fri Apr 05 07:48:05 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_machdep.c,v 1.51.6.1 2017/09/04 20:41:28 snj Exp $ */
+/*     $NetBSD: linux_machdep.c,v 1.51.6.2 2019/04/05 07:48:05 martin Exp $ */
 
 /*-
  * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
@@ -33,7 +33,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.51.6.1 2017/09/04 20:41:28 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.51.6.2 2019/04/05 07:48:05 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -89,11 +89,13 @@
 #endif
 
        fpu_save_area_clear(l, __NetBSD_NPXCW__);
+
+       kpreempt_disable();
        pcb->pcb_flags = 0;
-
        l->l_proc->p_flag &= ~PK_32;
-
        l->l_md.md_flags = MDL_IRET;
+       cpu_fsgs_zero(l);
+       kpreempt_enable();
 
        tf = l->l_md.md_regs;
        tf->tf_rax = 0;
@@ -118,7 +120,6 @@
        tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
        tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
        tf->tf_es = 0;
-       cpu_fsgs_zero(l);
 
        return;
 }
diff -r 223ec6a3ad99 -r 9bdeb15ad991 sys/compat/linux32/arch/amd64/linux32_machdep.c
--- a/sys/compat/linux32/arch/amd64/linux32_machdep.c   Mon Apr 01 12:36:44 2019 +0000
+++ b/sys/compat/linux32/arch/amd64/linux32_machdep.c   Fri Apr 05 07:48:05 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux32_machdep.c,v 1.38.6.1 2017/09/09 17:01:23 snj Exp $ */
+/*     $NetBSD: linux32_machdep.c,v 1.38.6.2 2019/04/05 07:48:05 martin Exp $ */
 
 /*-
  * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
@@ -31,7 +31,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux32_machdep.c,v 1.38.6.1 2017/09/09 17:01:23 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux32_machdep.c,v 1.38.6.2 2019/04/05 07:48:05 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -283,10 +283,14 @@
 
        fpu_save_area_clear(l, __Linux_NPXCW__);
 
-       l->l_md.md_flags |= MDL_COMPAT32;       /* Forces iret not sysret */
+       kpreempt_disable();
        pcb->pcb_flags = PCB_COMPAT32;
-
        p->p_flag |= PK_32;
+       l->l_md.md_flags = MDL_COMPAT32;        /* force iret not sysret */
+       cpu_fsgs_zero(l);
+       cpu_fsgs_reload(l, GSEL(GUDATA32_SEL, SEL_UPL),
+           GSEL(GUDATA32_SEL, SEL_UPL));
+       kpreempt_enable();
 
        tf = l->l_md.md_regs;
        tf->tf_rax = 0;
@@ -311,8 +315,6 @@
        tf->tf_ss = GSEL(GUDATA32_SEL, SEL_UPL);
        tf->tf_ds = GSEL(GUDATA32_SEL, SEL_UPL);
        tf->tf_es = GSEL(GUDATA32_SEL, SEL_UPL);
-       cpu_fsgs_zero(l);
-       cpu_fsgs_reload(l, GSEL(GUDATA32_SEL, SEL_UPL), GSEL(GUDATA32_SEL, SEL_UPL));
 }
 
 static void



Home | Main Index | Thread Index | Old Index