svn commit: r323772 - in head/sys: amd64/amd64 i386/i386

Konstantin Belousov kib at FreeBSD.org
Tue Sep 19 17:57:05 UTC 2017


Author: kib
Date: Tue Sep 19 17:57:04 2017
New Revision: 323772
URL: https://svnweb.freebsd.org/changeset/base/323772

Log:
  Do not do torn writes to active LDTs.
  
  Care must be taken when updating the active LDT, since parallel
  threads might try to load a segment descriptor which is currently
  updated. Since the results are undefined, this cannot be ignored by
  claiming to be an application race.
  
  Reviewed by:	jhb
  Sponsored by:	The FreeBSD Foundation
  MFC after:	2 weeks
  Differential revision:	https://reviews.freebsd.org/D12413

Modified:
  head/sys/amd64/amd64/sys_machdep.c
  head/sys/i386/i386/sys_machdep.c

Modified: head/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- head/sys/amd64/amd64/sys_machdep.c	Tue Sep 19 17:12:18 2017	(r323771)
+++ head/sys/amd64/amd64/sys_machdep.c	Tue Sep 19 17:57:04 2017	(r323772)
@@ -583,22 +583,22 @@ amd64_get_ldt(td, uap)
 }
 
 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;
+	int error;
+	unsigned int largest_ld, i;
 
 #ifdef	DEBUG
 	printf("amd64_set_ldt: start=%d num=%d 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;
@@ -616,10 +616,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++)
+			((uint64_t *)(pldt->ldt_base))[i] = 0;
 		mtx_unlock(&dt_lock);
 		return (0);
 	}
@@ -741,14 +740,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;
+	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 = (uint64_t *)(pldt->ldt_base);
+	src = (uint64_t *)descs;
+	for (i = 0; i < num; i++)
+		dst[start + i] = src[i];
 	return (0);
 }

Modified: head/sys/i386/i386/sys_machdep.c
==============================================================================
--- head/sys/i386/i386/sys_machdep.c	Tue Sep 19 17:12:18 2017	(r323771)
+++ head/sys/i386/i386/sys_machdep.c	Tue Sep 19 17:57:04 2017	(r323772)
@@ -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>
@@ -546,7 +547,7 @@ i386_set_ldt(td, uap, descs)
 	struct i386_ldt_args *uap;
 	union descriptor *descs;
 {
-	int error = 0, i;
+	int error, i;
 	int largest_ld;
 	struct mdproc *mdp = &td->td_proc->p_md;
 	struct proc_ldt *pldt;
@@ -556,6 +557,7 @@ i386_set_ldt(td, uap, descs)
 	printf("i386_set_ldt: start=%d num=%d descs=%p\n",
 	    uap->start, uap->num, (void *)uap->descs);
 #endif
+	error = 0;
 
 	if (descs == NULL) {
 		/* Free descriptors */
@@ -578,9 +580,9 @@ 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);
 	}
@@ -702,17 +704,27 @@ 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);
 }
 


More information about the svn-src-all mailing list