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;

Reply via email to