svn commit: r324310 - head/sys/amd64/amd64

Konstantin Belousov kib at FreeBSD.org
Thu Oct 5 12:29:36 UTC 2017


Author: kib
Date: Thu Oct  5 12:29:34 2017
New Revision: 324310
URL: https://svnweb.freebsd.org/changeset/base/324310

Log:
  Improve amd64_get_ldt().
  
  Provide consistent snapshot of the requested descriptors by preventing
  other threads from modifying LDT while we fetch the data, lock dt_lock
  around the read.  Copy the data into intermediate buffer, which is
  copied out after the lock is dropped.
  
  Use guaranteed atomic (aligned volatile) reads of the descriptors to
  use same-size atomic as CPU update to set A bit in the descriptor type
  field.
  
  Improve overflow checking for the descriptors range calculations and
  remove unneeded casts.
  
  Reviewed by:	bde
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

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

Modified: head/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- head/sys/amd64/amd64/sys_machdep.c	Thu Oct  5 12:25:18 2017	(r324309)
+++ head/sys/amd64/amd64/sys_machdep.c	Thu Oct  5 12:29:34 2017	(r324310)
@@ -550,34 +550,36 @@ user_ldt_deref(struct proc_ldt *pldt)
 int
 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=%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
+	if (uap->start >= max_ldt_segment)
 		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 *
+	num = min(uap->num, max_ldt_segment - uap->start);
+	pldt = td->td_proc->p_md.md_ldt;
+	if (pldt == NULL)
+		return (EINVAL);
+	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


More information about the svn-src-all mailing list