🦣 @dalias@hachyderm.io 🦣 Profile picture
Here for the 🍿 as it burns. Come along to the 'don if you want more than popcorn from me.

Nov 4, 2022, 8 tweets

So today #musl discovered a longstanding 🤦🤦🤦 bug in Linux's ELF loader...

For whatever reason, Linux has two copies of the ELF loading code in binfmt_elf.c, one for the main program and the other for the "program interpreter" (dynamic linker). The former handles BSS right but the latter doesn't.

ELF program LOAD segments can have p_memsz>p_filesz, representing a mapping larger in memory than in the image on disk, with the remainder zero-filled (mapping zero paged if needed).

For the main program, Linux handles this fine. But for the interpreter, it only maps p_filesz, not p_memsz. Then, at the very end, it goes back and performs one additional mapping for the remaining "bss" if needed.

This happens to work if there's only one data segment mapping that utilizes p_memsz>p_filesz, or if where the page boundaries fall make it so that no additional mapping is needed.

Unfortunately, lld wants to make multiple LOAD segments with data, one for the GOT and related machinery, and the other for actual program data. In this case, the kernel just doesn't map enough memory for the GOT, and process crashes (in ldso) on entry. 🤦

I think Linux may also be failing to do the right zero-fill (leaving junk mapped from disk present) even when it's not crossing a page boundary. Depending on what the linker did (e.g. if it put data segment before GOT seg rather than after), this could cause severe malfunctions.

The kernel has apparently always had this brokenness, and kernels in the wild will have it for decades to come. So does lld need to stop generating such output? Or should ldso do some workaround on itself in case it was linked this way?

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling