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.)
