From owner-svn-src-all@freebsd.org Sun Oct 22 08:47:14 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id D6E46E4D409; Sun, 22 Oct 2017 08:47:14 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A17558311D; Sun, 22 Oct 2017 08:47:14 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v9M8lDVH048298; Sun, 22 Oct 2017 08:47:13 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v9M8lDYN048292; Sun, 22 Oct 2017 08:47:13 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201710220847.v9M8lDYN048292@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sun, 22 Oct 2017 08:47:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r324855 - in stable/11/sys: amd64/amd64 amd64/include i386/i386 i386/include X-SVN-Group: stable-11 X-SVN-Commit-Author: kib X-SVN-Commit-Paths: in stable/11/sys: amd64/amd64 amd64/include i386/i386 i386/include X-SVN-Commit-Revision: 324855 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 22 Oct 2017 08:47:15 -0000 Author: kib Date: Sun Oct 22 08:47:13 2017 New Revision: 324855 URL: https://svnweb.freebsd.org/changeset/base/324855 Log: MFC r323772, r324302-r324308, r324310, r324313, r324315, r324326, r324330, r324334, r324354-r324355, r324366, r324432-r324433, r324437-r324439: Fixes and improvements for x86 LDT handling. Modified: stable/11/sys/amd64/amd64/sys_machdep.c stable/11/sys/amd64/include/proc.h stable/11/sys/i386/i386/machdep.c stable/11/sys/i386/i386/swtch.s stable/11/sys/i386/i386/sys_machdep.c stable/11/sys/i386/include/md_var.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/amd64/amd64/sys_machdep.c ============================================================================== --- stable/11/sys/amd64/amd64/sys_machdep.c Sun Oct 22 08:42:01 2017 (r324854) +++ stable/11/sys/amd64/amd64/sys_machdep.c Sun Oct 22 08:47:13 2017 (r324855) @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -64,7 +65,7 @@ __FBSDID("$FreeBSD$"); #define MAX_LD 8192 -int max_ldt_segment = 1024; +int max_ldt_segment = 512; SYSCTL_INT(_machdep, OID_AUTO, max_ldt_segment, CTLFLAG_RDTUN, &max_ldt_segment, 0, "Maximum number of allowed LDT segments in the single address space"); @@ -80,11 +81,6 @@ max_ldt_segment_init(void *arg __unused) } SYSINIT(maxldt, SI_SUB_VM_CONF, SI_ORDER_ANY, max_ldt_segment_init, NULL); -#ifdef notyet -#ifdef SMP -static void set_user_ldt_rv(struct vmspace *vmsp); -#endif -#endif static void user_ldt_derefl(struct proc_ldt *pldt); #ifndef _SYS_SYSPROTO_H_ @@ -428,18 +424,14 @@ done: * Update the GDT entry pointing to the LDT to point to the LDT of the * current process. */ -void +static void set_user_ldt(struct mdproc *mdp) { - critical_enter(); *PCPU_GET(ldt) = mdp->md_ldt_sd; lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); - critical_exit(); } -#ifdef notyet -#ifdef SMP static void set_user_ldt_rv(struct vmspace *vmsp) { @@ -451,8 +443,6 @@ set_user_ldt_rv(struct vmspace *vmsp) set_user_ldt(&td->td_proc->p_md); } -#endif -#endif struct proc_ldt * user_ldt_alloc(struct proc *p, int force) @@ -494,11 +484,13 @@ user_ldt_alloc(struct proc *p, int force) sizeof(struct user_segment_descriptor)); user_ldt_derefl(pldt); } + critical_enter(); ssdtosyssd(&sldt, &p->p_md.md_ldt_sd); - atomic_store_rel_ptr((volatile uintptr_t *)&mdp->md_ldt, - (uintptr_t)new_ldt); - if (p == curproc) - set_user_ldt(mdp); + atomic_thread_fence_rel(); + mdp->md_ldt = new_ldt; + critical_exit(); + smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, NULL, + p->p_vmspace); return (mdp->md_ldt); } @@ -516,10 +508,13 @@ user_ldt_free(struct thread *td) return; } + critical_enter(); mdp->md_ldt = NULL; + atomic_thread_fence_rel(); bzero(&mdp->md_ldt_sd, sizeof(mdp->md_ldt_sd)); if (td == curthread) lldt(GSEL(GNULL_SEL, SEL_KPL)); + critical_exit(); user_ldt_deref(pldt); } @@ -550,57 +545,57 @@ user_ldt_deref(struct proc_ldt *pldt) * the OS-specific one. */ int -amd64_get_ldt(td, uap) - struct thread *td; - struct i386_ldt_args *uap; +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=%d num=%d descs=%p\n", + 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 - 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 * + pldt = td->td_proc->p_md.md_ldt; + if (pldt == NULL || uap->start >= max_ldt_segment || uap->num == 0) { + td->td_retval[0] = 0; + return (0); + } + num = min(uap->num, max_ldt_segment - uap->start); + 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 -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; + u_int largest_ld, i; + int error; #ifdef DEBUG - printf("amd64_set_ldt: start=%d num=%d descs=%p\n", + printf("amd64_set_ldt: start=%u num=%u 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; @@ -618,10 +613,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++) + ((volatile uint64_t *)(pldt->ldt_base))[i] = 0; mtx_unlock(&dt_lock); return (0); } @@ -658,12 +652,7 @@ amd64_set_ldt(td, uap, descs) case SDT_SYSNULL4: case SDT_SYSIGT: case SDT_SYSTGT: - /* I can't think of any reason to allow a user proc - * to create a segment of these types. They are - * for OS use only. - */ return (EACCES); - /*NOTREACHED*/ /* memory segment types */ case SDT_MEMEC: /* memory execute only conforming */ @@ -689,7 +678,6 @@ amd64_set_ldt(td, uap, descs) break; default: return(EINVAL); - /*NOTREACHED*/ } /* Only user (ring-3) descriptors may be present. */ @@ -743,14 +731,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; + volatile 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 = (volatile uint64_t *)(pldt->ldt_base); + src = (volatile uint64_t *)descs; + for (i = 0; i < num; i++) + dst[start + i] = src[i]; return (0); } Modified: stable/11/sys/amd64/include/proc.h ============================================================================== --- stable/11/sys/amd64/include/proc.h Sun Oct 22 08:42:01 2017 (r324854) +++ stable/11/sys/amd64/include/proc.h Sun Oct 22 08:47:13 2017 (r324855) @@ -88,7 +88,6 @@ struct syscall_args { (char *)&td; \ } while (0) -void set_user_ldt(struct mdproc *); struct proc_ldt *user_ldt_alloc(struct proc *, int); void user_ldt_free(struct thread *); void user_ldt_deref(struct proc_ldt *); Modified: stable/11/sys/i386/i386/machdep.c ============================================================================== --- stable/11/sys/i386/i386/machdep.c Sun Oct 22 08:42:01 2017 (r324854) +++ stable/11/sys/i386/i386/machdep.c Sun Oct 22 08:47:13 2017 (r324855) @@ -1146,6 +1146,15 @@ exec_setregs(struct thread *td, struct image_params *i else mtx_unlock_spin(&dt_lock); + /* + * Reset the fs and gs bases. The values from the old address + * space do not make sense for the new program. In particular, + * gsbase might be the TLS base for the old program but the new + * program has no TLS now. + */ + set_fsbase(td, 0); + set_gsbase(td, 0); + bzero((char *)regs, sizeof(struct trapframe)); regs->tf_eip = imgp->entry_addr; regs->tf_esp = stack; Modified: stable/11/sys/i386/i386/swtch.s ============================================================================== --- stable/11/sys/i386/i386/swtch.s Sun Oct 22 08:42:01 2017 (r324854) +++ stable/11/sys/i386/i386/swtch.s Sun Oct 22 08:47:13 2017 (r324855) @@ -283,6 +283,10 @@ sw1: pushl %edx /* Preserve pointer to pcb. */ addl $P_MD,%eax /* Pointer to mdproc is arg. */ pushl %eax + /* + * Holding dt_lock prevents context switches, so dt_lock cannot + * be held now and set_user_ldt() will not deadlock acquiring it. + */ call set_user_ldt addl $4,%esp popl %edx Modified: stable/11/sys/i386/i386/sys_machdep.c ============================================================================== --- stable/11/sys/i386/i386/sys_machdep.c Sun Oct 22 08:42:01 2017 (r324854) +++ stable/11/sys/i386/i386/sys_machdep.c Sun Oct 22 08:47:13 2017 (r324855) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -68,10 +69,10 @@ __FBSDID("$FreeBSD$"); #define NULL_LDT_BASE ((caddr_t)NULL) #ifdef SMP -static void set_user_ldt_rv(struct vmspace *vmsp); +static void set_user_ldt_rv(void *arg); #endif static int i386_set_ldt_data(struct thread *, int start, int num, - union descriptor *descs); + union descriptor *descs); static int i386_ldt_grow(struct thread *td, int len); void @@ -90,6 +91,37 @@ fill_based_sd(struct segment_descriptor *sdp, uint32_t sdp->sd_gran = 1; } +/* + * Construct special descriptors for "base" selectors. Store them in + * the PCB for later use by cpu_switch(). Store them in the GDT for + * more immediate use. The GDT entries are part of the current + * context. Callers must load related segment registers to complete + * setting up the current context. + */ +void +set_fsbase(struct thread *td, uint32_t base) +{ + struct segment_descriptor sd; + + fill_based_sd(&sd, base); + critical_enter(); + td->td_pcb->pcb_fsd = sd; + PCPU_GET(fsgs_gdt)[0] = sd; + critical_exit(); +} + +void +set_gsbase(struct thread *td, uint32_t base) +{ + struct segment_descriptor sd; + + fill_based_sd(&sd, base); + critical_enter(); + td->td_pcb->pcb_gsd = sd; + PCPU_GET(fsgs_gdt)[1] = sd; + critical_exit(); +} + #ifndef _SYS_SYSPROTO_H_ struct sysarch_args { int op; @@ -110,7 +142,7 @@ sysarch(td, uap) struct i386_get_xfpustate xfpu; } kargs; uint32_t base; - struct segment_descriptor sd, *sdp; + struct segment_descriptor *sdp; AUDIT_ARG_CMD(uap->op); @@ -155,8 +187,6 @@ sysarch(td, uap) if ((error = copyin(uap->parms, &kargs.largs, sizeof(struct i386_ldt_args))) != 0) return (error); - if (kargs.largs.num > MAX_LD || kargs.largs.num <= 0) - return (EINVAL); break; case I386_GET_XFPUSTATE: if ((error = copyin(uap->parms, &kargs.xfpu, @@ -167,14 +197,15 @@ sysarch(td, uap) break; } - switch(uap->op) { + switch (uap->op) { case I386_GET_LDT: error = i386_get_ldt(td, &kargs.largs); break; case I386_SET_LDT: if (kargs.largs.descs != NULL) { - lp = (union descriptor *)malloc( - kargs.largs.num * sizeof(union descriptor), + if (kargs.largs.num > MAX_LD) + return (EINVAL); + lp = malloc(kargs.largs.num * sizeof(union descriptor), M_TEMP, M_WAITOK); error = copyin(kargs.largs.descs, lp, kargs.largs.num * sizeof(union descriptor)); @@ -206,16 +237,11 @@ sysarch(td, uap) error = copyin(uap->parms, &base, sizeof(base)); if (error == 0) { /* - * Construct a descriptor and store it in the pcb for - * the next context switch. Also store it in the gdt - * so that the load of tf_fs into %fs will activate it - * at return to userland. + * Construct the special descriptor for fsbase + * and arrange for doreti to load its selector + * soon enough. */ - fill_based_sd(&sd, base); - critical_enter(); - td->td_pcb->pcb_fsd = sd; - PCPU_GET(fsgs_gdt)[0] = sd; - critical_exit(); + set_fsbase(td, base); td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); } break; @@ -228,15 +254,11 @@ sysarch(td, uap) error = copyin(uap->parms, &base, sizeof(base)); if (error == 0) { /* - * Construct a descriptor and store it in the pcb for - * the next context switch. Also store it in the gdt - * because we have to do a load_gs() right now. + * Construct the special descriptor for gsbase. + * The selector is loaded immediately, since we + * normally only reload %gs on context switches. */ - fill_based_sd(&sd, base); - critical_enter(); - td->td_pcb->pcb_gsd = sd; - PCPU_GET(fsgs_gdt)[1] = sd; - critical_exit(); + set_gsbase(td, base); load_gs(GSEL(GUGS_SEL, SEL_UPL)); } break; @@ -385,41 +407,40 @@ done: * Update the GDT entry pointing to the LDT to point to the LDT of the * current process. Manage dt_lock holding/unholding autonomously. */ -void -set_user_ldt(struct mdproc *mdp) +static void +set_user_ldt_locked(struct mdproc *mdp) { struct proc_ldt *pldt; - int dtlocked; + int gdt_idx; - dtlocked = 0; - if (!mtx_owned(&dt_lock)) { - mtx_lock_spin(&dt_lock); - dtlocked = 1; - } + mtx_assert(&dt_lock, MA_OWNED); pldt = mdp->md_ldt; -#ifdef SMP - gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd; -#else - gdt[GUSERLDT_SEL].sd = pldt->ldt_sd; -#endif + gdt_idx = GUSERLDT_SEL; + gdt_idx += PCPU_GET(cpuid) * NGDT; /* always 0 on UP */ + gdt[gdt_idx].sd = pldt->ldt_sd; lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL)); - if (dtlocked) - mtx_unlock_spin(&dt_lock); } +void +set_user_ldt(struct mdproc *mdp) +{ + + mtx_lock_spin(&dt_lock); + set_user_ldt_locked(mdp); + mtx_unlock_spin(&dt_lock); +} + #ifdef SMP static void -set_user_ldt_rv(struct vmspace *vmsp) +set_user_ldt_rv(void *arg) { - struct thread *td; + struct proc *p; - td = curthread; - if (vmsp != td->td_proc->p_vmspace) - return; - - set_user_ldt(&td->td_proc->p_md); + p = curproc; + if (arg == p->p_vmspace) + set_user_ldt(&p->p_md); } #endif @@ -433,8 +454,7 @@ user_ldt_alloc(struct mdproc *mdp, int len) mtx_assert(&dt_lock, MA_OWNED); mtx_unlock_spin(&dt_lock); - new_ldt = malloc(sizeof(struct proc_ldt), - M_SUBPROC, M_WAITOK); + new_ldt = malloc(sizeof(struct proc_ldt), M_SUBPROC, M_WAITOK); new_ldt->ldt_len = len = NEW_MAX_LD(len); new_ldt->ldt_base = (caddr_t)kmem_malloc(kernel_arena, @@ -464,10 +484,11 @@ user_ldt_alloc(struct mdproc *mdp, int len) void user_ldt_free(struct thread *td) { - struct mdproc *mdp = &td->td_proc->p_md; + struct mdproc *mdp; struct proc_ldt *pldt; mtx_assert(&dt_lock, MA_OWNED); + mdp = &td->td_proc->p_md; if ((pldt = mdp->md_ldt) == NULL) { mtx_unlock_spin(&dt_lock); return; @@ -503,61 +524,55 @@ user_ldt_deref(struct proc_ldt *pldt) * the OS-specific one. */ int -i386_get_ldt(td, uap) - struct thread *td; - struct i386_ldt_args *uap; +i386_get_ldt(struct thread *td, struct i386_ldt_args *uap) { - int error = 0; struct proc_ldt *pldt; - int nldt, num; - union descriptor *lp; + char *data; + u_int nldt, num; + int error; -#ifdef DEBUG - printf("i386_get_ldt: start=%d num=%d descs=%p\n", +#ifdef DEBUG + printf("i386_get_ldt: start=%u num=%u descs=%p\n", uap->start, uap->num, (void *)uap->descs); #endif + num = min(uap->num, MAX_LD); + data = malloc(num * sizeof(union descriptor), M_TEMP, M_WAITOK); mtx_lock_spin(&dt_lock); - if ((pldt = td->td_proc->p_md.md_ldt) != NULL) { - nldt = pldt->ldt_len; - lp = &((union descriptor *)(pldt->ldt_base))[uap->start]; - mtx_unlock_spin(&dt_lock); - num = min(uap->num, nldt); + pldt = td->td_proc->p_md.md_ldt; + nldt = pldt != NULL ? pldt->ldt_len : nitems(ldt); + if (uap->start >= nldt) { + num = 0; } else { - mtx_unlock_spin(&dt_lock); - nldt = sizeof(ldt)/sizeof(ldt[0]); - num = min(uap->num, nldt); - lp = &ldt[uap->start]; + num = min(num, nldt - uap->start); + bcopy(pldt != NULL ? + &((union descriptor *)(pldt->ldt_base))[uap->start] : + &ldt[uap->start], data, num * sizeof(union descriptor)); } - - if ((uap->start > (unsigned int)nldt) || - ((unsigned int)num > (unsigned int)nldt) || - ((unsigned int)(uap->start + num) > (unsigned int)nldt)) - return(EINVAL); - - error = copyout(lp, uap->descs, num * sizeof(union descriptor)); - if (!error) + mtx_unlock_spin(&dt_lock); + error = copyout(data, uap->descs, num * sizeof(union descriptor)); + if (error == 0) td->td_retval[0] = num; - - return(error); + free(data, M_TEMP); + return (error); } int -i386_set_ldt(td, uap, descs) - struct thread *td; - struct i386_ldt_args *uap; - union descriptor *descs; +i386_set_ldt(struct thread *td, struct i386_ldt_args *uap, + union descriptor *descs) { - int error = 0, i; - int largest_ld; - struct mdproc *mdp = &td->td_proc->p_md; + struct mdproc *mdp; struct proc_ldt *pldt; union descriptor *dp; + u_int largest_ld, i; + int error; -#ifdef DEBUG - printf("i386_set_ldt: start=%d num=%d descs=%p\n", +#ifdef DEBUG + printf("i386_set_ldt: start=%u num=%u descs=%p\n", uap->start, uap->num, (void *)uap->descs); #endif + error = 0; + mdp = &td->td_proc->p_md; if (descs == NULL) { /* Free descriptors */ @@ -569,8 +584,6 @@ i386_set_ldt(td, uap, descs) uap->start = NLDT; uap->num = MAX_LD - NLDT; } - if (uap->num == 0) - return (EINVAL); mtx_lock_spin(&dt_lock); if ((pldt = mdp->md_ldt) == NULL || uap->start >= pldt->ldt_len) { @@ -580,19 +593,18 @@ 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); } - if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) { + if (uap->start != LDT_AUTO_ALLOC || uap->num != 1) { /* verify range of descriptors to modify */ largest_ld = uap->start + uap->num; - if (uap->start >= MAX_LD || largest_ld > MAX_LD) { + if (uap->start >= MAX_LD || largest_ld > MAX_LD) return (EINVAL); - } } /* Check descriptors for access violations */ @@ -618,12 +630,7 @@ i386_set_ldt(td, uap, descs) case SDT_SYS386TGT: /* system 386 trap gate */ case SDT_SYS286CGT: /* system 286 call gate */ case SDT_SYS386CGT: /* system 386 call gate */ - /* I can't think of any reason to allow a user proc - * to create a segment of these types. They are - * for OS use only. - */ return (EACCES); - /*NOTREACHED*/ /* memory segment types */ case SDT_MEMEC: /* memory execute only conforming */ @@ -648,12 +655,11 @@ i386_set_ldt(td, uap, descs) case SDT_MEMERA: /* memory execute read accessed */ break; default: - return(EINVAL); - /*NOTREACHED*/ + return (EINVAL); } /* Only user (ring-3) descriptors may be present. */ - if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL)) + if (dp->sd.sd_p != 0 && dp->sd.sd_dpl != SEL_UPL) return (EACCES); } @@ -704,27 +710,37 @@ 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); } static int i386_ldt_grow(struct thread *td, int len) { - struct mdproc *mdp = &td->td_proc->p_md; + struct mdproc *mdp; struct proc_ldt *new_ldt, *pldt; - caddr_t old_ldt_base = NULL_LDT_BASE; - int old_ldt_len = 0; + caddr_t old_ldt_base; + int old_ldt_len; mtx_assert(&dt_lock, MA_OWNED); @@ -733,6 +749,10 @@ i386_ldt_grow(struct thread *td, int len) if (len < NLDT + 1) len = NLDT + 1; + mdp = &td->td_proc->p_md; + old_ldt_base = NULL_LDT_BASE; + old_ldt_len = 0; + /* Allocate a user ldt. */ if ((pldt = mdp->md_ldt) == NULL || len > pldt->ldt_len) { new_ldt = user_ldt_alloc(mdp, len); @@ -774,10 +794,10 @@ i386_ldt_grow(struct thread *td, int len) * to acquire it. */ mtx_unlock_spin(&dt_lock); - smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, - NULL, td->td_proc->p_vmspace); + smp_rendezvous(NULL, set_user_ldt_rv, NULL, + td->td_proc->p_vmspace); #else - set_user_ldt(&td->td_proc->p_md); + set_user_ldt_locked(&td->td_proc->p_md); mtx_unlock_spin(&dt_lock); #endif if (old_ldt_base != NULL_LDT_BASE) { Modified: stable/11/sys/i386/include/md_var.h ============================================================================== --- stable/11/sys/i386/include/md_var.h Sun Oct 22 08:42:01 2017 (r324854) +++ stable/11/sys/i386/include/md_var.h Sun Oct 22 08:47:13 2017 (r324855) @@ -66,6 +66,8 @@ void init_AMD_Elan_sc520(void); vm_paddr_t kvtop(void *addr); void panicifcpuunsupported(void); void ppro_reenable_apic(void); +void set_fsbase(struct thread *td, uint32_t base); +void set_gsbase(struct thread *td, uint32_t base); void setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int selec); union savefpu *get_pcb_user_save_td(struct thread *td); union savefpu *get_pcb_user_save_pcb(struct pcb *pcb);