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