Hi,
Rusky wrote:
Brendan wrote:
Of course if you allow processes to use the area at 0x00000000, very few processes will use the area, so it's very unlikely that it'll make any difference to kernel bug/exploit detection.
Unmapping the page at 0x00000000 is a useful exploit mitigation regardless of whether you have any third party code in kernel space, and regardless of whether the code you're protecting runs in kernel or user mode. Really, the fact that kernel code uses null pointers
and shares its address space with user mode means whoever controls 0x00000000 also has a bit of extra control over the kernel.
For example, first-party kernel code that accidentally skipped a null check could wind up reading or writing what it thinks is its own data from user-space controlled memory. Obviously the fix is to stop the kernel from dereferencing potentially-null pointers in the first place, since null pointer dereferences can cause other vulnerabilities (e.g. when the user controls the offset and you're also missing a bounds check). But that doesn't make unmapping 0x00000000 useless- experience shows that there
will be kernel bugs, no matter how competent and experienced the developers are.
Let's do a conservative estimate!
If there's a 0.1% chance that a process actually uses the area at 0x00000000 in the first place, multiplied by a 0.01% chance that the micro-kernel has a NULL pointer bug that isn't detected by other methods (e.g. unit tests, the fact that the data "disappears" when you switch virtual address space, the fact that something in user-space got its code or data trashed, etc); then there'd be a 0.00001% chance that the NULL pointer bug won't be detected if it only happens once, a 0.000005% chance that the NULL pointer bug won't be detected if it only happens twice, and a 0.00000000001% chance that the NULL pointer bug won't be detected if it happens 1 million times (e.g. every time a new process is spawned or something).
More realistically, (for a micro-kernel) it's probably more likely that a shark will be struck by lightning while that shark is biting the computer.
On the other side; if you assume that there's a 0.1% chance that a process uses the area at 0x00000000, then you'd also have to assume that 1 process out of 1000 had a reason for wanting to use the area at 0x00000000, and you'd have to assume that by not allowing a process to use the area at 0x0000000 (when it has a reason to want to use this area) you ruin some kind of potential (performance and/or complexity and/or other) benefit for 1 process out of 1000.
Rusky wrote:
The true solution, aside from exploit mitigation, is an automated and systematic check. For example, the number of null pointer dereference vulnerabilities in safe Java programs is zero- all they can do is terminate the program in a controlled way. You don't have to do it at runtime, either- exclude null as a valid value from pointer types and the compiler will ensure that an attacker can't even cause a NullPointerException.
The true solution is to realise that "NULL" is only one of many possible "bad pointer" values, and NULL pointer checks are only a partial solution to the "bad pointer value" problem. The worst case is a pointer that points to the wrong piece of kernel data (e.g. a pointer that points to "process data for the old process" and not "process data for the new process"), where it still points to kernel data and therefore can't be detectable by any hardware based tricks (not-present pages, SMAP, etc), and could still point to the correct type of data and therefore might not be detectable by compile-time tricks (e.g. type checking) either.
If you solve the full "bad pointer value" problem (e.g. using unit tests, mathematical proofs, etc) you have no reason to care about a small subset of the problem (NULL pointers).
Cheers,
Brendan