This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug dynamic-link/17769] New: The program interpreter should not call static initializers in PIE binaries
- From: "stijnv at gmail dot com" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sourceware dot org
- Date: Sun, 28 Dec 2014 12:51:11 +0000
- Subject: [Bug dynamic-link/17769] New: The program interpreter should not call static initializers in PIE binaries
- Auto-submitted: auto-generated
https://sourceware.org/bugzilla/show_bug.cgi?id=17769
Bug ID: 17769
Summary: The program interpreter should not call static
initializers in PIE binaries
Product: glibc
Version: 2.19
Status: NEW
Keywords: glibc_2.19
Severity: normal
Priority: P2
Component: dynamic-link
Assignee: unassigned at sourceware dot org
Reporter: stijnv at gmail dot com
Hello,
I've been seeing the following problem for a while now. It has been posted on
other bugtrackers, e.g.
https://code.google.com/p/chromium/issues/detail?id=394508 , but even though
this particular bugtracker says the problem is fixed, it is not fixed for me.
Whenever gcc compiles a program as PIE, its ELF type is set to ET_DYN. While
this isn't a problem on its own, it does make ld-linux.so falsely believe that
the program is a shared library. Observe for example the following program:
#include <stdio.h>
void __attribute__((constructor)) pie_init() {
printf("I am a PIE binary and this is my constructor!\n");
}
int main(int argc, char** argv) {
printf("Hello!\n");
return 0;
}
When compiled as PIE and invoked directly I get:
$ gcc -ggdb -o i_like_pie -fPIE -pie i_like_pie.c
$ ./i_like_pie
I am a PIE binary and this is my constructor!
Hello!
This is the expected output. However, when invoked through the interpreter, I
get:
$ /lib/ld-linux.so.2 ./i_like_pie
I am a PIE binary and this is my constructor!
I am a PIE binary and this is my constructor!
Hello!
This is certainly not the correct output. If the program is not compiled as
PIE, I get the same output in both cases (direct invocation and invocation
through the program interpreter). This is hardly surprising, as the call_init
function, which invokes the initializers checks:
/* Check for object which constructors we do not run here. */
if (__builtin_expect (l->l_name[0], 'a') == '\0'
&& l->l_type == lt_executable)
return;
For non-PIE binaries, the l_type is indeed lt_executable. For PIE binaries, the
l_type is lt_library. The root cause for this problem lies in elf/rtld.c. If
the program is loaded directly, the interpreter simply creates the main map as
follows:
/* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */
main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
__RTLD_OPENEXEC, LM_ID_BASE);
However, if the program is interpreter loads the program instead, it does:
_dl_map_object (NULL, rtld_progname, lt_library, 0,
__RTLD_OPENEXEC, LM_ID_BASE);
/* ... */
/* Now the map for the main executable is available. */
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
The problem here is that _dl_map_object will actually read l_type from the ELF
header, wheras dl_new_object will use whatever l_type you pass to it. I see no
reason why l_type shouldn't be set to lt_executable if a program is loaded
indirecty, even if the program you're attempting to load is in fact a shared
library.
The following patch fixes the problem for me:
$ diff -up glibc-2.19.orig/elf/rtld.c glibc-2.19/elf/rtld.c
--- glibc-2.19.orig/elf/rtld.c 2014-12-09 16:38:51.929980899 +0100
+++ glibc-2.19/elf/rtld.c 2014-12-28 13:20:18.613821869 +0100
@@ -1085,6 +1085,11 @@ of this helper program; chances are you
/* Now the map for the main executable is available. */
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ /* Make sure that the type for the main binary is lt_executable,
+ even if it says ET_DYN in the header. This way we won't call the
+ static initializers twice for PIE binaries */
+ main_map->l_type = lt_executable;
+
if (__builtin_expect (mode, normal) == normal
&& GL(dl_rtld_map).l_info[DT_SONAME] != NULL
&& main_map->l_info[DT_SONAME] != NULL
Regards,
Stijn
--
You are receiving this mail because:
You are on the CC list for the bug.