Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20150405223031.GA29575@brightrain.aerifal.cx>
Date: Sun, 5 Apr 2015 18:30:31 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Dynamic linker changes

As part of the dynamic linker overhaul project for ssp-enabled
libc.so, I'd like to make some somewhat unrelated changes to the
dynamic linker. Some aspects of these are just general improvements,
but most of them eliminate implementation snags I'm forseeing in the
early-relocation code. Anyway, here they are:


Revisiting how we find load base address:

If the dynamic linker is invoked as the PT_INTERP for a program, it
gets its own base address as AT_BASE in auxv. But if it's invoked
directly, AT_BASE is empty, and we presently round down the AT_PHDR
address to a page boundary and assume that's the load base. This is an
ugly hack and not guaranteed to be correct (although it should be with
any reasonable linker).

A better approach is having the asm entry point for the dynamic linker
compute the address of _DYNAMIC using its known PC-relative offset and
pass this into the C code. The C code can then find the base-relative
location of _DYNAMIC via PT_DYNAMIC in the program headers, and the
difference between these two values (absolute address of _DYNAMIC and
base-relative address of _DYNAMIC) is the base.


Revisiting how ld.so skips argv entries:

Presently, when invoked as a command, ld.so uses an ugly hack for
stripping the beginning of argv[] before passing it to the main
program entry point. It replaces slots with (char*)-1 and the calling
asm is responsible for skipping over these before passing execution to
the main program's entry point. This requires a lot of ugly
arch-specific asm, and often this asm does not get tested early on
since invocation of ld.so as a command is not a commonly used feature.

A better approach would be making the C part of the dynamic linker
never return, but instead call longjmp to pass execution to the main
program's entry point. Provided we tell the dynamic linker where the
PC and SP registers are located in jmp_buf, all it needs to do are
store the AT_ENTRY address into the PC slot and the updated start
address of the argv array in the SP slot, then call longjmp.


Stripping down entry point asm further:

Like the way crt_arch.h and crt1.c work for the main program entry
point now, almost all asm can be eliminated from the dynamic linker
entry point. All that's needed is some minimal asm to align SP and put
the original SP value (and now, also the address of _DYNAMIC) in
argument registers/slots and tail-call to the C code. The C code can
be responsible for extracting argc out of the ELF argv array.


Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.