On Wed, 2009-11-04 at 08:38 -0800, John Reiser wrote:
I have three applications that fundamentally fail to work
if mmap(0,PAGE_SIZE,,MAP_FIXED,,) is disallowed. Addressing
memory at address 0 is fundamental to the way that they work.
Using "any other page" would totally prevent two of the apps
from working at all, and would severely cripple the third.
They are not "old [W]indows apps". They are every-day utilities
and development tools written for Linux, and I object to them
being broken.
You're saying you have apps that rely on being able to dereference the
zero page, and _not_ because the processor mode requires it? I thought
the vax died long ago.
The kernel could remove 99.9% of the vulnerability, with
no dynamic cost to processes that don't use page 0, by:
1. Reduce STACK_TOP by one page, and reserve the corresponding
virtual page frame.
2. If a process does mmap(0,,,MAP_FIXED,,) then turn on the
process status bit which forces "slow path" for kernel entry
via system call from that process. In the slow path, check for
a mapping at page 0 and if so then move that mapping to the
reserved page at STACK_TOP, and turn off the mapping at page 0.
Reverse the substitution when returning from the syscall.
3. Add the necessary check in the trap handler for
copy_{to,from}_user() to handle intended kernel access to page 0
(including I/O) by substituting the reserved page instead.
This would allow mmap(0,,,MAP_FIXED,,) yet still protect all
synchronous kernel execution. The only remaining window of
vulnerability is interrupt handlers. If an interrupt handler
is touching *any* user address space then the problems are more
serious than mmap(0).
The problem is that the address space doesn't change when in the
interrupt handler; the zero page will still be mapped, so if there's a
bug in the interrupt handler that would normally oops, well, now it
won't.
Yes, bugs like that _have_ been found. Pretty sure they've been
exploited in the wild too.
You could probably fix this by checking if the zero page is mapped at
any context switch into the kernel (including interrupt) and doing
mprotect(PROT_NONE) on it if so. This adds a small but more or less
fixed overhead on every interrupt, plus a fairly high overhead when an
interrupt fires while the zero-mapping process is running.
- ajax