svn commit: r331839 - stable/11/sys/amd64/ia32
Konstantin Belousov
kib at FreeBSD.org
Sat Mar 31 12:43:08 UTC 2018
Author: kib
Date: Sat Mar 31 12:43:07 2018
New Revision: 331839
URL: https://svnweb.freebsd.org/changeset/base/331839
Log:
MFC r331486:
Improve the lcall $7,$0 syscall emulation on amd64.
Modified:
stable/11/sys/amd64/ia32/ia32_sigtramp.S
stable/11/sys/amd64/ia32/ia32_syscall.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/amd64/ia32/ia32_sigtramp.S
==============================================================================
--- stable/11/sys/amd64/ia32/ia32_sigtramp.S Sat Mar 31 11:38:16 2018 (r331838)
+++ stable/11/sys/amd64/ia32/ia32_sigtramp.S Sat Mar 31 12:43:07 2018 (r331839)
@@ -78,44 +78,23 @@ ia32_osigcode:
1:
jmp 1b
-
/*
- * The lcall $7,$0 emulator cannot use the call gate that does an
- * inter-privilege transition. The reason is that the call gate
- * does not disable interrupts, and, before the swapgs is
- * executed, we would have a window where the ring 0 code is
- * executed with the wrong gsbase.
+ * Our lcall $7,$0 handler remains in user mode (ring 3), since lcalls
+ * don't change the interrupt mask, so if this one went directly to the
+ * kernel then there would be a window with interrupts enabled in kernel
+ * mode, and all interrupt handlers would have to be almost as complicated
+ * as the NMI handler to support this.
*
- * 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.
+ * Instead, convert the lcall to an int0x80 call. The kernel does most
+ * of the conversion by popping the lcall return values off the user
+ * stack and returning to them instead of to here, except when the
+ * conversion itself fails. Adjusting the stack here is impossible for
+ * vfork() and harder for other syscalls.
*/
ALIGN_TEXT
lcall_tramp:
- cmpl $SYS_vfork,%eax
- je 1f
- pushl %ebp
- movl %esp,%ebp
- pushl 0x24(%ebp) /* arg 6 */
- pushl 0x20(%ebp)
- pushl 0x1c(%ebp)
- pushl 0x18(%ebp)
- pushl 0x14(%ebp)
- pushl 0x10(%ebp) /* arg 1 */
- subl $4,%esp /* gap */
int $0x80
- leavel
- lretl
-1:
- /*
- * vfork handling is special and relies on the libc stub saving
- * the return ip in %ecx. Also, we assume that the call was done
- * with ucode32 selector in %cs.
- */
- int $0x80
- movl $0x33,4(%esp) /* GUCODE32_SEL | SEL_UPL */
- movl %ecx,(%esp)
- lretl
+1: jmp 1b
#endif
ALIGN_TEXT
Modified: stable/11/sys/amd64/ia32/ia32_syscall.c
==============================================================================
--- stable/11/sys/amd64/ia32/ia32_syscall.c Sat Mar 31 11:38:16 2018 (r331838)
+++ stable/11/sys/amd64/ia32/ia32_syscall.c Sat Mar 31 12:43:07 2018 (r331839)
@@ -114,10 +114,38 @@ ia32_fetch_syscall_args(struct thread *td)
caddr_t params;
u_int32_t args[8], tmp;
int error, i;
+#ifdef COMPAT_43
+ u_int32_t eip;
+ int cs;
+#endif
p = td->td_proc;
frame = td->td_frame;
sa = &td->td_sa;
+
+#ifdef COMPAT_43
+ if (__predict_false(frame->tf_cs == 7 && frame->tf_rip == 2)) {
+ /*
+ * In lcall $7,$0 after int $0x80. Convert the user
+ * frame to what it would be for a direct int 0x80 instead
+ * of lcall $7,$0, by popping the lcall return address.
+ */
+ error = fueword32((void *)frame->tf_rsp, &eip);
+ if (error == -1)
+ return (EFAULT);
+ cs = fuword16((void *)(frame->tf_rsp + sizeof(u_int32_t)));
+ if (cs == -1)
+ return (EFAULT);
+
+ /*
+ * Unwind in-kernel frame after all stack frame pieces
+ * were successfully read.
+ */
+ frame->tf_rip = eip;
+ frame->tf_cs = cs;
+ frame->tf_rsp += 2 * sizeof(u_int32_t);
+ }
+#endif
params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t);
sa->code = frame->tf_rax;
More information about the svn-src-stable-11
mailing list