Re: git: 95f773e59482 - main - i386 copyout_fast: improve detection of a fault on accessing userspace
Date: Thu, 08 Sep 2022 16:36:26 UTC
On Thu, 8 Sep 2022 14:49:09 +0200 Tijl Coosemans <tijl@FreeBSD.org> wrote: > My patch adds a trylock after cli and an unlock before sti. If the > trylock fails panic("") is called. I put the lock at the base of the > trampoline stack so it's per cpu. The code between cli and sti is > supposed to be uninterruptible so the trylock should never fail, but it > does! Somehow there's a context switch to another thread that calls > copyout or copyin while the first thread was still busy copying when it > was switched out. This corrupts the trampoline stack and/or copyout_buf > of the first thread. I managed to find such a pair of threads. This is the first thread calling copyin, handling a page fault and handling an interrupt on top of the page fault: (kgdb) thread 202 [Switching to thread 202 (Thread 101397)] (kgdb) bt #0 0x009c55b6 in sched_switch (td=0x1a7fb000, flags=1538) at /home/tijl/freebsd/base/main/sys/kern/sched_4bsd.c:1099 #1 0x009abada in mi_switch (flags=1538) at /home/tijl/freebsd/base/main/sys/kern/kern_synch.c:545 #2 0x009a9d60 in critical_exit_preempt () at /home/tijl/freebsd/base/main/sys/kern/kern_switch.c:245 #3 0x0097507e in critical_exit () at /home/tijl/freebsd/base/main/sys/sys/systm.h:196 #4 0x00974fde in intr_event_handle (ie=0x4858e00, frame=0x1b076844) at /home/tijl/freebsd/base/main/sys/kern/kern_intr.c:1470 #5 0x00b7a86e in intr_execute_handlers (isrc=0xc8270c <atintrs+224>, frame=0x1b076844) at /home/tijl/freebsd/base/main/sys/x86/x86/intr_machdep.c:357 #6 0x00bad840 in atpic_handle_intr (vector=4, frame=0x1b076844) at /home/tijl/freebsd/base/main/sys/x86/isa/atpic.c:553 #7 0xffc03845 in ?? () #8 0x00000004 in ?? () #9 0x1b076844 in ?? () (kgdb) info sym 0xffc03845-setidt_disp Xatpic_intr4_pti + 197 in section .text of /boot/kernel/kernel Further backtrace reconstructed with "frame view": #0 sse2_pagezero () at /home/tijl/freebsd/base/main/sys/i386/i386/support.s:56 56 movnti %ebx,(%ecx) #0 0x00b9aef5 in pagezero () at /home/tijl/freebsd/base/main/sys/i386/i386/pmap.c:4497 4497 sse2_pagezero(page); #0 pmap_nopae_zero_page () at /home/tijl/freebsd/base/main/sys/i386/i386/pmap.c:4524 4524 *cmap_pte2 = 0; #0 0x00b94bb1 in pmap_zero_page () at /home/tijl/freebsd/base/main/sys/i386/i386/pmap_base.c:668 668 pmap_methods_ptr->pm_zero_page(m); #0 0x00b31f02 in vm_fault_zerofill () at /home/tijl/freebsd/base/main/sys/vm/vm_fault.c:1114 1114 pmap_zero_page(fs->m); #0 0x00b31453 in vm_fault () at /home/tijl/freebsd/base/main/sys/vm/vm_fault.c:1602 1602 vm_fault_zerofill(&fs); #0 0x00b311c4 in vm_fault_trap () at /home/tijl/freebsd/base/main/sys/vm/vm_fault.c:683 683 result = vm_fault(map, trunc_page(vaddr), fault_type, fault_flags, #0 0x00ba7829 in trap_pfault () at /home/tijl/freebsd/base/main/sys/i386/i386/trap.c:849 849 rv = vm_fault_trap(map, eva, ftype, VM_FAULT_NORMAL, signo, ucode); #0 0x00ba6ec4 in trap () at /home/tijl/freebsd/base/main/sys/i386/i386/trap.c:474 474 (void)trap_pfault(frame, false, eva, NULL, NULL); (kgdb) x/3x 0x1b076a84 0x1b076a84: 0x1b076a90 0xffc031ff 0x1b076a90 (kgdb) info sym 0xffc031ff-setidt_disp calltrap + 8 in section .text of /boot/kernel/kernel (kgdb) p/x *(struct trapframe *)0x1b076a90 $47 = {tf_fs = 0x8, tf_es = 0x28, tf_ds = 0x28, tf_edi = 0xe25c000, tf_esi = 0xffc04f80, tf_ebp = 0x1b076adc, tf_isp = 0x1b076abc, tf_ebx = 0x141e000, tf_edx = 0xb8da80, tf_ecx = 0x1, tf_eax = 0x1b076ad0, tf_trapno = 0xc, tf_err = 0x2, tf_eip = 0xffc04362, tf_cs = 0x20, tf_eflags = 0x210017, tf_esp = 0xffbfc5a0, tf_ss = 0x1} (kgdb) info sym 0xffc04362-setidt_disp copyin_fast + 106 in section .text of /boot/kernel/kernel (kgdb) frame view 0x1b076adc 0xffc04362-setidt_disp #0 0x00b8da62 in copyin_fast () at /home/tijl/freebsd/base/main/sys/i386/i386/copyout_fast.s:133 133 rep; movsb (kgdb) disas 0xffc04362-setidt_disp Dump of assembler code for function copyin_fast: 0x00b8d9f8 <+0>: push %ebp 0x00b8d9f9 <+1>: mov %esp,%ebp 0x00b8d9fb <+3>: push %esi 0x00b8d9fc <+4>: push %edi 0x00b8d9fd <+5>: push %ebx 0x00b8d9fe <+6>: mov 0x14(%ebp),%ebx 0x00b8da01 <+9>: mov %fs:0x10,%eax 0x00b8da07 <+15>: mov 0x44(%eax),%edx 0x00b8da0a <+18>: mov 0x10(%ebp),%ecx 0x00b8da0d <+21>: mov 0x8(%ebp),%esi 0x00b8da10 <+24>: cli 0x00b8da11 <+25>: mov %fs:0x120,%edi 0x00b8da18 <+32>: mov $0xdeadc0de,%eax 0x00b8da1d <+37>: xchg %eax,-0xff0(%edi) 0x00b8da23 <+43>: cmp $0xdeadc0de,%eax 0x00b8da28 <+48>: jne 0xb8da36 <copyin_fast+62> 0x00b8da2a <+50>: push $0xb8da7d 0x00b8da2f <+55>: mov $0x9a20b0,%eax 0x00b8da34 <+60>: call *%eax 0x00b8da36 <+62>: mov %fs:0x194,%edi 0x00b8da3d <+69>: mov %esp,%eax 0x00b8da3f <+71>: mov %fs:0x120,%esp 0x00b8da46 <+78>: mov %edx,%cr3 0x00b8da49 <+81>: mov $0xb8da80,%edx 0x00b8da4e <+86>: rep movsb %ds:(%esi),%es:(%edi) 0x00b8da50 <+88>: mov %ebx,%cr3 0x00b8da53 <+91>: mov %eax,%esp 0x00b8da55 <+93>: mov 0x10(%ebp),%ecx 0x00b8da58 <+96>: mov 0xc(%ebp),%edi 0x00b8da5b <+99>: mov %fs:0x194,%esi 0x00b8da62 <+106>: rep movsb %ds:(%esi),%es:(%edi) 0x00b8da64 <+108>: mov %fs:0x120,%edi 0x00b8da6b <+115>: movl $0x0,-0xff0(%edi) 0x00b8da75 <+125>: sti 0x00b8da76 <+126>: xor %eax,%eax 0x00b8da78 <+128>: pop %ebx 0x00b8da79 <+129>: pop %edi 0x00b8da7a <+130>: pop %esi 0x00b8da7b <+131>: leave 0x00b8da7c <+132>: ret 0x00b8da7d <+133>: add %ah,-0x70(%esi) End of assembler dump. #0 0x00b89208 in copyin () at /home/tijl/freebsd/base/main/sys/i386/i386/copyout.c:215 215 copyin_fast_tramp(udaddr, kaddr, len, pmap_get_kcr3()) == 0)) #0 0x009ea24e in uiomove_faultflag () at /home/tijl/freebsd/base/main/sys/kern/subr_uio.c:255 255 error = copyin(iov->iov_base, cp, cnt); #0 0x009ea1a3 in uiomove () at /home/tijl/freebsd/base/main/sys/kern/subr_uio.c:198 198 return (uiomove_faultflag(cp, n, uio, 0)); #0 0x009f2ae0 in pipe_write () at /home/tijl/freebsd/base/main/sys/kern/sys_pipe.c:1252 1252 error = uiomove(&wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in], #0 0x009f1dc4 in fo_write () at /home/tijl/freebsd/base/main/sys/sys/file.h:349 349 return ((*fp->f_ops->fo_write)(fp, uio, active_cred, flags, td)); #0 0x009efac9 in dofilewrite () at /home/tijl/freebsd/base/main/sys/kern/sys_generic.c:565 565 if ((error = fo_write(fp, auio, td->td_ucred, flags, td))) { #0 0x009ef8cb in kern_writev () at /home/tijl/freebsd/base/main/sys/kern/sys_generic.c:492 492 error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0); #0 0x009ef880 in sys_write () at /home/tijl/freebsd/base/main/sys/kern/sys_generic.c:407 407 error = kern_writev(td, uap->fd, &auio); #0 0x00ba7c00 in syscallenter () at /home/tijl/freebsd/base/main/sys/i386/i386/../../kern/subr_syscall.c:189 189 error = (se->sy_call)(td, sa->args); #0 syscall () at /home/tijl/freebsd/base/main/sys/i386/i386/trap.c:1137 1137 if ((orig_tf_eflags & PSL_T) && !(orig_tf_eflags & PSL_VM)) { This is the second thread calling copyout: (kgdb) thread 192 [Switching to thread 192 (Thread 101428)] (kgdb) bt #0 0x009a1dfd in dump_savectx () at /home/tijl/freebsd/base/main/sys/kern/kern_shutdown.c:404 #1 0x009a1e77 in doadump (textdump=0) at /home/tijl/freebsd/base/main/sys/kern/kern_shutdown.c:434 #2 0x008d1194 in db_dump (dummy=10315780, dummy2=false, dummy3=-1, dummy4=0x1b0bc850 "") at /home/tijl/freebsd/base/main/sys/ddb/db_command.c:593 #3 0x008d0f41 in db_command (last_cmdp=<optimized out>, cmd_table=<optimized out>, dopager=true) at /home/tijl/freebsd/base/main/sys/ddb/db_command.c:506 #4 0x008d0ddc in db_command_loop () at /home/tijl/freebsd/base/main/sys/ddb/db_command.c:553 #5 0x008d3b00 in db_trap (type=3, code=0) at /home/tijl/freebsd/base/main/sys/ddb/db_main.c:270 #6 0x009d6b89 in kdb_trap (type=3, code=0, tf=0x1b0bca14) at /home/tijl/freebsd/base/main/sys/kern/subr_kdb.c:745 #7 0x00ba6e9e in trap (frame=0x1b0bca14) at /home/tijl/freebsd/base/main/sys/i386/i386/trap.c:667 #8 0xffc031ff in ?? () #9 0x1b0bca14 in ?? () (kgdb) info sym 0xffc031ff-setidt_disp calltrap + 8 in section .text of /boot/kernel/kernel Reconstructed backtrace: #0 breakpoint () at /home/tijl/freebsd/base/main/sys/i386/include/cpufunc.h:57 57 } #0 kdb_enter () at /home/tijl/freebsd/base/main/sys/kern/subr_kdb.c:509 509 kdb_why = KDB_WHY_UNSET; #0 0x009a21e6 in vpanic () at /home/tijl/freebsd/base/main/sys/kern/kern_shutdown.c:966 966 kdb_enter(KDB_WHY_PANIC, "panic"); #0 0x009a20c4 in panic () at /home/tijl/freebsd/base/main/sys/kern/kern_shutdown.c:903 903 vpanic(fmt, ap); #0 0x00b8d9af in copyout_fast () at /home/tijl/freebsd/base/main/sys/i386/i386/copyout_fast.s:65 65 movl PCPU(COPYOUT_BUF),%edi Dump of assembler code for function copyout_fast: 0x00b8d970 <+0>: push %ebp 0x00b8d971 <+1>: mov %esp,%ebp 0x00b8d973 <+3>: push %esi 0x00b8d974 <+4>: push %edi 0x00b8d975 <+5>: push %ebx 0x00b8d976 <+6>: mov 0x14(%ebp),%ebx 0x00b8d979 <+9>: mov %fs:0x10,%edx 0x00b8d980 <+16>: mov 0x44(%edx),%edx 0x00b8d983 <+19>: mov 0x10(%ebp),%ecx 0x00b8d986 <+22>: mov 0x8(%ebp),%esi 0x00b8d989 <+25>: cli 0x00b8d98a <+26>: mov %fs:0x120,%edi 0x00b8d991 <+33>: mov $0xdeadc0de,%eax 0x00b8d996 <+38>: xchg %eax,-0xff0(%edi) 0x00b8d99c <+44>: cmp $0xdeadc0de,%eax 0x00b8d9a1 <+49>: jne 0xb8d9af <copyout_fast+63> 0x00b8d9a3 <+51>: push $0xb8da7d 0x00b8d9a8 <+56>: mov $0x9a20b0,%eax 0x00b8d9ad <+61>: call *%eax 0x00b8d9af <+63>: mov %fs:0x194,%edi 0x00b8d9b6 <+70>: rep movsb %ds:(%esi),%es:(%edi) 0x00b8d9b8 <+72>: mov 0x10(%ebp),%ecx 0x00b8d9bb <+75>: mov %fs:0x194,%esi 0x00b8d9c2 <+82>: mov 0xc(%ebp),%edi 0x00b8d9c5 <+85>: mov %esp,%eax 0x00b8d9c7 <+87>: mov %fs:0x120,%esp 0x00b8d9ce <+94>: mov %edx,%cr3 0x00b8d9d1 <+97>: mov $0xb8da80,%edx 0x00b8d9d6 <+102>: rep movsb %ds:(%esi),%es:(%edi) 0x00b8d9d8 <+104>: mov %ebx,%cr3 0x00b8d9db <+107>: mov %eax,%esp 0x00b8d9dd <+109>: mov %fs:0x120,%edi 0x00b8d9e4 <+116>: movl $0x0,-0xff0(%edi) 0x00b8d9ee <+126>: sti 0x00b8d9ef <+127>: xor %eax,%eax 0x00b8d9f1 <+129>: pop %ebx 0x00b8d9f2 <+130>: pop %edi 0x00b8d9f3 <+131>: pop %esi 0x00b8d9f4 <+132>: leave 0x00b8d9f5 <+133>: ret End of assembler dump. #0 0x00b892f8 in copyout () at /home/tijl/freebsd/base/main/sys/i386/i386/copyout.c:250 250 copyout_fast_tramp(kaddr, udaddr, len, pmap_get_kcr3()) == 0)) #0 0x009f177c in pollout () at /home/tijl/freebsd/base/main/sys/kern/sys_generic.c:1687 1687 error = copyout(&fds->revents, &ufds->revents, #0 0x009f1233 in kern_poll () at /home/tijl/freebsd/base/main/sys/kern/sys_generic.c:1607 1607 error = pollout(td, kfds, ufds, nfds); #0 0x009f1194 in sys_poll () at /home/tijl/freebsd/base/main/sys/kern/sys_generic.c:1485 1485 return (kern_poll(td, uap->fds, uap->nfds, tsp, NULL)); #0 0x00ba7c00 in syscallenter () at /home/tijl/freebsd/base/main/sys/i386/i386/../../kern/subr_syscall.c:189 189 error = (se->sy_call)(td, sa->args); #0 syscall () at /home/tijl/freebsd/base/main/sys/i386/i386/trap.c:1137 1137 if ((orig_tf_eflags & PSL_T) && !(orig_tf_eflags & PSL_VM)) {