Date: Mon, 9 Oct 2017 15:39:43 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r324433 - in head/sys/i386: i386 include Message-ID: <201710091539.v99Fdh4m042224@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Mon Oct 9 15:39:43 2017 New Revision: 324433 URL: https://svnweb.freebsd.org/changeset/base/324433 Log: Reset the fs and gs bases on exec(2). 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. amd64 already handles this correctly. Reported and reviewed by: bde Sponsored by: The FreeBSD Foundation MFC after: 1 week Modified: head/sys/i386/i386/machdep.c head/sys/i386/i386/sys_machdep.c head/sys/i386/include/md_var.h Modified: head/sys/i386/i386/machdep.c ============================================================================== --- head/sys/i386/i386/machdep.c Mon Oct 9 15:24:18 2017 (r324432) +++ head/sys/i386/i386/machdep.c Mon Oct 9 15:39:43 2017 (r324433) @@ -1132,6 +1132,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: head/sys/i386/i386/sys_machdep.c ============================================================================== --- head/sys/i386/i386/sys_machdep.c Mon Oct 9 15:24:18 2017 (r324432) +++ head/sys/i386/i386/sys_machdep.c Mon Oct 9 15:39:43 2017 (r324433) @@ -91,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; @@ -109,7 +140,7 @@ sysarch(struct thread *td, struct sysarch_args *uap) struct i386_get_xfpustate xfpu; } kargs; uint32_t base; - struct segment_descriptor sd, *sdp; + struct segment_descriptor *sdp; AUDIT_ARG_CMD(uap->op); @@ -204,16 +235,11 @@ sysarch(struct thread *td, struct sysarch_args *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; @@ -226,15 +252,11 @@ sysarch(struct thread *td, struct sysarch_args *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; Modified: head/sys/i386/include/md_var.h ============================================================================== --- head/sys/i386/include/md_var.h Mon Oct 9 15:24:18 2017 (r324432) +++ head/sys/i386/include/md_var.h Mon Oct 9 15:39:43 2017 (r324433) @@ -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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201710091539.v99Fdh4m042224>