Prex 0.9.0 suffers from a serious bug in its exception handling code
Thu 17 Mar 2011 10:02 EDT
In our Systems course here at Northeastern, we’re working with Prex as our experimental platform this semester. A recent assignment called for the implementation of some virtual-memory-like features, using Prex’s exceptions to deliver information about faulting memory accesses to the faulting process, which is thereby given an opportunity to arrange for some memory to back the accessed address.
The problem is in the x86 code implementing system call handling for
the exception_return()
system call. The logic for detecting that an
exception_return()
has occurred neglects to take into account the
fact that returning from an exception replaces the active context. The
fix is to check %eax
before calling syscall_handler
.
Without the patch below, %eax
will be smashed in the context of the
code that was interrupted by the exception.
I emailed this patch to the Prex list, but something about my message triggered Sourceforge’s spam detection software, or something equally tedious and annoying, and it hasn’t made its way through yet; so I’m posting this here in the hopes that those in need of it might find it.
Here’s the required change:
--- a/bsp/hal/x86/arch/locore.S
+++ b/bsp/hal/x86/arch/locore.S
@@ -313,11 +313,23 @@ ENTRY(syscall_entry)
pushl $(SYSCALL_INT) /* Trap number */
SAVE_ALL
SETUP_SEG
- call syscall_handler
+ /* We check the saved value of eax here, before calling syscall_handler,
+ because if it's zero (i.e. exception_return), we will completely
+ obliterate the saved registers in context_restore() within
+ exception_return() within syscall_handler(), which will make the value
+ of 0x10(%esp) contain whatever random eax value happened to be around
+ at the time the exception was delivered. For example, if the exn
+ was a page fault, eax could be anything at all. If we check 0x10(%esp)
+ after syscall_handler has returned, it will in the general case contain
+ junk. */
cmpl $0, 0x10(%esp) /* Skip setting eax if exception_return */
je 1f
+ call syscall_handler
movl %eax, 0x10(%esp) /* Set return value to eax */
+ jmp 2f
1:
+ call syscall_handler
+2:
call exception_deliver /* Check exception */
syscall_ret:
RESTORE_ALL