]> xenbits.xensource.com Git - people/royger/freebsd.git/commitdiff
amd64: Avoid enabling interrupts when handling kernel mode prot faults
authorMark Johnston <markj@FreeBSD.org>
Mon, 31 May 2021 22:49:33 +0000 (18:49 -0400)
committerMark Johnston <markj@FreeBSD.org>
Mon, 31 May 2021 22:49:33 +0000 (18:49 -0400)
When PTI is enabled, we may have been on the trampoline stack when iret
faults.  So, we have to switch back to the regular stack before
re-entering trap().

trap() has the somewhat strange behaviour of re-enabling interrupts when
handling certain kernel-mode execeptions.  In particular, it was doing
this for exceptions raised during execution of iret.  When switching
away from the trampoline stack, however, the thread must not be migrated
to a different CPU.  Fix the problem by simply leaving interrupts
disabled during the window.

Reported by: syzbot+6cfa544fd86ad4647ffc@syzkaller.appspotmail.com
Reported by: syzbot+cfdfc9e5a8f28f11a7f5@syzkaller.appspotmail.com
Reviewed by: kib
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D30578

sys/amd64/amd64/trap.c

index 4ce31ce47a45bdb3d02775e48cf17315964603d1..cc0b8fcf6c1703f1ac735b42a6edc1acf25ff05c 100644 (file)
@@ -236,25 +236,31 @@ trap(struct trapframe *frame)
                 * interrupts disabled until they are accidentally
                 * enabled later.
                 */
-               if (TRAPF_USERMODE(frame))
+               if (TRAPF_USERMODE(frame)) {
                        uprintf(
                            "pid %ld (%s): trap %d with interrupts disabled\n",
                            (long)curproc->p_pid, curthread->td_name, type);
-               else if (type != T_NMI && type != T_BPTFLT &&
-                   type != T_TRCTRAP) {
-                       /*
-                        * XXX not quite right, since this may be for a
-                        * multiple fault in user mode.
-                        */
-                       printf("kernel trap %d with interrupts disabled\n",
-                           type);
-
-                       /*
-                        * We shouldn't enable interrupts while holding a
-                        * spin lock.
-                        */
-                       if (td->td_md.md_spinlock_count == 0)
-                               enable_intr();
+               } else {
+                       switch (type) {
+                       case T_NMI:
+                       case T_BPTFLT:
+                       case T_TRCTRAP:
+                       case T_PROTFLT:
+                       case T_SEGNPFLT:
+                       case T_STKFLT:
+                               break;
+                       default:
+                               printf(
+                                   "kernel trap %d with interrupts disabled\n",
+                                   type);
+
+                               /*
+                                * We shouldn't enable interrupts while holding a
+                                * spin lock.
+                                */
+                               if (td->td_md.md_spinlock_count == 0)
+                                       enable_intr();
+                       }
                }
        }
 
@@ -444,6 +450,8 @@ trap(struct trapframe *frame)
                         * Magic '5' is the number of qwords occupied by
                         * the hardware trap frame.
                         */
+                       KASSERT((read_rflags() & PSL_I) == 0,
+                           ("interrupts enabled"));
                        if (frame->tf_rip == (long)doreti_iret) {
                                frame->tf_rip = (long)doreti_iret_fault;
                                if ((PCPU_GET(curpmap)->pm_ucr3 !=