Author: kib
Date: Thu Apr 12 20:43:39 2018
New Revision: 332454
URL: https://svnweb.freebsd.org/changeset/base/332454

Log:
  Fix PSL_T inheritance on exec for x86.
  
  The miscellaneous x86 sysent->sv_setregs() implementations tried to
  migrate PSL_T from the previous program to the new executed one, but
  they evaluated regs->tf_eflags after the whole regs structure was
  bzeroed.  Make this functional by saving PSL_T value before zeroing.
  
  Note that if the debugger is not attached, executing the first
  instruction in the new program with PSL_T set results in SIGTRAP, and
  since all intercepted signals are reset to default dispostion on
  exec(2), this means that non-debugged process gets killed immediately
  if PSL_T is inherited.  In particular, since suid images drop
  P_TRACED, attempt to set PSL_T for execution of such program would
  kill the process.
  
  Another issue with userspace PSL_T handling is that it is reset by
  trap().  It is reasonable to clear PSL_T when entering SIGTRAP
  handler, to allow the signal to be handled without recursion or
  delivery of blocked fault.  But it is not reasonable to return back to
  the normal flow with PSL_T cleared.  This is too late to change, I
  think.
  
  Discussed with:       bde, Ali Mashtizadeh
  Sponsored by: The FreeBSD Foundation
  MFC after:    3 weeks
  Differential revision:        https://reviews.freebsd.org/D14995

Modified:
  head/sys/amd64/amd64/machdep.c
  head/sys/amd64/ia32/ia32_signal.c
  head/sys/amd64/linux/linux_sysvec.c
  head/sys/amd64/linux32/linux32_sysvec.c
  head/sys/i386/i386/machdep.c

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c      Thu Apr 12 20:27:57 2018        
(r332453)
+++ head/sys/amd64/amd64/machdep.c      Thu Apr 12 20:43:39 2018        
(r332454)
@@ -581,9 +581,13 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_
 void
 exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-       struct trapframe *regs = td->td_frame;
-       struct pcb *pcb = td->td_pcb;
+       struct trapframe *regs;
+       struct pcb *pcb;
+       register_t saved_rflags;
 
+       regs = td->td_frame;
+       pcb = td->td_pcb;
+
        if (td->td_proc->p_md.md_ldt != NULL)
                user_ldt_free(td);
 
@@ -593,11 +597,12 @@ exec_setregs(struct thread *td, struct image_params *i
        clear_pcb_flags(pcb, PCB_32BIT);
        pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
 
+       saved_rflags = regs->tf_rflags & PSL_T;
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_rip = imgp->entry_addr;
        regs->tf_rsp = ((stack - 8) & ~0xFul) + 8;
        regs->tf_rdi = stack;           /* argv */
-       regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+       regs->tf_rflags = PSL_USER | saved_rflags;
        regs->tf_ss = _udatasel;
        regs->tf_cs = _ucodesel;
        regs->tf_ds = _udatasel;

Modified: head/sys/amd64/ia32/ia32_signal.c
==============================================================================
--- head/sys/amd64/ia32/ia32_signal.c   Thu Apr 12 20:27:57 2018        
(r332453)
+++ head/sys/amd64/ia32/ia32_signal.c   Thu Apr 12 20:43:39 2018        
(r332454)
@@ -936,9 +936,13 @@ freebsd32_sigreturn(td, uap)
 void
 ia32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-       struct trapframe *regs = td->td_frame;
-       struct pcb *pcb = td->td_pcb;
+       struct trapframe *regs;
+       struct pcb *pcb;
+       register_t saved_rflags;
 
+       regs = td->td_frame;
+       pcb = td->td_pcb;
+
        if (td->td_proc->p_md.md_ldt != NULL)
                user_ldt_free(td);
 #ifdef COMPAT_43
@@ -949,10 +953,11 @@ ia32_setregs(struct thread *td, struct image_params *i
        pcb->pcb_gsbase = 0;
        pcb->pcb_initial_fpucw = __INITIAL_FPUCW_I386__;
 
+       saved_rflags = regs->tf_rflags & PSL_T;
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_rip = imgp->entry_addr;
        regs->tf_rsp = stack;
-       regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+       regs->tf_rflags = PSL_USER | saved_rflags;
        regs->tf_ss = _udatasel;
        regs->tf_cs = _ucode32sel;
        regs->tf_rbx = imgp->ps_strings;

Modified: head/sys/amd64/linux/linux_sysvec.c
==============================================================================
--- head/sys/amd64/linux/linux_sysvec.c Thu Apr 12 20:27:57 2018        
(r332453)
+++ head/sys/amd64/linux/linux_sysvec.c Thu Apr 12 20:43:39 2018        
(r332454)
@@ -404,9 +404,13 @@ linux_copyout_strings(struct image_params *imgp)
 static void
 linux_exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-       struct trapframe *regs = td->td_frame;
-       struct pcb *pcb = td->td_pcb;
+       struct trapframe *regs;
+       struct pcb *pcb;
+       register_t saved_rflags;
 
+       regs = td->td_frame;
+       pcb = td->td_pcb;
+
        if (td->td_proc->p_md.md_ldt != NULL)
                user_ldt_free(td);
 
@@ -416,10 +420,11 @@ linux_exec_setregs(struct thread *td, struct image_par
        pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
        set_pcb_flags(pcb, PCB_FULL_IRET);
 
+       saved_rflags = regs->tf_rflags & PSL_T;
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_rip = imgp->entry_addr;
        regs->tf_rsp = stack;
-       regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+       regs->tf_rflags = PSL_USER | saved_rflags;
        regs->tf_ss = _udatasel;
        regs->tf_cs = _ucodesel;
        regs->tf_ds = _udatasel;

Modified: head/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- head/sys/amd64/linux32/linux32_sysvec.c     Thu Apr 12 20:27:57 2018        
(r332453)
+++ head/sys/amd64/linux32/linux32_sysvec.c     Thu Apr 12 20:43:39 2018        
(r332454)
@@ -719,7 +719,11 @@ linux_exec_setregs(struct thread *td, struct image_par
 {
        struct trapframe *regs = td->td_frame;
        struct pcb *pcb = td->td_pcb;
+       register_t saved_rflags;
 
+       regs = td->td_frame;
+       pcb = td->td_pcb;
+
        if (td->td_proc->p_md.md_ldt != NULL)
                user_ldt_free(td);
 
@@ -731,10 +735,11 @@ linux_exec_setregs(struct thread *td, struct image_par
        critical_exit();
        pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
 
+       saved_rflags = regs->tf_rflags & PSL_T;
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_rip = imgp->entry_addr;
        regs->tf_rsp = stack;
-       regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+       regs->tf_rflags = PSL_USER | saved_rflags;
        regs->tf_gs = _ugssel;
        regs->tf_fs = _ufssel;
        regs->tf_es = _udatasel;

Modified: head/sys/i386/i386/machdep.c
==============================================================================
--- head/sys/i386/i386/machdep.c        Thu Apr 12 20:27:57 2018        
(r332453)
+++ head/sys/i386/i386/machdep.c        Thu Apr 12 20:43:39 2018        
(r332454)
@@ -1104,9 +1104,13 @@ sys_sigreturn(td, uap)
 void
 exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-       struct trapframe *regs = td->td_frame;
-       struct pcb *pcb = td->td_pcb;
+       struct trapframe *regs;
+       struct pcb *pcb;
+       register_t saved_eflags;
 
+       regs = td->td_frame;
+       pcb = td->td_pcb;
+
        /* Reset pc->pcb_gs and %gs before possibly invalidating it. */
        pcb->pcb_gs = _udatasel;
        load_gs(_udatasel);
@@ -1127,10 +1131,11 @@ exec_setregs(struct thread *td, struct image_params *i
        set_gsbase(td, 0);
 
        /* Make sure edx is 0x0 on entry. Linux binaries depend on it. */
+       saved_eflags = regs->tf_eflags & PSL_T;
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_eip = imgp->entry_addr;
        regs->tf_esp = stack;
-       regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T);
+       regs->tf_eflags = PSL_USER | saved_eflags;
        regs->tf_ss = _udatasel;
        regs->tf_ds = _udatasel;
        regs->tf_es = _udatasel;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to