svn commit: r324855 - in stable/11/sys: amd64/amd64 amd64/include i386/i386 i386/include

Konstantin Belousov kib at FreeBSD.org
Sun Oct 22 08:47:15 UTC 2017


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);


More information about the svn-src-stable mailing list