glibc weighs a switch to refuse binaries that cannot use ASLR
The Node.js Brotli decoder buffer overflow (CVE-2026-111497) has led to a discussion of Linux program loading. The official Linux binaries of Node.js were compiled in such a way that address space layout randomization (ASLR) wasn't effective, making the overflow easier to exploit. As per the LWN article, the glibc folks are now debating adding tunables to deny execution of programs that can't be randomized. The change is a small one to the dynamic linker, but the effect is huge: it changes a recommendation in the build process to a necessity at runtime.
And the interesting bit, which is why this isn't just a Node.js fix, is the way it works. ASLR isn't just a kernel feature. It's about how the executable is linked. A non-position-independent executable (non-PIE) can lock down its own code at a fixed address, whether the kernel wants it or not. If the loader can detect that and block, it can close a long-standing door, one that most distributions have only fixed by rebuilding their own packages.
What ASLR actually randomizes
ASLR randomizes the base address for the memory regions used by the process. This includes the code of the executable, shared libraries like libc, the stack, the heap, and the mmap region. ASLR isn't to hide memory. It's to ensure that the address of any given function/data structure is unknown when the process starts, so an attacker who corrupts memory can't easily jump to a target.
This is especially important for return-oriented programming, the standard way to break the "no executable stack" protection that's now standard on all modern systems. ROP is about piecing together short sequences of instructions (gadgets) that already exist either in the program or in the libraries. The gadgets end with a return. So the attacker creates a stack of return addresses. But the attacker needs to know the locations of those gadgets to make that work. ASLR breaks that knowledge.
ASLR is entropy. And entropy can run out. If an attacker can leak a pointer, they can often calculate the slide for the entire region and break the randomization for that process. If the entropy is low, they can brute force the address by crashing and trying again. This is feasible for a service that restarts quickly. So ASLR is a layer, not a guarantee. It increases the cost of exploitation. It's most useful when paired with a build that doesn't give the attacker a static address.
Why a non-PIE binary defeats the protection
A position-independent executable is compiled and linked in a way that allows the code to be loaded with any base address. When the loader loads it, it picks a random base address and applies the relocations. And the program runs. A non-PIE executable is linked for a specific load address. Usually a low address that's selected at build time. But the kernel can still randomize the stack, heap, and shared libraries. The main executable's code is at the address the linker set.
The static address is a boon to an exploit developer. Because the offsets inside the binary are static, you can access a gadget inside the program without having to leak anything. Sure, if you want to call something in libc, you still need to know where libc is. But there are a lot of useful primitives, like stack pivots and register gadgets, in the main binary. And a non-PIE binary makes partial overwrites and fixed-address jumps much easier.
Node.js is a good example. The overflow was in the Brotli decoder, a parser that processes untrusted compressed data. The official binaries weren't PIE. So even if you had ASLR turned on, the mapping for the main executable was known. This doesn't mean the bug is exploitable. You still have to consider what can be overwritten by the overflow, and what other mitigations are in the rest of the binary. But it's a big hurdle. And it means the ASLR setting in the distro is a false sense of security.
From overflow to code execution
A buffer overflow is a write past the end of the allocation. If the memory that's overwritten has a return address or a function pointer or a length that later gets used for a copy, then you can hijack control flow. The old way is: corrupt a return address. Make it point to a ROP gadget. Chain gadgets to call execve or to make memory executable.
With ASLR+PIE, all the above steps need to be done with knowledge that the attacker doesn't have. They first need to leak something. Then they need to calculate the slide. Then they need to build the chain against the actual addresses. For a non-PIE main binary, the first two steps are collapsed for gadgets in the executable. The attacker can often piece together a chain that pivots the stack into a buffer they control. Then calls something in a function whose address is derived from leaking a single library pointer. The bug is the same. But the cost of exploitation is very different.
This is why the glibc discussion is about build flags, not the Brotli bug. Fixing the decoder just fixes one overflow. Making binaries randomized means you're breaking a class of easy exploits for all future bugs in the same program. The loader can't fix unsafe C. But it can deny execution of code that opts out of a security feature the OS claims to provide.
What a dynamic-linker tunable can and cannot enforce
Glibc dynamic linker has tunables via GLIBC_TUNABLES. This is a way to configure library behavior at the start of the process. A tunable to deny non-PIE executables would be checked before the entry point of the program is run. If it's not position-independent, the loader would issue a diagnostic and exit. This is good. The failure is early. Loud. And easy to blame. This is what you want for a security feature.
But there are limits. You can't have a tunable that checks whether the program was compiled with stack protectors or fortify sources or control flow integrity. You can't check for a logic bug or an authorization bug or an injection bug. All you can do is ask: can this executable be loaded at a random base address? This is a narrow property. But it's a prerequisite for ASLR to work for the main binary. And it's cheap to check.
And there's the compatibility issue. Denying execution of a program is a hard failure. And a hard failure in the loader could affect a login session or an init system or a recovery shell if it's too broad. You'd have to have permissive mode or an allowlist or a slow rollout for any deployment. The discussion is about giving an admin a tool. Not about defaulting to it everywhere on day one.
Why the Node.js case is the trigger
Node.js is a good test case for this idea. It's widely used. Often exposed to untrusted data. And it's prebuilt binaries from an upstream project, not just distros. A distro can rebuild Node.js with whatever flags they want. If you download the official tarball, you get what the release process gave you. If it's non-PIE, your hardened kernel and hardened libc won't help for the main executable.
That's the supply chain problem in a nutshell. Your security hardening is only as good as the least hardened binary on the chain. It's a really bad place to lose the property for a language runtime. Because it's hosting application code. And because it's parsing a ton of attacker-controlled data. The Brotli decoder is just one of many parsers. The next bug might be in the HTTP parser. Or the TLS stack. Or a native add-on.
The idea with glibc is it's checking at the point of load. So the OS can see the properties of the binary, regardless of who built it. It doesn't require Node.js to change their release process. But it would put pressure on them to do that. It doesn't require all distros to rebuild all packages before the protection kicks in. It gives the admin a switch. "On this system, we don't allow execution of code that can't be randomized."
The ecosystem problem
The reason it's a discussion and not a feature that's shipping is because the Linux ecosystem is diverse. There's limited support for PIE on some architectures. There are old binaries that can't be rebuilt because the source is lost. There's proprietary executables from vendors that will never be relinked. So if you did something like a blanket denial, it would break those cases. And the folks who use those are often the least able to fix them.
With a tunable, you avoid the blanket mandate by making it local. So an admin running an internet facing service can turn it on. An admin running a legacy appliance can leave it off. That's a reasonable compromise. But that also means the protection only goes as far as the folks who know to turn it on. Defaults are important. The discussion needs to figure out what the default should be for new distros.There's a similar story for other things controlled at the loader level: fs.suid_dumpable in the kernel, noexec mount option, a bunch of mmap_min_addr knobs... these are all features that limit your attack surface at the cost of some compatibility. They're not all on by default because they're problematic. This would be one of those features, and it'd be a very sharp knife in the hands of people who can afford to be that strict.
The long-term solution is good build practices. By and large, distros are now defaulting to PIE. It's the easy way to build with modern toolchains. The remaining non-PIE binaries are mostly the ones that slipped through the cracks: upstream pre-built things, legacy vendor blobs, and stuff that's built with custom build systems. A loader check lets you see where the cracks are. It doesn't fix the cracks -- but it prevents them from being silently exploitable. It also gives packagers a clear list of things that need fixing.
What administrators should watch
If this tunable gets added, the next question is how to adopt it in a way that doesn't break stuff. The obvious way is to turn it on for new, well-understood systems. Internet-facing services, containers with a known base image, build hosts that you never want to have a legacy blob run on. When it refuses to load, you get a nice clear error. So it's easy to figure out what happened and easily fix it by unsetting the tunable.
Packagers, on the other hand, need to verify that everything they distribute is position-independent. And they need a policy for the things that aren't. Some of the things might be old but harmless. Some of them might be security-sensitive, and they'd better be rebuilt or abandoned. A loader check lets packagers see where the holes are. Because the program that won't load is a program that needs some attention.
The worst thing would be to have something that breaks recovery environments by default. If your rescue shell won't start because it's not non-PIE, that's going to be a nightmare. It's going to give the feature a black eye before it can help us. Any rollout should exclude the tools that are there to fix broken systems. And it should have documentation with it that explains exactly what's going on with the diagnostic. And how to disable the check.
Conclusion
The glibc tunable discussion is in response to a particular bug, but the argument is more general. The quality of ASLR depends on the quality of the binaries it's applied to. A non-PIE executable is opting out of the defense, but still reaping the benefits of the OS claiming to provide that defense. Allowing the dynamic linker to refuse non-PIE binaries gives admins the ability to enforce this property at load time, regardless of who compiled the program.
This proposal doesn't solve memory safety issues. And it shouldn't be presented as though it does. It's a very specific, cheap check that fills a well-known hole. It forces build issues to the light of day. The challenge is deployment. Choosing defaults. Making sure we don't break recovery environments. Providing a way for legacy software to deal with this. If this gets into glibc with a reasonable opt-in and a clear diagnostic, it's a useful addition to the Linux hardening toolkit. It's a reminder that the loader is part of the security boundary.
Sources
- LWN, coverage of the glibc ASLR tunable proposal (11 November 2026): https://lwn.net/Articles/1105134/
- Node.js security releases for CVE-2026-111497: https://nodejs.org/en/blog/vulnerability
- glibc tunables documentation: https://www.gnu.org/software/libc/manual/html_node/Tunables.html