Module Name:    src
Committed By:   maxv
Date:           Sun Feb  5 08:19:05 UTC 2017

Modified Files:
        src/sys/arch/amd64/amd64: machdep.c

Log Message:
In cpu_mcontext_validate, treat %cs differently depending on whether a user
LDT is set; just check the permission without checking the location (which
may change).

In valid_user_selector, don't check the length of the LDT. This is racy
because pm_ldt_len could be updated by another thread, and useless since
the length is already referenced in ldtr (ldt_alloc), which means that any
overflow will fault in userland.

Also, don't check the permission of the segment pointed to; this too is
racy, and we don't care either since the permissions are checked earlier
in x86_set_ldt1.

Pass 1/2.


To generate a diff of this commit:
cvs rdiff -u -r1.249 -r1.250 src/sys/arch/amd64/amd64/machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.249 src/sys/arch/amd64/amd64/machdep.c:1.250
--- src/sys/arch/amd64/amd64/machdep.c:1.249	Sun Feb  5 06:26:06 2017
+++ src/sys/arch/amd64/amd64/machdep.c	Sun Feb  5 08:19:05 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.249 2017/02/05 06:26:06 maya Exp $	*/
+/*	$NetBSD: machdep.c,v 1.250 2017/02/05 08:19:05 maxv 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.249 2017/02/05 06:26:06 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.250 2017/02/05 08:19:05 maxv Exp $");
 
 /* #define XENDEBUG_LOW  */
 
@@ -1939,23 +1939,28 @@ cpu_mcontext_validate(struct lwp *l, con
 		error = valid_user_selector(l, gr[_REG_SS]);
 		if (error != 0)
 			return error;
+
+		if (!USERMODE(gr[_REG_CS], gr[_REG_RFLAGS]))
+			return EINVAL;
 #endif
 	} else {
 #define VUD(sel) \
     ((p->p_flag & PK_32) ? VALID_USER_DSEL32(sel) : VALID_USER_DSEL(sel))
+#define VUF(sel) /* XXX: Shouldn't this be FSEL32? */ \
+    ((p->p_flag & PK_32) ? VALID_USER_DSEL32(sel) : VALID_USER_DSEL(sel))
+#define VUG(sel) \
+    ((p->p_flag & PK_32) ? VALID_USER_GSEL32(sel) : VALID_USER_DSEL(sel))
+#define VUC(sel) \
+    ((p->p_flag & PK_32) ? VALID_USER_CSEL32(sel) : VALID_USER_CSEL(sel))
+
 		sel = gr[_REG_ES] & 0xffff;
 		if (sel != 0 && !VUD(sel))
 			return EINVAL;
 
-/* XXX: Shouldn't this be FSEL32? */
-#define VUF(sel) \
-    ((p->p_flag & PK_32) ? VALID_USER_DSEL32(sel) : VALID_USER_DSEL(sel))
 		sel = gr[_REG_FS] & 0xffff;
 		if (sel != 0 && !VUF(sel))
 			return EINVAL;
 
-#define VUG(sel) \
-    ((p->p_flag & PK_32) ? VALID_USER_GSEL32(sel) : VALID_USER_DSEL(sel))
 		sel = gr[_REG_GS] & 0xffff;
 		if (sel != 0 && !VUG(sel))
 			return EINVAL;
@@ -1968,17 +1973,12 @@ cpu_mcontext_validate(struct lwp *l, con
 		sel = gr[_REG_SS] & 0xffff;
 		if (!VUD(sel))
 			return EINVAL;
-#endif
-
-	}
 
-#ifndef XEN
-#define VUC(sel) \
-    ((p->p_flag & PK_32) ? VALID_USER_CSEL32(sel) : VALID_USER_CSEL(sel))
-	sel = gr[_REG_CS] & 0xffff;
-	if (!VUC(sel))
-		return EINVAL;
+		sel = gr[_REG_CS] & 0xffff;
+		if (!VUC(sel))
+			return EINVAL;
 #endif
+	}
 
 	if (gr[_REG_RIP] >= VM_MAXUSER_ADDRESS)
 		return EINVAL;
@@ -1991,34 +1991,17 @@ cpu_initclocks(void)
 	(*initclock_func)();
 }
 
+/*
+ * Called only when the LDT is user-set (USER_LDT).
+ */
 static int
 valid_user_selector(struct lwp *l, uint64_t seg)
 {
-	int off, len;
-	char *dt;
-	struct mem_segment_descriptor *sdp;
-	struct proc *p = l->l_proc;
-	struct pmap *pmap= p->p_vmspace->vm_map.pmap;
-	uint64_t base;
-
 	seg &= 0xffff;
-
 	if (seg == 0)
 		return 0;
 
-	off = (seg & 0xfff8);
-	if (seg & SEL_LDT) {
-		if (pmap->pm_ldt != NULL) {
-			len = pmap->pm_ldt_len; /* XXX broken */
-			dt = (char *)pmap->pm_ldt;
-		} else {
-			dt = ldtstore;
-			len = LDT_SIZE;
-		}
-
-		if (off > (len - 8))
-			return EINVAL;
-	} else {
+	if (!(seg & SEL_LDT)) {
 		CTASSERT(GUDATA_SEL & SEL_LDT);
 		KASSERT(seg != GUDATA_SEL);
 		CTASSERT(GUDATA32_SEL & SEL_LDT);
@@ -2026,17 +2009,6 @@ valid_user_selector(struct lwp *l, uint6
 		return EINVAL;
 	}
 
-	sdp = (struct mem_segment_descriptor *)(dt + off);
-	if (sdp->sd_type < SDT_MEMRO || sdp->sd_p == 0)
-		return EINVAL;
-
-	base = ((uint64_t)sdp->sd_hibase << 32) | ((uint64_t)sdp->sd_lobase);
-	if (sdp->sd_gran == 1)
-		base <<= PAGE_SHIFT;
-
-	if (base >= VM_MAXUSER_ADDRESS)
-		return EINVAL;
-
 	return 0;
 }
 

Reply via email to