Question: can normal mmap placement leave a small grow-down stack gap?
From: Partha Satapathy
Date: Tue Aug 18 2026 - 06:59:32 EST
Hello,
We are investigating intermittent user-space SIGSEGVs on Oracle Linux 8 UEK:
5.15.0-322.203.3.2.el8uek.x86_64
We realize this is a downstream kernel. We are asking for guidance on the
expected mmap/stack-layout behavior and on a small standalone testcase that
could be run on an equivalent system and on current mainline.
The affected process had:
kernel.randomize_va_space = 2
vm.legacy_va_layout = 0
vm.mmap_rnd_bits = 28
RLIMIT_STACK soft/hard = 32 MiB / 32 MiB
There were no boot parameters disabling ASLR or selecting a special mmap or
stack layout. The process personality was not captured during the incident.
In one failing process, the last librt VMA ended only 308 KiB below the
initial grow-down main-stack VMA:
7ffc2e5fa000-7ffc2e5fb000 r-xp 00208000 fc:07 1572970
/usr/lib64/librt-2.28.so
7ffc2e648000-7ffc2e669000 rw-p 00000000 00:00 0 [stack]
That is:
stack start: 0x7ffc2e648000
librt end: 0x7ffc2e5fb000
gap: 0x4d000 (315,392 bytes; 308 KiB)
fault address: 0x7ffc2e6472a0
%rsp: 0x7ffc2e6472a0
%rbp: 0x7ffc2e649320
fault below stack: 3,424 bytes
szingroup frame setup: sub $0x2058,%rsp
faulting store: mov %rdi,-0x2080(%rbp)
The fault occurs during setup/use of an approximately 8 KiB stack frame, on
an access below the current stack VMA.
We understand that RLIMIT_STACK is a stack-growth limit; it does not reserve
an unmapped 32 MiB range below [stack].
We are also aware that the initial [stack] VMA is not expected to be 32 MiB.
For these processes it is initially about 132 KiB, which is normal: the
kernel expands the grow-down stack on demand, subject to RLIMIT_STACK and
the applicable guard/growth constraints. The concern is not the initial
132 KiB mapping size, but the unusually small gap to the adjacent library
mapping.
In the affected UEK source, stack_guard_gap is initialized as
256UL << PAGE_SHIFT. On this x86-64 system this is 1 MiB, and no
stack_guard_gap= boot override was present. One hypothesis is that the
faulting access required expansion of the grow-down VMA and that expansion
was rejected because the preceding VMA was already within the applicable
stack guard gap.
We do not have a reliable reproducer. We also cannot obtain an exec-time
strace or otherwise instrument the production launcher: the issue is
intermittent and occurs in customer environments. Therefore, we cannot yet
determine how the affected shared object's overall load address was selected:
ordinary non-fixed address selection by the dynamic loader, an address hint,
an earlier reservation followed by MAP_FIXED segment mappings, or some
process-specific personality/launcher action.
We understand that MAP_FIXED calls used by the dynamic loader can be normal
internal ELF-segment construction after an initial reservation. A testcase
that deliberately creates a VMA near [stack] using MAP_FIXED would demonstrate
the expected stack-growth failure, but would not explain how the library
mapping reached that location.
Could maintainers please advise:
1. With the settings above, should the ordinary mmap(NULL, ...) /
get_unmapped_area() path exclude the effective guard-gap region below a
VM_GROWSDOWN main-stack VMA?
2. Are there known mmap-layout, exec, ELF-loader, or personality paths that
could produce a library VMA substantially less than the 1 MiB guard gap
below [stack] without an explicit fixed mapping or address hint?
3. Can you suggest a small self-contained testcase that repeatedly execs a
dynamically linked program with RLIMIT_STACK=32 MiB and detects whether
normal loader/library mappings can be placed unusually close to [stack]?
A test based on MAP_FIXED alone would not answer this question.
Thanks,
Partha Sarathi Satapathy
partha.satapathy@xxxxxxxxxx