Skip site navigation (1)Skip section navigation (2)
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>