Author: kib
Date: Sat Dec 27 23:19:08 2014
New Revision: 276322
URL: https://svnweb.freebsd.org/changeset/base/276322

Log:
  Change the way the lcall $7,$0 is reflected to usermode.  Instead of
  setting call gate, which must be 64 bit, put a code segment descriptor
  into ldt slot 0.
  
  This way, syscall shim does not switch temporary to 64bit trampoline,
  and does not create a window where signal delivery interrupts 64 bit
  mode (signal handler cannot return).  The cost is shim running with
  non-zero based segment in %cs, which requires vfork() handling make
  more assumptions.
  
  Sponsored by: The FreeBSD Foundation
  MFC after:    1 week

Modified:
  head/sys/amd64/ia32/ia32_sigtramp.S
  head/sys/amd64/ia32/ia32_syscall.c

Modified: head/sys/amd64/ia32/ia32_sigtramp.S
==============================================================================
--- head/sys/amd64/ia32/ia32_sigtramp.S Sat Dec 27 21:50:47 2014        
(r276321)
+++ head/sys/amd64/ia32/ia32_sigtramp.S Sat Dec 27 23:19:08 2014        
(r276322)
@@ -86,34 +86,14 @@ ia32_osigcode:
  * executed, we would have a window where the ring 0 code is
  * executed with the wrong gsbase.
  *
- * Instead, reflect the lcall $7,$0 back to ring 3 trampoline
- * which sets up the frame for int $0x80.
+ * Instead, set LDT descriptor 0 as code segment, which reflects
+ * the lcall $7,$0 back to ring 3 trampoline.  The trampoline sets up
+ * the frame for int $0x80.
  */
        ALIGN_TEXT
 lcall_tramp:
-       .code64
-       /*
-        * There, we are in 64bit mode and need to return to 32bit.
-        * First, convert call frame from 64 to 32 bit format.
-        */
-       pushq   %rax
-       movl    16(%rsp),%eax
-       movl    %eax,20(%rsp)   /* ret %cs */
-       movl    8(%rsp),%eax
-       movl    %eax,16(%rsp)   /* ret %rip -> %eip */
-       popq    %rax
-       addq    $8,%rsp
-       /* Now return to 32bit */
-       pushq   $0x33 /* _ucode32sel UPL */
-       callq   1f
-1:
-       addq    $2f-1b,(%rsp)
-       lretq
-2:
-       /* Back in 32bit mode */
-       .code32
        cmpl    $SYS_vfork,%eax
-       je      4f
+       je      1f
        pushl   %ebp
        movl    %esp,%ebp
        pushl   0x24(%ebp) /* arg 6 */
@@ -122,21 +102,20 @@ lcall_tramp:
        pushl   0x18(%ebp)
        pushl   0x14(%ebp)
        pushl   0x10(%ebp) /* arg 1 */
-       pushl   0xc(%ebp)  /* gap */
+       subl    $4,%esp   /* gap */
        int     $0x80
        leavel
-3:
        lretl
-4:
+1:
        /*
         * vfork handling is special and relies on the libc stub saving
-        * the return ip in %ecx.  If vfork failed, then there is no
-        * child which can corrupt the frame created by call gate.
+        * the return ip in %ecx.  Also, we assume that the call was done
+        * with ucode32 selector in %cs.
         */
        int     $0x80
-       jb      3b
-       addl    $8,%esp
-       jmpl    *%ecx
+       movl    $0x33,4(%esp)   /* GUCODE32_SEL | SEL_UPL */
+       movl    %ecx,(%esp)
+       lretl
 #endif
 
        ALIGN_TEXT

Modified: head/sys/amd64/ia32/ia32_syscall.c
==============================================================================
--- head/sys/amd64/ia32/ia32_syscall.c  Sat Dec 27 21:50:47 2014        
(r276321)
+++ head/sys/amd64/ia32/ia32_syscall.c  Sat Dec 27 23:19:08 2014        
(r276322)
@@ -223,39 +223,28 @@ int
 setup_lcall_gate(void)
 {
        struct i386_ldt_args uap;
-       struct user_segment_descriptor descs[2];
-       struct gate_descriptor *ssd;
+       struct user_segment_descriptor desc;
        uint32_t lcall_addr;
        int error;
 
        bzero(&uap, sizeof(uap));
        uap.start = 0;
-       uap.num = 2;
-
-       /*
-        * This is the easiest way to cut the space for system
-        * descriptor in ldt.  Manually adjust the descriptor type to
-        * the call gate later.
-        */
-       bzero(&descs[0], sizeof(descs));
-       descs[0].sd_type = SDT_SYSNULL;
-       descs[1].sd_type = SDT_SYSNULL;
-       error = amd64_set_ldt(curthread, &uap, descs);
+       uap.num = 1;
+       lcall_addr = curproc->p_sysent->sv_psstrings - sz_lcall_tramp;
+       bzero(&desc, sizeof(desc));
+       desc.sd_type = SDT_MEMERA;
+       desc.sd_dpl = SEL_UPL;
+       desc.sd_p = 1;
+       desc.sd_def32 = 1;
+       desc.sd_gran = 1;
+       desc.sd_lolimit = 0xffff;
+       desc.sd_hilimit = 0xf;
+       desc.sd_lobase = lcall_addr;
+       desc.sd_hibase = lcall_addr >> 24;
+       error = amd64_set_ldt(curthread, &uap, &desc);
        if (error != 0)
                return (error);
 
-       lcall_addr = curproc->p_sysent->sv_psstrings - sz_lcall_tramp;
-       mtx_lock(&dt_lock);
-       ssd = (struct gate_descriptor *)(curproc->p_md.md_ldt->ldt_base);
-       bzero(ssd, sizeof(*ssd));
-       ssd->gd_looffset = lcall_addr;
-       ssd->gd_hioffset = lcall_addr >> 16;
-       ssd->gd_selector = _ucodesel;
-       ssd->gd_type = SDT_SYSCGT;
-       ssd->gd_dpl = SEL_UPL;
-       ssd->gd_p = 1;
-       mtx_unlock(&dt_lock);
-
        return (0);
 }
 #endif
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to