Hi Theo,

On Fri, Feb 20, 2026, at 16:26, Theo de Raadt wrote:
> Do me a favor and show the precise words where POSIX says this is "bad".
>
> You can use this file:
>
> https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html
>
> Quoting that page:
>
>> When MAP_FIXED is not set, the implementation uses addr in an
>> implementation-defined manner to arrive at pa.
>
> Our implementation-defined manner was chosen after recognizing that
> historically most developers used the hints unsafely, incorrectly, and
> were unintentionally undoing system-default address space randomization
> efforts.
>
> Hyrums law made them think this is a powerful method.
>
>> The pa so chosen shall be an area of the address space that the
>> implementation deems suitable for a mapping of len bytes to the
>> file.
>
> We consider a user recommendation without MAP_FIXED not suitable.

Hmm, this interpretation of that sentence seems like a stretch to me. The 
reason I considered this a bug in the first place is precisely because my 
reading of that sentence does not leave room for the implementation to decide 
that literally nowhere in the address space is suitable just because it does 
not like the address hint.

But, spec interpretation aside, I don't quite follow your argument because if 
you try to mmap() at the same address twice (but below VM_MAXUSER_ADDRESS), the 
kernel will happily ignore the hint in the second mmap() and place the mapping 
nearby instead. So if we go with this line of reasoning, it seems like the 
behavior should at least be made consistent, no? As it stands, this behavior 
only manifesting for addr >= VM_MAXUSER_ADDRESS seems more like an accident, at 
least from my perspective as a user.

It also occurs to me that, if the goal is maximal address space randomization 
while being POSIX-conformant, the more obvious and helpful thing to do would be 
to just always silently ignore addr in the !MAP_FIXED case. That would keep 
programs such as Zig working because our hinting would at worst just be a waste 
of a few instructions to compute the hint, rather than outright breaking us. I 
assume the same would be true of any other program that uses mmap() hints the 
way they're (presumably) intended to be used. (Any program that breaks due to 
addr being ignored in the !MAP_FIXED case is clearly a hopelessly broken 
program anyway, as no OS that I'm aware of gives a hard guarantee about this 
case.)

> Once all allocations are done via mmap(2), and the kernel does all
> process layout strongly random, and ld.so also gets into the game with
> almost no layout limitations, processes should not be placing objects at
> addresses they believe will work.  An address that worked in a previous
> process is not going to work in a new process.

I agree with this of course. That's exactly why we're not using MAP_FIXED; 
we're merely passing a hint and if the kernel does not like it, we're perfectly 
happy to accept its judgement instead. But in this case, the kernel is just 
making us awkwardly have to invoke mmap() a second time with addr=NULL to reset 
our last-known-good address, rather than just doing what I would consider the 
obviously more helpful (and expected) thing of simply ignoring addr and picking 
a better address.

However...

> The address space randomization found on other operating systems is not
> as maximally random as ours.

... are you saying that if I do multiple mmap(NULL, ...) on OpenBSD, I should 
expect the resulting addresses to be sufficiently random as to make our address 
reuse prevention scheme effectively unnecessary anyway? (See clarification 
below.) If so, that would actually be very convenient for us as we could just 
outright disable mmap() hinting on OpenBSD.

>> All implementations interpret an addr value of 0 as granting the
>> implementation complete freedom in selecting pa, subject to
>> constraints described below. A non-zero value of addr is taken to be a
>> suggestion of a process address near which the mapping should be
>> placed. When the implementation selects a value for pa, it never
>> places a mapping at address 0, nor does it replace any extant mapping.
>
> We intentionaly ignore the suggestion, because when we reviewed the body
> of code we found omre bad suggestions than good ones.  By our definition,
> there is almost no way to make a good decision.  The way you want this
> to work fits into that model of a bad idea.  An address taken from a
> previous process runtime is a not a good hint for a new process runtime.

To be clear, we are not trying to reuse an address from a previous process. The 
only thing we're trying to do is (on a best-effort basis) avoid mmap() -> 
munmap() -> mmap() reusing the same address within a process, as this makes it 
much harder to debug use-after-free bugs. (This scheme will, sooner or later, 
hit this ENOMEM case as the hints move closer to the VM_MAXUSER_ADDRESS region 
of the address space.)

Reply via email to