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
This commit is contained in:
parent
4f7c931a11
commit
787f835bf0
@ -1132,6 +1132,15 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
|
||||
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;
|
||||
|
@ -91,6 +91,37 @@ fill_based_sd(struct segment_descriptor *sdp, uint32_t base)
|
||||
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;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user