> From: "Theo de Raadt" <[email protected]>
> Date: Fri, 20 Feb 2026 08:26:15 -0700
>
> Alex Rønne Petersen <[email protected]> wrote:
>
> > Hi,
> >
> > Running the attached C program results in this output:
> >
> > $ uname -mprsv
> > OpenBSD 7.8 GENERIC.MP#1 amd64 amd64
> > $ cc bug.c
> > $ ./a.out
> > 0xffffffffffffffff (Cannot allocate memory)
> >
> > By my reading of POSIX, this seems bad;
>
> 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.
>
> 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.
>
> The address space randomization found on other operating systems is not
> as maximally random as ours.
>
> > 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.
That's not what we do. We respect the hint. If I modify the program
the ask for 0x7f7ffc000, and that address isn't in use, II get exactly
that adress.
I'm pretty sure we discussed/tried ignoring the hint completely at
some point (in the non-MAP_FIXED case). But IIRC that caused issues
with some javascript engine that wanted to use the top bits of a
pointer to store type information.
At some point we discussed perturbing the hint with some random
offset, but I don't think that was ever implemented. Maybe because
pivots were going to do that in a better way?
What Alex is pointing out is that if you pass a hint that exceeds some
MD-specific limit you get ENOMEM. I agree that's a bug.
This happens because when uvm_map_findspace() invokes the address
selectors for the map all of them fail to find a suitable address
because the hint is outside the bounds of the map. Maybe we should
set the hint to zero and retry if that happens?
Diff below implements that. This fixes the bug.
Index: uvm/uvm_map.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.c,v
diff -u -p -r1.354 uvm_map.c
--- uvm/uvm_map.c 11 Feb 2026 22:34:40 -0000 1.354
+++ uvm/uvm_map.c 20 Feb 2026 18:38:49 -0000
@@ -657,6 +657,7 @@ uvm_map_findspace(struct vm_map *map, st
struct uvm_addr_state *uaddr;
int i;
+retry:
/*
* Allocation for sz bytes at any address,
* using the addr selectors in order.
@@ -674,6 +675,11 @@ uvm_map_findspace(struct vm_map *map, st
if (uvm_addr_invoke(map, uaddr, first, last,
addr, sz, pmap_align, pmap_offset, prot, hint) == 0)
return 0;
+
+ if (hint != 0) {
+ hint = 0;
+ goto retry;
+ }
return ENOMEM;
}