Author: kib
Date: Sun Oct 22 08:47:13 2017
New Revision: 324855
URL: https://svnweb.freebsd.org/changeset/base/324855

Log:
  MFC r323772, r324302-r324308, r324310, r324313, r324315, r324326, r324330,
      r324334, r324354-r324355, r324366, r324432-r324433, r324437-r324439:
  Fixes and improvements for x86 LDT handling.

Modified:
  stable/11/sys/amd64/amd64/sys_machdep.c
  stable/11/sys/amd64/include/proc.h
  stable/11/sys/i386/i386/machdep.c
  stable/11/sys/i386/i386/swtch.s
  stable/11/sys/i386/i386/sys_machdep.c
  stable/11/sys/i386/include/md_var.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- stable/11/sys/amd64/amd64/sys_machdep.c     Sun Oct 22 08:42:01 2017        
(r324854)
+++ stable/11/sys/amd64/amd64/sys_machdep.c     Sun Oct 22 08:47:13 2017        
(r324855)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mutex.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/smp.h>
 #include <sys/sysproto.h>
 #include <sys/uio.h>
 
@@ -64,7 +65,7 @@ __FBSDID("$FreeBSD$");
 
 #define        MAX_LD          8192
 
-int max_ldt_segment = 1024;
+int max_ldt_segment = 512;
 SYSCTL_INT(_machdep, OID_AUTO, max_ldt_segment, CTLFLAG_RDTUN,
     &max_ldt_segment, 0,
     "Maximum number of allowed LDT segments in the single address space");
@@ -80,11 +81,6 @@ max_ldt_segment_init(void *arg __unused)
 }
 SYSINIT(maxldt, SI_SUB_VM_CONF, SI_ORDER_ANY, max_ldt_segment_init, NULL);
 
-#ifdef notyet
-#ifdef SMP
-static void set_user_ldt_rv(struct vmspace *vmsp);
-#endif
-#endif
 static void user_ldt_derefl(struct proc_ldt *pldt);
 
 #ifndef _SYS_SYSPROTO_H_
@@ -428,18 +424,14 @@ done:
  * Update the GDT entry pointing to the LDT to point to the LDT of the
  * current process.
  */
-void
+static void
 set_user_ldt(struct mdproc *mdp)
 {
 
-       critical_enter();
        *PCPU_GET(ldt) = mdp->md_ldt_sd;
        lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
-       critical_exit();
 }
 
-#ifdef notyet
-#ifdef SMP
 static void
 set_user_ldt_rv(struct vmspace *vmsp)
 {
@@ -451,8 +443,6 @@ set_user_ldt_rv(struct vmspace *vmsp)
 
        set_user_ldt(&td->td_proc->p_md);
 }
-#endif
-#endif
 
 struct proc_ldt *
 user_ldt_alloc(struct proc *p, int force)
@@ -494,11 +484,13 @@ user_ldt_alloc(struct proc *p, int force)
                    sizeof(struct user_segment_descriptor));
                user_ldt_derefl(pldt);
        }
+       critical_enter();
        ssdtosyssd(&sldt, &p->p_md.md_ldt_sd);
-       atomic_store_rel_ptr((volatile uintptr_t *)&mdp->md_ldt,
-           (uintptr_t)new_ldt);
-       if (p == curproc)
-               set_user_ldt(mdp);
+       atomic_thread_fence_rel();
+       mdp->md_ldt = new_ldt;
+       critical_exit();
+       smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, NULL,
+           p->p_vmspace);
 
        return (mdp->md_ldt);
 }
@@ -516,10 +508,13 @@ user_ldt_free(struct thread *td)
                return;
        }
 
+       critical_enter();
        mdp->md_ldt = NULL;
+       atomic_thread_fence_rel();
        bzero(&mdp->md_ldt_sd, sizeof(mdp->md_ldt_sd));
        if (td == curthread)
                lldt(GSEL(GNULL_SEL, SEL_KPL));
+       critical_exit();
        user_ldt_deref(pldt);
 }
 
@@ -550,57 +545,57 @@ user_ldt_deref(struct proc_ldt *pldt)
  * the OS-specific one.
  */
 int
-amd64_get_ldt(td, uap)
-       struct thread *td;
-       struct i386_ldt_args *uap;
+amd64_get_ldt(struct thread *td, struct i386_ldt_args *uap)
 {
-       int error = 0;
        struct proc_ldt *pldt;
-       int num;
        struct user_segment_descriptor *lp;
+       uint64_t *data;
+       u_int i, num;
+       int error;
 
 #ifdef DEBUG
-       printf("amd64_get_ldt: start=%d num=%d descs=%p\n",
+       printf("amd64_get_ldt: start=%u num=%u descs=%p\n",
            uap->start, uap->num, (void *)uap->descs);
 #endif
 
-       if ((pldt = td->td_proc->p_md.md_ldt) != NULL) {
-               lp = &((struct user_segment_descriptor *)(pldt->ldt_base))
-                   [uap->start];
-               num = min(uap->num, max_ldt_segment);
-       } else
-               return (EINVAL);
-
-       if ((uap->start > (unsigned int)max_ldt_segment) ||
-           ((unsigned int)num > (unsigned int)max_ldt_segment) ||
-           ((unsigned int)(uap->start + num) > (unsigned int)max_ldt_segment))
-               return(EINVAL);
-
-       error = copyout(lp, uap->descs, num *
+       pldt = td->td_proc->p_md.md_ldt;
+       if (pldt == NULL || uap->start >= max_ldt_segment || uap->num == 0) {
+               td->td_retval[0] = 0;
+               return (0);
+       }
+       num = min(uap->num, max_ldt_segment - uap->start);
+       lp = &((struct user_segment_descriptor *)(pldt->ldt_base))[uap->start];
+       data = malloc(num * sizeof(struct user_segment_descriptor), M_TEMP,
+           M_WAITOK);
+       mtx_lock(&dt_lock);
+       for (i = 0; i < num; i++)
+               data[i] = ((volatile uint64_t *)lp)[i];
+       mtx_unlock(&dt_lock);
+       error = copyout(data, uap->descs, num *
            sizeof(struct user_segment_descriptor));
-       if (!error)
+       free(data, M_TEMP);
+       if (error == 0)
                td->td_retval[0] = num;
-
-       return(error);
+       return (error);
 }
 
 int
-amd64_set_ldt(td, uap, descs)
-       struct thread *td;
-       struct i386_ldt_args *uap;
-       struct user_segment_descriptor *descs;
+amd64_set_ldt(struct thread *td, struct i386_ldt_args *uap,
+    struct user_segment_descriptor *descs)
 {
-       int error = 0;
-       unsigned int largest_ld, i;
-       struct mdproc *mdp = &td->td_proc->p_md;
+       struct mdproc *mdp;
        struct proc_ldt *pldt;
        struct user_segment_descriptor *dp;
        struct proc *p;
+       u_int largest_ld, i;
+       int error;
 
 #ifdef DEBUG
-       printf("amd64_set_ldt: start=%d num=%d descs=%p\n",
+       printf("amd64_set_ldt: start=%u num=%u descs=%p\n",
            uap->start, uap->num, (void *)uap->descs);
 #endif
+       mdp = &td->td_proc->p_md;
+       error = 0;
 
        set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        p = td->td_proc;
@@ -618,10 +613,9 @@ amd64_set_ldt(td, uap, descs)
                        largest_ld = max_ldt_segment;
                if (largest_ld < uap->start)
                        return (EINVAL);
-               i = largest_ld - uap->start;
                mtx_lock(&dt_lock);
-               bzero(&((struct user_segment_descriptor *)(pldt->ldt_base))
-                   [uap->start], sizeof(struct user_segment_descriptor) * i);
+               for (i = uap->start; i < largest_ld; i++)
+                       ((volatile uint64_t *)(pldt->ldt_base))[i] = 0;
                mtx_unlock(&dt_lock);
                return (0);
        }
@@ -658,12 +652,7 @@ amd64_set_ldt(td, uap, descs)
                case SDT_SYSNULL4:
                case SDT_SYSIGT:
                case SDT_SYSTGT:
-                       /* I can't think of any reason to allow a user proc
-                        * to create a segment of these types.  They are
-                        * for OS use only.
-                        */
                        return (EACCES);
-                       /*NOTREACHED*/
 
                /* memory segment types */
                case SDT_MEMEC:   /* memory execute only conforming */
@@ -689,7 +678,6 @@ amd64_set_ldt(td, uap, descs)
                        break;
                default:
                        return(EINVAL);
-                       /*NOTREACHED*/
                }
 
                /* Only user (ring-3) descriptors may be present. */
@@ -743,14 +731,18 @@ int
 amd64_set_ldt_data(struct thread *td, int start, int num,
     struct user_segment_descriptor *descs)
 {
-       struct mdproc *mdp = &td->td_proc->p_md;
-       struct proc_ldt *pldt = mdp->md_ldt;
+       struct mdproc *mdp;
+       struct proc_ldt *pldt;
+       volatile uint64_t *dst, *src;
+       int i;
 
        mtx_assert(&dt_lock, MA_OWNED);
 
-       /* Fill in range */
-       bcopy(descs,
-           &((struct user_segment_descriptor *)(pldt->ldt_base))[start],
-           num * sizeof(struct user_segment_descriptor));
+       mdp = &td->td_proc->p_md;
+       pldt = mdp->md_ldt;
+       dst = (volatile uint64_t *)(pldt->ldt_base);
+       src = (volatile uint64_t *)descs;
+       for (i = 0; i < num; i++)
+               dst[start + i] = src[i];
        return (0);
 }

Modified: stable/11/sys/amd64/include/proc.h
==============================================================================
--- stable/11/sys/amd64/include/proc.h  Sun Oct 22 08:42:01 2017        
(r324854)
+++ stable/11/sys/amd64/include/proc.h  Sun Oct 22 08:47:13 2017        
(r324855)
@@ -88,7 +88,6 @@ struct syscall_args {
            (char *)&td;                                                \
 } while (0)
 
-void set_user_ldt(struct mdproc *);
 struct proc_ldt *user_ldt_alloc(struct proc *, int);
 void user_ldt_free(struct thread *);
 void user_ldt_deref(struct proc_ldt *);

Modified: stable/11/sys/i386/i386/machdep.c
==============================================================================
--- stable/11/sys/i386/i386/machdep.c   Sun Oct 22 08:42:01 2017        
(r324854)
+++ stable/11/sys/i386/i386/machdep.c   Sun Oct 22 08:47:13 2017        
(r324855)
@@ -1146,6 +1146,15 @@ exec_setregs(struct thread *td, struct image_params *i
        else
                mtx_unlock_spin(&dt_lock);
   
+       /*
+        * Reset the fs and gs bases.  The values from the old address
+        * space do not make sense for the new program.  In particular,
+        * gsbase might be the TLS base for the old program but the new
+        * program has no TLS now.
+        */
+       set_fsbase(td, 0);
+       set_gsbase(td, 0);
+
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_eip = imgp->entry_addr;
        regs->tf_esp = stack;

Modified: stable/11/sys/i386/i386/swtch.s
==============================================================================
--- stable/11/sys/i386/i386/swtch.s     Sun Oct 22 08:42:01 2017        
(r324854)
+++ stable/11/sys/i386/i386/swtch.s     Sun Oct 22 08:47:13 2017        
(r324855)
@@ -283,6 +283,10 @@ sw1:
        pushl   %edx                            /* Preserve pointer to pcb. */
        addl    $P_MD,%eax                      /* Pointer to mdproc is arg. */
        pushl   %eax
+       /*
+        * Holding dt_lock prevents context switches, so dt_lock cannot
+        * be held now and set_user_ldt() will not deadlock acquiring it.
+        */
        call    set_user_ldt
        addl    $4,%esp
        popl    %edx

Modified: stable/11/sys/i386/i386/sys_machdep.c
==============================================================================
--- stable/11/sys/i386/i386/sys_machdep.c       Sun Oct 22 08:42:01 2017        
(r324854)
+++ stable/11/sys/i386/i386/sys_machdep.c       Sun Oct 22 08:47:13 2017        
(r324855)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_map.h>
 #include <vm/vm_extern.h>
 
+#include <machine/atomic.h>
 #include <machine/cpu.h>
 #include <machine/pcb.h>
 #include <machine/pcb_ext.h>
@@ -68,10 +69,10 @@ __FBSDID("$FreeBSD$");
 #define        NULL_LDT_BASE   ((caddr_t)NULL)
 
 #ifdef SMP
-static void set_user_ldt_rv(struct vmspace *vmsp);
+static void set_user_ldt_rv(void *arg);
 #endif
 static int i386_set_ldt_data(struct thread *, int start, int num,
-       union descriptor *descs);
+    union descriptor *descs);
 static int i386_ldt_grow(struct thread *td, int len);
 
 void
@@ -90,6 +91,37 @@ fill_based_sd(struct segment_descriptor *sdp, uint32_t
        sdp->sd_gran = 1;
 }
 
+/*
+ * Construct special descriptors for "base" selectors.  Store them in
+ * the PCB for later use by cpu_switch().  Store them in the GDT for
+ * more immediate use.  The GDT entries are part of the current
+ * context.  Callers must load related segment registers to complete
+ * setting up the current context.
+ */
+void
+set_fsbase(struct thread *td, uint32_t base)
+{
+       struct segment_descriptor sd;
+
+       fill_based_sd(&sd, base);
+       critical_enter();
+       td->td_pcb->pcb_fsd = sd;
+       PCPU_GET(fsgs_gdt)[0] = sd;
+       critical_exit();
+}
+
+void
+set_gsbase(struct thread *td, uint32_t base)
+{
+       struct segment_descriptor sd;
+
+       fill_based_sd(&sd, base);
+       critical_enter();
+       td->td_pcb->pcb_gsd = sd;
+       PCPU_GET(fsgs_gdt)[1] = sd;
+       critical_exit();
+}
+
 #ifndef _SYS_SYSPROTO_H_
 struct sysarch_args {
        int op;
@@ -110,7 +142,7 @@ sysarch(td, uap)
                struct i386_get_xfpustate xfpu;
        } kargs;
        uint32_t base;
-       struct segment_descriptor sd, *sdp;
+       struct segment_descriptor *sdp;
 
        AUDIT_ARG_CMD(uap->op);
 
@@ -155,8 +187,6 @@ sysarch(td, uap)
                if ((error = copyin(uap->parms, &kargs.largs,
                    sizeof(struct i386_ldt_args))) != 0)
                        return (error);
-               if (kargs.largs.num > MAX_LD || kargs.largs.num <= 0)
-                       return (EINVAL);
                break;
        case I386_GET_XFPUSTATE:
                if ((error = copyin(uap->parms, &kargs.xfpu,
@@ -167,14 +197,15 @@ sysarch(td, uap)
                break;
        }
 
-       switch(uap->op) {
+       switch (uap->op) {
        case I386_GET_LDT:
                error = i386_get_ldt(td, &kargs.largs);
                break;
        case I386_SET_LDT:
                if (kargs.largs.descs != NULL) {
-                       lp = (union descriptor *)malloc(
-                           kargs.largs.num * sizeof(union descriptor),
+                       if (kargs.largs.num > MAX_LD)
+                               return (EINVAL);
+                       lp = malloc(kargs.largs.num * sizeof(union descriptor),
                            M_TEMP, M_WAITOK);
                        error = copyin(kargs.largs.descs, lp,
                            kargs.largs.num * sizeof(union descriptor));
@@ -206,16 +237,11 @@ sysarch(td, uap)
                error = copyin(uap->parms, &base, sizeof(base));
                if (error == 0) {
                        /*
-                        * Construct a descriptor and store it in the pcb for
-                        * the next context switch.  Also store it in the gdt
-                        * so that the load of tf_fs into %fs will activate it
-                        * at return to userland.
+                        * Construct the special descriptor for fsbase
+                        * and arrange for doreti to load its selector
+                        * soon enough.
                         */
-                       fill_based_sd(&sd, base);
-                       critical_enter();
-                       td->td_pcb->pcb_fsd = sd;
-                       PCPU_GET(fsgs_gdt)[0] = sd;
-                       critical_exit();
+                       set_fsbase(td, base);
                        td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
                }
                break;
@@ -228,15 +254,11 @@ sysarch(td, uap)
                error = copyin(uap->parms, &base, sizeof(base));
                if (error == 0) {
                        /*
-                        * Construct a descriptor and store it in the pcb for
-                        * the next context switch.  Also store it in the gdt
-                        * because we have to do a load_gs() right now.
+                        * Construct the special descriptor for gsbase.
+                        * The selector is loaded immediately, since we
+                        * normally only reload %gs on context switches.
                         */
-                       fill_based_sd(&sd, base);
-                       critical_enter();
-                       td->td_pcb->pcb_gsd = sd;
-                       PCPU_GET(fsgs_gdt)[1] = sd;
-                       critical_exit();
+                       set_gsbase(td, base);
                        load_gs(GSEL(GUGS_SEL, SEL_UPL));
                }
                break;
@@ -385,41 +407,40 @@ done:
  * Update the GDT entry pointing to the LDT to point to the LDT of the
  * current process. Manage dt_lock holding/unholding autonomously.
  */   
-void
-set_user_ldt(struct mdproc *mdp)
+static void
+set_user_ldt_locked(struct mdproc *mdp)
 {
        struct proc_ldt *pldt;
-       int dtlocked;
+       int gdt_idx;
 
-       dtlocked = 0;
-       if (!mtx_owned(&dt_lock)) {
-               mtx_lock_spin(&dt_lock);
-               dtlocked = 1;
-       }
+       mtx_assert(&dt_lock, MA_OWNED);
 
        pldt = mdp->md_ldt;
-#ifdef SMP
-       gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd;
-#else
-       gdt[GUSERLDT_SEL].sd = pldt->ldt_sd;
-#endif
+       gdt_idx = GUSERLDT_SEL;
+       gdt_idx += PCPU_GET(cpuid) * NGDT;      /* always 0 on UP */
+       gdt[gdt_idx].sd = pldt->ldt_sd;
        lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
        PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
-       if (dtlocked)
-               mtx_unlock_spin(&dt_lock);
 }
 
+void
+set_user_ldt(struct mdproc *mdp)
+{
+
+       mtx_lock_spin(&dt_lock);
+       set_user_ldt_locked(mdp);
+       mtx_unlock_spin(&dt_lock);
+}
+
 #ifdef SMP
 static void
-set_user_ldt_rv(struct vmspace *vmsp)
+set_user_ldt_rv(void *arg)
 {
-       struct thread *td;
+       struct proc *p;
 
-       td = curthread;
-       if (vmsp != td->td_proc->p_vmspace)
-               return;
-
-       set_user_ldt(&td->td_proc->p_md);
+       p = curproc;
+       if (arg == p->p_vmspace)
+               set_user_ldt(&p->p_md);
 }
 #endif
 
@@ -433,8 +454,7 @@ user_ldt_alloc(struct mdproc *mdp, int len)
 
        mtx_assert(&dt_lock, MA_OWNED);
        mtx_unlock_spin(&dt_lock);
-       new_ldt = malloc(sizeof(struct proc_ldt),
-               M_SUBPROC, M_WAITOK);
+       new_ldt = malloc(sizeof(struct proc_ldt), M_SUBPROC, M_WAITOK);
 
        new_ldt->ldt_len = len = NEW_MAX_LD(len);
        new_ldt->ldt_base = (caddr_t)kmem_malloc(kernel_arena,
@@ -464,10 +484,11 @@ user_ldt_alloc(struct mdproc *mdp, int len)
 void
 user_ldt_free(struct thread *td)
 {
-       struct mdproc *mdp = &td->td_proc->p_md;
+       struct mdproc *mdp;
        struct proc_ldt *pldt;
 
        mtx_assert(&dt_lock, MA_OWNED);
+       mdp = &td->td_proc->p_md;
        if ((pldt = mdp->md_ldt) == NULL) {
                mtx_unlock_spin(&dt_lock);
                return;
@@ -503,61 +524,55 @@ user_ldt_deref(struct proc_ldt *pldt)
  * the OS-specific one.
  */
 int
-i386_get_ldt(td, uap)
-       struct thread *td;
-       struct i386_ldt_args *uap;
+i386_get_ldt(struct thread *td, struct i386_ldt_args *uap)
 {
-       int error = 0;
        struct proc_ldt *pldt;
-       int nldt, num;
-       union descriptor *lp;
+       char *data;
+       u_int nldt, num;
+       int error;
 
-#ifdef DEBUG
-       printf("i386_get_ldt: start=%d num=%d descs=%p\n",
+#ifdef DEBUG
+       printf("i386_get_ldt: start=%u num=%u descs=%p\n",
            uap->start, uap->num, (void *)uap->descs);
 #endif
 
+       num = min(uap->num, MAX_LD);
+       data = malloc(num * sizeof(union descriptor), M_TEMP, M_WAITOK);
        mtx_lock_spin(&dt_lock);
-       if ((pldt = td->td_proc->p_md.md_ldt) != NULL) {
-               nldt = pldt->ldt_len;
-               lp = &((union descriptor *)(pldt->ldt_base))[uap->start];
-               mtx_unlock_spin(&dt_lock);
-               num = min(uap->num, nldt);
+       pldt = td->td_proc->p_md.md_ldt;
+       nldt = pldt != NULL ? pldt->ldt_len : nitems(ldt);
+       if (uap->start >= nldt) {
+               num = 0;
        } else {
-               mtx_unlock_spin(&dt_lock);
-               nldt = sizeof(ldt)/sizeof(ldt[0]);
-               num = min(uap->num, nldt);
-               lp = &ldt[uap->start];
+               num = min(num, nldt - uap->start);
+               bcopy(pldt != NULL ?
+                   &((union descriptor *)(pldt->ldt_base))[uap->start] :
+                   &ldt[uap->start], data, num * sizeof(union descriptor));
        }
-
-       if ((uap->start > (unsigned int)nldt) ||
-           ((unsigned int)num > (unsigned int)nldt) ||
-           ((unsigned int)(uap->start + num) > (unsigned int)nldt))
-               return(EINVAL);
-
-       error = copyout(lp, uap->descs, num * sizeof(union descriptor));
-       if (!error)
+       mtx_unlock_spin(&dt_lock);
+       error = copyout(data, uap->descs, num * sizeof(union descriptor));
+       if (error == 0)
                td->td_retval[0] = num;
-
-       return(error);
+       free(data, M_TEMP);
+       return (error);
 }
 
 int
-i386_set_ldt(td, uap, descs)
-       struct thread *td;
-       struct i386_ldt_args *uap;
-       union descriptor *descs;
+i386_set_ldt(struct thread *td, struct i386_ldt_args *uap,
+    union descriptor *descs)
 {
-       int error = 0, i;
-       int largest_ld;
-       struct mdproc *mdp = &td->td_proc->p_md;
+       struct mdproc *mdp;
        struct proc_ldt *pldt;
        union descriptor *dp;
+       u_int largest_ld, i;
+       int error;
 
-#ifdef DEBUG
-       printf("i386_set_ldt: start=%d num=%d descs=%p\n",
+#ifdef DEBUG
+       printf("i386_set_ldt: start=%u num=%u descs=%p\n",
            uap->start, uap->num, (void *)uap->descs);
 #endif
+       error = 0;
+       mdp = &td->td_proc->p_md;
 
        if (descs == NULL) {
                /* Free descriptors */
@@ -569,8 +584,6 @@ i386_set_ldt(td, uap, descs)
                        uap->start = NLDT;
                        uap->num = MAX_LD - NLDT;
                }
-               if (uap->num == 0)
-                       return (EINVAL);
                mtx_lock_spin(&dt_lock);
                if ((pldt = mdp->md_ldt) == NULL ||
                    uap->start >= pldt->ldt_len) {
@@ -580,19 +593,18 @@ i386_set_ldt(td, uap, descs)
                largest_ld = uap->start + uap->num;
                if (largest_ld > pldt->ldt_len)
                        largest_ld = pldt->ldt_len;
-               i = largest_ld - uap->start;
-               bzero(&((union descriptor *)(pldt->ldt_base))[uap->start],
-                   sizeof(union descriptor) * i);
+               for (i = uap->start; i < largest_ld; i++)
+                       atomic_store_rel_64(&((uint64_t *)(pldt->ldt_base))[i],
+                           0);
                mtx_unlock_spin(&dt_lock);
                return (0);
        }
 
-       if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) {
+       if (uap->start != LDT_AUTO_ALLOC || uap->num != 1) {
                /* verify range of descriptors to modify */
                largest_ld = uap->start + uap->num;
-               if (uap->start >= MAX_LD || largest_ld > MAX_LD) {
+               if (uap->start >= MAX_LD || largest_ld > MAX_LD)
                        return (EINVAL);
-               }
        }
 
        /* Check descriptors for access violations */
@@ -618,12 +630,7 @@ i386_set_ldt(td, uap, descs)
                case SDT_SYS386TGT: /* system 386 trap gate */
                case SDT_SYS286CGT: /* system 286 call gate */ 
                case SDT_SYS386CGT: /* system 386 call gate */
-                       /* I can't think of any reason to allow a user proc
-                        * to create a segment of these types.  They are
-                        * for OS use only.
-                        */
                        return (EACCES);
-                       /*NOTREACHED*/
 
                /* memory segment types */
                case SDT_MEMEC:   /* memory execute only conforming */
@@ -648,12 +655,11 @@ i386_set_ldt(td, uap, descs)
                case SDT_MEMERA:  /* memory execute read accessed */
                        break;
                default:
-                       return(EINVAL);
-                       /*NOTREACHED*/
+                       return (EINVAL);
                }
 
                /* Only user (ring-3) descriptors may be present. */
-               if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL))
+               if (dp->sd.sd_p != 0 && dp->sd.sd_dpl != SEL_UPL)
                        return (EACCES);
        }
 
@@ -704,27 +710,37 @@ again:
 
 static int
 i386_set_ldt_data(struct thread *td, int start, int num,
-       union descriptor *descs)
+    union descriptor *descs)
 {
-       struct mdproc *mdp = &td->td_proc->p_md;
-       struct proc_ldt *pldt = mdp->md_ldt;
+       struct mdproc *mdp;
+       struct proc_ldt *pldt;
+       uint64_t *dst, *src;
+       int i;
 
        mtx_assert(&dt_lock, MA_OWNED);
 
-       /* Fill in range */
-       bcopy(descs,
-           &((union descriptor *)(pldt->ldt_base))[start],
-           num * sizeof(union descriptor));
+       mdp = &td->td_proc->p_md;
+       pldt = mdp->md_ldt;
+       dst = (uint64_t *)(pldt->ldt_base);
+       src = (uint64_t *)descs;
+
+       /*
+        * Atomic(9) is used only to get 64bit atomic store with
+        * cmpxchg8b when available.  There is no op without release
+        * semantic.
+        */
+       for (i = 0; i < num; i++)
+               atomic_store_rel_64(&dst[start + i], src[i]);
        return (0);
 }
 
 static int
 i386_ldt_grow(struct thread *td, int len) 
 {
-       struct mdproc *mdp = &td->td_proc->p_md;
+       struct mdproc *mdp;
        struct proc_ldt *new_ldt, *pldt;
-       caddr_t old_ldt_base = NULL_LDT_BASE;
-       int old_ldt_len = 0;
+       caddr_t old_ldt_base;
+       int old_ldt_len;
 
        mtx_assert(&dt_lock, MA_OWNED);
 
@@ -733,6 +749,10 @@ i386_ldt_grow(struct thread *td, int len) 
        if (len < NLDT + 1)
                len = NLDT + 1;
 
+       mdp = &td->td_proc->p_md;
+       old_ldt_base = NULL_LDT_BASE;
+       old_ldt_len = 0;
+
        /* Allocate a user ldt. */
        if ((pldt = mdp->md_ldt) == NULL || len > pldt->ldt_len) {
                new_ldt = user_ldt_alloc(mdp, len);
@@ -774,10 +794,10 @@ i386_ldt_grow(struct thread *td, int len) 
                 * to acquire it.
                 */
                mtx_unlock_spin(&dt_lock);
-               smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv,
-                   NULL, td->td_proc->p_vmspace);
+               smp_rendezvous(NULL, set_user_ldt_rv, NULL,
+                   td->td_proc->p_vmspace);
 #else
-               set_user_ldt(&td->td_proc->p_md);
+               set_user_ldt_locked(&td->td_proc->p_md);
                mtx_unlock_spin(&dt_lock);
 #endif
                if (old_ldt_base != NULL_LDT_BASE) {

Modified: stable/11/sys/i386/include/md_var.h
==============================================================================
--- stable/11/sys/i386/include/md_var.h Sun Oct 22 08:42:01 2017        
(r324854)
+++ stable/11/sys/i386/include/md_var.h Sun Oct 22 08:47:13 2017        
(r324855)
@@ -66,6 +66,8 @@ void  init_AMD_Elan_sc520(void);
 vm_paddr_t kvtop(void *addr);
 void   panicifcpuunsupported(void);
 void   ppro_reenable_apic(void);
+void   set_fsbase(struct thread *td, uint32_t base);
+void   set_gsbase(struct thread *td, uint32_t base);
 void   setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int selec);
 union savefpu *get_pcb_user_save_td(struct thread *td);
 union savefpu *get_pcb_user_save_pcb(struct pcb *pcb);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to