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