Hacker News new | ask | show | jobs
by iambvk 221 days ago
What is the justification to call `Null pointer dereference` as a memory safety issue?
2 comments

1) Null pointer derefs can sometimes lead to privilege escalation (look up "mapping the zero page", for instance). 2) As I understand it (could be off base), if you're already doing static checking for other memory bugs, eliminating null derefs comes "cheap". In other words, it follows pretty naturally from the systems that provide other memory safety guarantees (such as the famous "borrow checker" employed by Rust).
Both Linux and Windows forbid mapping the zero page.
Thank you.
It's worse than a memory safety issue, it's undefined behaviour (at least in C, C++, and Rust)
UB is in fact not worse than a memory safety issue, and the original question is a good one: NULL pointer dereferences are almost never exploitable, and preventing exploitation is the goal of "memory safety" as conceived of by this post and the articles it references.
> UB is in fact not worse than a memory safety issue

The worst case of UB is worse than the worst case of most kinds of non-UB memory safety issues.

> NULL pointer dereferences are almost never exploitable

Disagree; we've seen enough cases where they become exploitable (usually due to the impact of optimisations) that we can't say "almost never". They may not be the lowest hanging fruit, but they're still too dangerous to be acceptable.

What is the worst case of UB that you're thinking of that is worse than the worst memory safety issue?
Essentially Descartes' evil demon, since there are no limits at all on what UB can do.
Can I ask you to be specific here? The worse memory corruption vulnerabilities enable trivial remote code execution and full and surreptitious reliable takeovers of victim machines. What's a non-memory-corruption UB that has a worse impact? Thanks!

I know we've talked about this before! So I figure you have an answer here.

UB can lead to memory safety issues[0], among other terrible outcomes. Hence it’s worse than memory safety issues.

0: https://lwn.net/Articles/342330/

No, that doesn't hold logically.
I believe the point is if something is UB, like NULL pointer dereference, then the compiler can assume it can't happen and eliminate some other code paths based on that. And that, in turn, could be exploitable.
Yes, that part was clear. The certainty of a vulnerability is worse than the possibility of a vulnerability, and most UB does not in fact produce vulnerabilities.
Doesn't null-pointer-dereference always crash the application?

Is it only an undefined-behavior because program-must-crash is not the explicitly required by these languages' specs?

> Doesn't null-pointer-dereference always crash the application?

No. It's undefined behaviour, it may do anything or nothing.

> Is it only an undefined-behavior because program-must-crash is not the explicitly required by these languages' specs?

I don't understand the question here. It's undefined behaviour because the spec says it's undefined behaviour, which is some combination of because treating it as impossible allows many optimisation opportunities and because of historical accidents.

> No. It's undefined behaviour, it may do anything or nothing.

This is clearly nonsense.

It is not nonsense: see https://lwn.net/Articles/575563/

Compilers are allowed to assume undefined behavior doesn't happen, and dereferencing an invalid pointer is undefined behavior. You don't have to like it, but that's how it is.

> This is clearly nonsense.

It is indeed. Unfortunately it's also the C language standard.

No, it does not always crash. This is a common misconception caused by thinking about the problem on the MMU (hardware) level, where reading a null pointer predictably results in a page fault. If this was the only thing we had to contend with, then yes, it would immediately terminate the process, cutting down the risk of a null pointer dereference to just a crash.

The problem is instead in software - it is undefined behavior, so most compilers may optimize it out and write code that assumes it never happens, which often causes nightmarish silent corruption / control flow issues rather than immediately crashing. These optimizations are common enough for it to be a relatively common failure mode.

There is a bit of nuance that on non-MMU hardware such as microcontrollers and embedded devices, reading null pointers does not actually trigger an error on a hardware level, but instead actually gives you access to the 0 position on memory. This is usually either a feature (because it's a nice place to put global data) or a gigantic pitfall of its own (because it's the most likely place for accidental corruption to cause a serious problem, and reading it inadvertently may reveal sensitive global state).

> No, it does not always crash.

Can you give me an example that I can reproduce?

This crashes, but after doing something unexpected (printing "Wow" 4 times): https://godbolt.org/z/GPc7bEMn5
Only if that memory page is unmapped, and only if the optimizer doesn't detect that it's a null pointer and start deleting verification code because derefing null is UB, and UB is assumed to never happen.
How common is this in practice?
Compilers regularly delete null pointer checks when they can see that the pointer is dereferenced.
(GCC controls this with `-fno-delete-null-pointer-checks` https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#ind... )