Bug 23323 - [RFE] CSU startup code hardening.
Summary: [RFE] CSU startup code hardening.
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: 2.34
Assignee: Florian Weimer
Depends on:
Reported: 2018-06-21 06:14 UTC by Wade Mealing
Modified: 2021-12-14 19:05 UTC (History)
5 users (show)

See Also:
Last reconfirmed:
fweimer: security-


Note You need to log in before you can comment on or make changes to this bug.
Description Wade Mealing 2018-06-21 06:14:38 UTC

I've been made aware of an ASLR mitigation technique known as "return to CSU".  It builds on the existing idea of ROP gadgets, but instead uses the internal widgets available in __libc_csu_init().

This attack technique is not an exploit in itself but rather removing ROP widgets from predictable locations.   Rather than waste more time, check out the information here, along with suggestions for mitigations/ideas to remove these enabling widgets.



So what I want out of this, I hear you ask.  I defer to the experts on where to go from here, as this is not the area that I would know if any of these mitigations / plans have adverse affects.

It may be possible that the authors have already talked to the glibc maintainers, I did a quick search and wasn't able to find it.

Thanks in advance.

Wade Mealing
Comment 1 Florian Weimer 2018-06-21 06:43:32 UTC
What I don't understand here is why moving the code to libc.so.6 helps.  Wouldn't glibc then contain a very similar sequence?  Certainly you'll need another round of probing to find the base address of glibc, but then you'd be in the same situation again.

We have looked at this code in an entirely different context (because it's compiled with different hardening flags compared to the main executable), so moving it may make sense, but it will make it impossible to run *any* binaries compiled against a newer glibc on an older glibc.

The actual ASLR bypass seems to be due to the forking server not ree-execve-ing itself after it observes a couple of crashing child processes.  That allows you to learn the stack canary and base addresses for the executable and likely some of its libraries as well (and due to the constant offsets between libraries, that gives you the address of all libraries).
Comment 2 Florian Weimer 2018-06-22 11:49:27 UTC
(In reply to Florian Weimer from comment #1)
> What I don't understand here is why moving the code to libc.so.6 helps.

The paper says this:

“Due to the size and complexity of the C library, it is generally considered a huge pool of gadgets. Once the attacker reaches the libc the game is over.”

So it's basically just obfuscation and not a fundamental change.
Comment 3 Florian Weimer 2018-06-24 12:20:40 UTC
I posted a patch:


Flagging as security- because this is just hardening.
Comment 4 Wade Mealing 2018-06-27 07:51:59 UTC
Thanks for the quick response ! patch looks good to me.
Comment 5 Huzaifa Sidhpurwala 2018-09-05 05:07:21 UTC
Any idea if this patch is being reviewed etc? I dont see anything on the mailing list that is why i asked :)
Comment 6 Florian Weimer 2018-09-05 06:28:09 UTC
(In reply to Huzaifa Sidhpurwala from comment #5)
> Any idea if this patch is being reviewed etc? I dont see anything on the
> mailing list that is why i asked :)

There hasn't been a review yet.
Comment 7 Florian Weimer 2021-02-18 13:17:38 UTC
New patch posted: https://sourceware.org/pipermail/libc-alpha/2021-February/122794.html
Comment 8 lvying 2021-03-01 09:20:46 UTC
Hi Florian, Will this patch be synchronized to other glibc versions(glibc 2.28 etc)?
Comment 9 Florian Weimer 2021-03-01 09:44:22 UTC
(In reply to lvying from comment #8)
> Hi Florian, Will this patch be synchronized to other glibc versions(glibc
> 2.28 etc)?

Unfortunately, a change like this is impossible to backport, due to its ABI implications.
Comment 10 Florian Weimer 2021-03-01 09:44:56 UTC
Fixed for glibc 2.34 via:

commit 035c012e32c11e84d64905efaf55e74f704d3668
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Feb 25 12:10:57 2021 +0100

    Reduce the statically linked startup code [BZ #23323]
    It turns out the startup code in csu/elf-init.c has a perfect pair of
    ROP gadgets (see Marco-Gisbert and Ripoll-Ripoll, "return-to-csu: A
    New Method to Bypass 64-bit Linux ASLR").  These functions are not
    needed in dynamically-linked binaries because DT_INIT/DT_INIT_ARRAY
    are already processed by the dynamic linker.  However, the dynamic
    linker skipped the main program for some reason.  For maximum
    backwards compatibility, this is not changed, and instead, the main
    map is consulted from __libc_start_main if the init function argument
    is a NULL pointer.
    For statically linked binaries, the old approach based on linker
    symbols is still used because there is nothing else available.
    A new symbol version __libc_start_main@@GLIBC_2.34 is introduced because
    new binaries running on an old libc would not run their ELF
    constructors, leading to difficult-to-debug issues.