POSIX specifies these error cases for memory faults: SIGSEGV/SEGV_MAPERR: Accessing an unmapped page.
SIGSEGV/SEGV_ACCERR: Reading from a non-readable or writing to a non-writable page. SIGBUS/BUS_ADRERR: Accessing a mapped page that exceeds the end of the underlying mapped file. I added a regress test at regress/sys/kern/siginfo-fault to cover these cases, but unfortunately we're non-compliant in a few ways, and fixing it is somewhat MD. With the diff below, the tests pass on amd64, but other platforms will need similar changes. Currently VM_PAGER_BAD is only returned by pgo_get() in the case of uvn_get() trying to access a page beyond the end of the file, so this diff changes uvm_fault() to recognize this and return ENOSPC (arbitrary unused error code) and then the MD trap() code needs to know to map this error to BUS_ADRERR. Additionally, some MD trap()s already know to map EACCES to SEGV_ACCERR instead of SEGV_MAPERR, but amd64 wasn't one of them. So this diff fixes that too. Index: uvm/uvm_fault.c =================================================================== RCS file: /home/matthew/cvs-mirror/cvs/src/sys/uvm/uvm_fault.c,v retrieving revision 1.73 diff -u -p -r1.73 uvm_fault.c --- uvm/uvm_fault.c 8 May 2014 20:08:50 -0000 1.73 +++ uvm/uvm_fault.c 23 Jun 2014 21:29:24 -0000 @@ -1125,7 +1125,8 @@ Case2: goto ReFault; } - return (EACCES); /* XXX i/o error */ + /* XXX i/o error */ + return (result == VM_PAGER_BAD ? ENOSPC : EACCES); } /* re-verify the state of the world. */ Index: arch/amd64/amd64/trap.c =================================================================== RCS file: /home/matthew/cvs-mirror/cvs/src/sys/arch/amd64/amd64/trap.c,v retrieving revision 1.40 diff -u -p -r1.40 trap.c --- arch/amd64/amd64/trap.c 15 Jun 2014 11:43:24 -0000 1.40 +++ arch/amd64/amd64/trap.c 23 Jun 2014 21:38:31 -0000 @@ -387,9 +387,6 @@ faultcommon: KERNEL_UNLOCK(); goto out; } - if (error == EACCES) { - error = EFAULT; - } if (type == T_PAGEFLT) { if (pcb->pcb_onfault != 0) { @@ -407,13 +404,23 @@ faultcommon: sv.sival_ptr = (void *)fa; trapsignal(p, SIGKILL, T_PAGEFLT, SEGV_MAPERR, sv); } else { + int signo, code; + if (error == ENOSPC) { + signo = SIGBUS; + code = BUS_ADRERR; + } else { + signo = SIGSEGV; + code = (error == EACCES) ? SEGV_ACCERR : + SEGV_MAPERR; + } #ifdef TRAP_SIGDEBUG - printf("pid %d (%s): SEGV at rip %lx addr %lx\n", - p->p_pid, p->p_comm, frame->tf_rip, fa); + printf("pid %d (%s): %s at rip %lx addr %lx\n", + p->p_pid, p->p_comm, (signo == SIGBUS) ? + "BUS" : "SEGV", frame->tf_rip, fa); frame_dump(frame); #endif sv.sival_ptr = (void *)fa; - trapsignal(p, SIGSEGV, T_PAGEFLT, SEGV_MAPERR, sv); + trapsignal(p, signo, T_PAGEFLT, code, sv); } KERNEL_UNLOCK(); break;