* commit 'f3ffb8fa6ecd9db2da19eb3144a5da7724a875bc': Clean up the linker a bit, remove prelinking support.
This commit is contained in:
commit
366c01992a
@ -59,6 +59,10 @@ enum {
|
||||
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int __libc_android_log_write(int prio, const char* tag, const char* buffer);
|
||||
int __libc_android_log_print(int prio, const char *tag, const char *fmt, ...);
|
||||
int __libc_android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap);
|
||||
@ -66,4 +70,8 @@ int __libc_android_log_vprint(int prio, const char *tag, const char *fmt, va_lis
|
||||
void __libc_android_log_event_int(int32_t tag, int value);
|
||||
void __libc_android_log_event_uid(int32_t tag);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _ANDROID_BIONIC_LOGD_H */
|
||||
|
@ -3,13 +3,13 @@ include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
arch/$(TARGET_ARCH)/begin.S \
|
||||
linker.c \
|
||||
debugger.c \
|
||||
dlfcn.c \
|
||||
linker.cpp \
|
||||
linker_environ.c \
|
||||
linker_format.c \
|
||||
linker_phdr.c \
|
||||
rt.c \
|
||||
dlfcn.c \
|
||||
debugger.c
|
||||
rt.c
|
||||
|
||||
LOCAL_LDFLAGS := -shared
|
||||
|
||||
@ -23,15 +23,14 @@ LOCAL_CFLAGS += -fno-stack-protector \
|
||||
#
|
||||
LOCAL_CFLAGS += -DLINKER_DEBUG=0
|
||||
|
||||
# we need to access the Bionic private header <bionic_tls.h>
|
||||
# in the linker; duplicate the HAVE_ARM_TLS_REGISTER definition
|
||||
# from the libc build
|
||||
# We need to access Bionic private headers in the linker...
|
||||
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
|
||||
|
||||
# ...one of which is <private/bionic_tls.h>, for which we
|
||||
# need HAVE_ARM_TLS_REGISTER.
|
||||
ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
|
||||
LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
|
||||
endif
|
||||
LOCAL_CFLAGS += \
|
||||
-I$(LOCAL_PATH)/../libc/private \
|
||||
-I$(LOCAL_PATH)/../libc/arch-$(TARGET_ARCH)/bionic
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
LOCAL_CFLAGS += -DANDROID_ARM_LINKER
|
||||
|
@ -8,44 +8,6 @@ This document provides several notes related to the design of the Android
|
||||
dynamic linker.
|
||||
|
||||
|
||||
Prelinking:
|
||||
-----------
|
||||
|
||||
System libraries in Android are internally prelinked, which means that
|
||||
any internal relocations within them are stripped from the corresponding
|
||||
shared object, in order to reduce size and speed up loading.
|
||||
|
||||
Such libraries can only be loaded at the very specific virtual memory address
|
||||
they have been prelinked to (during the build process). The list of prelinked
|
||||
system libraries and their corresponding virtual memory address is found in
|
||||
the file:
|
||||
|
||||
build/core/prelink-linux-<arch>.map
|
||||
|
||||
It should be updated each time a new system library is added to the
|
||||
system.
|
||||
|
||||
The prelink step happens at build time, and uses the 'soslim' and 'apriori'
|
||||
tools:
|
||||
|
||||
- 'apriori' is the real prelink tool which removes relocations from the
|
||||
shared object, however, it must be given a list of symbols to remove
|
||||
from the file.
|
||||
|
||||
- 'soslim' is used to find symbols in an executable ELF file
|
||||
and generate a list that can be passed to 'apriori'.
|
||||
|
||||
By default, these tools are only used to remove internal symbols from
|
||||
libraries, though they have been designed to allow more aggressive
|
||||
optimizations (e.g. 'global' prelinking and symbol stripping, which
|
||||
prevent replacing individual system libraries though).
|
||||
|
||||
You can disable prelinking at build time by modifying your Android.mk with
|
||||
a line like:
|
||||
|
||||
LOCAL_PRELINK_MODULE := false
|
||||
|
||||
|
||||
Initialization and Termination functions:
|
||||
-----------------------------------------
|
||||
|
||||
|
@ -156,7 +156,7 @@ static void logSignalSummary(int signum, const siginfo_t* info)
|
||||
* Catches fatal signals so we can ask debuggerd to ptrace us before
|
||||
* we crash.
|
||||
*/
|
||||
void debugger_signal_handler(int n, siginfo_t* info, void* unused)
|
||||
void debugger_signal_handler(int n, siginfo_t* info, void* unused __attribute__((unused)))
|
||||
{
|
||||
char msgbuf[128];
|
||||
unsigned tid;
|
||||
|
@ -26,25 +26,23 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/auxvec.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <sys/atomics.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* special private C library header - see Android.mk */
|
||||
#include <bionic_tls.h>
|
||||
// Private C library headers.
|
||||
#include <private/bionic_tls.h>
|
||||
#include <private/logd.h>
|
||||
|
||||
#include "linker.h"
|
||||
#include "linker_debug.h"
|
||||
@ -79,8 +77,8 @@
|
||||
* - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
|
||||
* headers provide versions that are negative...
|
||||
* - allocate space for soinfo structs dynamically instead of
|
||||
* having a hard limit (64)
|
||||
*/
|
||||
* having a hard limit (SO_MAX)
|
||||
*/
|
||||
|
||||
|
||||
static int soinfo_link_image(soinfo *si, unsigned wr_offset);
|
||||
@ -126,24 +124,30 @@ struct _link_stats linker_stats;
|
||||
unsigned bitmask[4096];
|
||||
#endif
|
||||
|
||||
#define HOODLUM(name, ret, ...) \
|
||||
ret name __VA_ARGS__ \
|
||||
{ \
|
||||
char errstr[] = "ERROR: " #name " called from the dynamic linker!\n"; \
|
||||
write(2, errstr, sizeof(errstr)); \
|
||||
abort(); \
|
||||
// You shouldn't try to call memory-allocating functions in the dynamic linker.
|
||||
// Guard against the most obvious ones.
|
||||
#define DISALLOW_ALLOCATION(return_type, name, ...) \
|
||||
return_type name __VA_ARGS__ \
|
||||
{ \
|
||||
const char* msg = "ERROR: " #name " called from the dynamic linker!\n"; \
|
||||
__libc_android_log_write(ANDROID_LOG_FATAL, "linker", msg); \
|
||||
write(2, msg, sizeof(msg)); \
|
||||
abort(); \
|
||||
}
|
||||
HOODLUM(malloc, void *, (size_t size));
|
||||
HOODLUM(free, void, (void *ptr));
|
||||
HOODLUM(realloc, void *, (void *ptr, size_t size));
|
||||
HOODLUM(calloc, void *, (size_t cnt, size_t size));
|
||||
#define UNUSED __attribute__((unused))
|
||||
DISALLOW_ALLOCATION(void*, malloc, (size_t u UNUSED));
|
||||
DISALLOW_ALLOCATION(void, free, (void* u UNUSED));
|
||||
DISALLOW_ALLOCATION(void*, realloc, (void* u1 UNUSED, size_t u2 UNUSED));
|
||||
DISALLOW_ALLOCATION(void*, calloc, (size_t u1 UNUSED, size_t u2 UNUSED));
|
||||
|
||||
static char tmp_err_buf[768];
|
||||
static char __linker_dl_err_buf[768];
|
||||
#define BASENAME(s) (strrchr(s, '/') != NULL ? strrchr(s, '/') + 1 : s)
|
||||
#define DL_ERR(fmt, x...) \
|
||||
do { \
|
||||
format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), \
|
||||
"%s[%d]: " fmt, __func__, __LINE__, ##x); \
|
||||
"(%s:%d, pid %d) %s: " fmt, \
|
||||
BASENAME(__FILE__), __LINE__, pid, __func__, ##x); \
|
||||
ERROR(fmt "\n", ##x); \
|
||||
} while(0)
|
||||
|
||||
@ -156,7 +160,7 @@ const char *linker_get_error(void)
|
||||
* This function is an empty stub where GDB locates a breakpoint to get notified
|
||||
* about linker activity.
|
||||
*/
|
||||
extern void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(void);
|
||||
extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(void);
|
||||
|
||||
static struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
|
||||
RT_CONSISTENT, 0};
|
||||
@ -243,7 +247,7 @@ void notify_gdb_of_unload(soinfo * info)
|
||||
pthread_mutex_unlock(&_r_debug_lock);
|
||||
}
|
||||
|
||||
void notify_gdb_of_libraries()
|
||||
extern "C" void notify_gdb_of_libraries()
|
||||
{
|
||||
_r_debug.r_state = RT_ADD;
|
||||
rtld_db_dlactivity();
|
||||
@ -253,10 +257,8 @@ void notify_gdb_of_libraries()
|
||||
|
||||
static soinfo *soinfo_alloc(const char *name)
|
||||
{
|
||||
soinfo *si;
|
||||
|
||||
if(strlen(name) >= SOINFO_NAME_LEN) {
|
||||
DL_ERR("%5d library name %s too long", pid, name);
|
||||
if (strlen(name) >= SOINFO_NAME_LEN) {
|
||||
DL_ERR("library name \"%s\" too long", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -264,15 +266,15 @@ static soinfo *soinfo_alloc(const char *name)
|
||||
done only by dlclose(), which is not likely to be used.
|
||||
*/
|
||||
if (!freelist) {
|
||||
if(socount == SO_MAX) {
|
||||
DL_ERR("%5d too many libraries when loading %s", pid, name);
|
||||
if (socount == SO_MAX) {
|
||||
DL_ERR("too many libraries when loading \"%s\"", name);
|
||||
return NULL;
|
||||
}
|
||||
freelist = sopool + socount++;
|
||||
freelist->next = NULL;
|
||||
}
|
||||
|
||||
si = freelist;
|
||||
soinfo* si = freelist;
|
||||
freelist = freelist->next;
|
||||
|
||||
/* Make sure we get a clean block of soinfo */
|
||||
@ -287,8 +289,12 @@ static soinfo *soinfo_alloc(const char *name)
|
||||
return si;
|
||||
}
|
||||
|
||||
static void soinfo_free(soinfo *si)
|
||||
static void soinfo_free(soinfo* si)
|
||||
{
|
||||
if (si == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
soinfo *prev = NULL, *trav;
|
||||
|
||||
TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si);
|
||||
@ -300,7 +306,7 @@ static void soinfo_free(soinfo *si)
|
||||
}
|
||||
if (trav == NULL) {
|
||||
/* si was not ni solist */
|
||||
DL_ERR("%5d name %s is not in solist!", pid, si->name);
|
||||
DL_ERR("name \"%s\" is not in solist!", si->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -315,17 +321,16 @@ static void soinfo_free(soinfo *si)
|
||||
|
||||
const char *addr_to_name(unsigned addr)
|
||||
{
|
||||
soinfo *si;
|
||||
|
||||
for(si = solist; si != 0; si = si->next){
|
||||
if((addr >= si->base) && (addr < (si->base + si->size))) {
|
||||
for (soinfo* si = solist; si != 0; si = si->next) {
|
||||
if ((addr >= si->base) && (addr < (si->base + si->size))) {
|
||||
return si->name;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#ifdef ANDROID_ARM_LINKER
|
||||
|
||||
/* For a given PC, find the .so that it belongs to.
|
||||
* Returns the base address of the .ARM.exidx section
|
||||
* for that .so, and the number of 8-byte entries
|
||||
@ -335,7 +340,6 @@ const char *addr_to_name(unsigned addr)
|
||||
*
|
||||
* This function is exposed via dlfcn.c and libdl.so.
|
||||
*/
|
||||
#ifdef ANDROID_ARM_LINKER
|
||||
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
|
||||
{
|
||||
soinfo *si;
|
||||
@ -350,7 +354,9 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
|
||||
*pcount = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
|
||||
|
||||
/* Here, we only have to provide a callback to iterate across all the
|
||||
* loaded libraries. gcc_eh does the rest. */
|
||||
int
|
||||
@ -372,6 +378,7 @@ dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static Elf32_Sym *soinfo_elf_lookup(soinfo *si, unsigned hash, const char *name)
|
||||
@ -454,8 +461,7 @@ soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset)
|
||||
if(d[0] == DT_NEEDED){
|
||||
lsi = (soinfo *)d[1];
|
||||
if (!validate_soinfo(lsi)) {
|
||||
DL_ERR("%5d bad DT_NEEDED pointer in %s",
|
||||
pid, lsi->name);
|
||||
DL_ERR("bad DT_NEEDED pointer in \"%s\"", lsi->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -638,35 +644,33 @@ static int open_library(const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
long mmap_addr;
|
||||
char tag[4]; /* 'P', 'R', 'E', ' ' */
|
||||
} prelink_info_t;
|
||||
|
||||
/* Returns the requested base address if the library is prelinked,
|
||||
* and 0 otherwise. */
|
||||
static unsigned long
|
||||
is_prelinked(int fd, const char *name)
|
||||
// Returns 'true' if the library is prelinked or on failure so we error out
|
||||
// either way. We no longer support prelinking.
|
||||
static bool is_prelinked(int fd, const char* name)
|
||||
{
|
||||
off_t sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
|
||||
struct prelink_info_t {
|
||||
long mmap_addr;
|
||||
char tag[4]; // "PRE ".
|
||||
};
|
||||
|
||||
off_t sz = lseek(fd, -sizeof(struct prelink_info_t), SEEK_END);
|
||||
if (sz < 0) {
|
||||
DL_ERR("lseek() failed!");
|
||||
return 0;
|
||||
DL_ERR("lseek failed: %s", strerror(errno));
|
||||
return true;
|
||||
}
|
||||
|
||||
prelink_info_t info;
|
||||
struct prelink_info_t info;
|
||||
int rc = TEMP_FAILURE_RETRY(read(fd, &info, sizeof(info)));
|
||||
if (rc != sizeof(info)) {
|
||||
WARN("Could not read prelink_info_t structure for `%s`\n", name);
|
||||
return 0;
|
||||
DL_ERR("could not read prelink_info_t structure for \"%s\":", name, strerror(errno));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (memcmp(info.tag, "PRE ", 4)) {
|
||||
WARN("`%s` is not a prelinked library\n", name);
|
||||
return 0;
|
||||
if (memcmp(info.tag, "PRE ", 4) == 0) {
|
||||
DL_ERR("prelinked libraries no longer supported: %s", name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return (unsigned long)info.mmap_addr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* verify_elf_header
|
||||
@ -697,101 +701,106 @@ verify_elf_header(const Elf32_Ehdr* hdr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct scoped_fd {
|
||||
~scoped_fd() {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
int fd;
|
||||
};
|
||||
|
||||
static soinfo *
|
||||
load_library(const char *name)
|
||||
struct soinfo_ptr {
|
||||
soinfo_ptr(const char* name) {
|
||||
const char* bname = strrchr(name, '/');
|
||||
ptr = soinfo_alloc(bname ? bname + 1 : name);
|
||||
}
|
||||
~soinfo_ptr() {
|
||||
soinfo_free(ptr);
|
||||
}
|
||||
soinfo* release() {
|
||||
soinfo* result = ptr;
|
||||
ptr = NULL;
|
||||
return result;
|
||||
}
|
||||
soinfo* ptr;
|
||||
};
|
||||
|
||||
// TODO: rewrite linker_phdr.h to use a class, then lose this.
|
||||
struct phdr_ptr {
|
||||
phdr_ptr() : phdr_mmap(NULL) {}
|
||||
~phdr_ptr() {
|
||||
if (phdr_mmap != NULL) {
|
||||
phdr_table_unload(phdr_mmap, phdr_size);
|
||||
}
|
||||
}
|
||||
void* phdr_mmap;
|
||||
Elf32_Addr phdr_size;
|
||||
};
|
||||
|
||||
static soinfo* load_library(const char* name)
|
||||
{
|
||||
int fd = open_library(name);
|
||||
int ret, cnt;
|
||||
unsigned ext_sz;
|
||||
unsigned req_base;
|
||||
const char *bname;
|
||||
struct stat sb;
|
||||
soinfo *si = NULL;
|
||||
Elf32_Ehdr header[1];
|
||||
int phdr_count;
|
||||
void* phdr_mmap = NULL;
|
||||
Elf32_Addr phdr_size;
|
||||
const Elf32_Phdr* phdr_table;
|
||||
|
||||
void* load_start = NULL;
|
||||
Elf32_Addr load_size = 0;
|
||||
Elf32_Addr load_bias = 0;
|
||||
|
||||
if (fd == -1) {
|
||||
DL_ERR("Library '%s' not found", name);
|
||||
// Open the file.
|
||||
scoped_fd fd;
|
||||
fd.fd = open_library(name);
|
||||
if (fd.fd == -1) {
|
||||
DL_ERR("library \"%s\" not found", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read the ELF header first */
|
||||
ret = TEMP_FAILURE_RETRY(read(fd, (void*)header, sizeof(header)));
|
||||
// Read the ELF header.
|
||||
Elf32_Ehdr header[1];
|
||||
int ret = TEMP_FAILURE_RETRY(read(fd.fd, (void*)header, sizeof(header)));
|
||||
if (ret < 0) {
|
||||
DL_ERR("%5d can't read file %s: %s", pid, name, strerror(errno));
|
||||
goto fail;
|
||||
DL_ERR("can't read file \"%s\": %s", name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (ret != (int)sizeof(header)) {
|
||||
DL_ERR("%5d too small to be an ELF executable: %s", pid, name);
|
||||
goto fail;
|
||||
DL_ERR("too small to be an ELF executable: %s", name);
|
||||
return NULL;
|
||||
}
|
||||
if (verify_elf_header(header) < 0) {
|
||||
DL_ERR("%5d not a valid ELF executable: %s", pid, name);
|
||||
goto fail;
|
||||
DL_ERR("not a valid ELF executable: %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Then read the program header table */
|
||||
ret = phdr_table_load(fd, header->e_phoff, header->e_phnum,
|
||||
&phdr_mmap, &phdr_size, &phdr_table);
|
||||
// Read the program header table.
|
||||
const Elf32_Phdr* phdr_table;
|
||||
phdr_ptr phdr_holder;
|
||||
ret = phdr_table_load(fd.fd, header->e_phoff, header->e_phnum,
|
||||
&phdr_holder.phdr_mmap, &phdr_holder.phdr_size, &phdr_table);
|
||||
if (ret < 0) {
|
||||
DL_ERR("%5d can't load program header table: %s: %s", pid,
|
||||
name, strerror(errno));
|
||||
goto fail;
|
||||
DL_ERR("can't load program header table: %s: %s", name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
phdr_count = header->e_phnum;
|
||||
size_t phdr_count = header->e_phnum;
|
||||
|
||||
/* Get the load extents and the prelinked load address, if any */
|
||||
ext_sz = phdr_table_get_load_size(phdr_table, phdr_count);
|
||||
// Get the load extents.
|
||||
Elf32_Addr ext_sz = phdr_table_get_load_size(phdr_table, phdr_count);
|
||||
TRACE("[ %5d - '%s' wants sz=0x%08x ]\n", pid, name, ext_sz);
|
||||
if (ext_sz == 0) {
|
||||
DL_ERR("%5d no loadable segments in file: %s", pid, name);
|
||||
goto fail;
|
||||
DL_ERR("no loadable segments in file: %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req_base = (unsigned) is_prelinked(fd, name);
|
||||
if (req_base == (unsigned)-1) {
|
||||
DL_ERR("%5d can't read end of library: %s: %s", pid, name,
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
if (req_base != 0) {
|
||||
TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n",
|
||||
pid, name, req_base);
|
||||
} else {
|
||||
TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
|
||||
// We no longer support pre-linked libraries.
|
||||
if (is_prelinked(fd.fd, name)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
|
||||
(req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
|
||||
|
||||
/* Now configure the soinfo struct where we'll store all of our data
|
||||
* for the ELF object. If the loading fails, we waste the entry, but
|
||||
* same thing would happen if we failed during linking. Configuring the
|
||||
* soinfo struct here is a lot more convenient.
|
||||
*/
|
||||
bname = strrchr(name, '/');
|
||||
si = soinfo_alloc(bname ? bname + 1 : name);
|
||||
if (si == NULL)
|
||||
goto fail;
|
||||
|
||||
/* Reserve address space for all loadable segments */
|
||||
// Reserve address space for all loadable segments.
|
||||
void* load_start = NULL;
|
||||
Elf32_Addr load_size = 0;
|
||||
Elf32_Addr load_bias = 0;
|
||||
ret = phdr_table_reserve_memory(phdr_table,
|
||||
phdr_count,
|
||||
req_base,
|
||||
&load_start,
|
||||
&load_size,
|
||||
&load_bias);
|
||||
if (ret < 0) {
|
||||
DL_ERR("%5d Can't reserve %d bytes from 0x%08x in address space for %s: %s",
|
||||
pid, ext_sz, req_base, name, strerror(errno));
|
||||
goto fail;
|
||||
DL_ERR("can't reserve %d bytes in address space for \"%s\": %s",
|
||||
ext_sz, name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
|
||||
@ -800,14 +809,12 @@ load_library(const char *name)
|
||||
/* Map all the segments in our address space with default protections */
|
||||
ret = phdr_table_load_segments(phdr_table,
|
||||
phdr_count,
|
||||
load_start,
|
||||
load_size,
|
||||
load_bias,
|
||||
fd);
|
||||
fd.fd);
|
||||
if (ret < 0) {
|
||||
DL_ERR("%5d Can't map loadable segments for %s: %s",
|
||||
pid, name, strerror(errno));
|
||||
goto fail;
|
||||
DL_ERR("can't map loadable segments for \"%s\": %s",
|
||||
name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Unprotect the segments, i.e. make them writable, to allow
|
||||
@ -819,36 +826,30 @@ load_library(const char *name)
|
||||
phdr_count,
|
||||
load_bias);
|
||||
if (ret < 0) {
|
||||
DL_ERR("%5d Can't unprotect loadable segments for %s: %s",
|
||||
pid, name, strerror(errno));
|
||||
goto fail;
|
||||
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
||||
name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
si->base = (Elf32_Addr) load_start;
|
||||
si->size = load_size;
|
||||
si->load_bias = load_bias;
|
||||
si->flags = 0;
|
||||
si->entry = 0;
|
||||
si->dynamic = (unsigned *)-1;
|
||||
si->phnum = phdr_count;
|
||||
si->phdr = phdr_table_get_loaded_phdr(phdr_table, phdr_count, load_bias);
|
||||
if (si->phdr == NULL) {
|
||||
DL_ERR("%5d Can't find loaded PHDR for %s",
|
||||
pid, name);
|
||||
goto fail;
|
||||
soinfo_ptr si(name);
|
||||
if (si.ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
phdr_table_unload(phdr_mmap, phdr_size);
|
||||
close(fd);
|
||||
return si;
|
||||
|
||||
fail:
|
||||
if (si) soinfo_free(si);
|
||||
if (phdr_mmap != NULL) {
|
||||
phdr_table_unload(phdr_mmap, phdr_size);
|
||||
si.ptr->base = (Elf32_Addr) load_start;
|
||||
si.ptr->size = load_size;
|
||||
si.ptr->load_bias = load_bias;
|
||||
si.ptr->flags = 0;
|
||||
si.ptr->entry = 0;
|
||||
si.ptr->dynamic = (unsigned *)-1;
|
||||
si.ptr->phnum = phdr_count;
|
||||
si.ptr->phdr = phdr_table_get_loaded_phdr(phdr_table, phdr_count, load_bias);
|
||||
if (si.ptr->phdr == NULL) {
|
||||
DL_ERR("can't find loaded PHDR for \"%s\"", name);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
return NULL;
|
||||
|
||||
return si.release();
|
||||
}
|
||||
|
||||
static soinfo *
|
||||
@ -891,11 +892,11 @@ soinfo *find_library(const char *name)
|
||||
for(si = solist; si != 0; si = si->next){
|
||||
if(!strcmp(bname, si->name)) {
|
||||
if(si->flags & FLAG_ERROR) {
|
||||
DL_ERR("%5d '%s' failed to load previously", pid, bname);
|
||||
DL_ERR("\"%s\" failed to load previously", bname);
|
||||
return NULL;
|
||||
}
|
||||
if(si->flags & FLAG_LINKED) return si;
|
||||
DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name);
|
||||
DL_ERR("OOPS: recursive link to \"%s\"", si->name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -908,8 +909,7 @@ soinfo *find_library(const char *name)
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
* notify gdb of unload
|
||||
* for non-prelinked libraries, find a way to decrement libbase
|
||||
* find a way to decrement libbase
|
||||
*/
|
||||
static void call_destructors(soinfo *si);
|
||||
unsigned soinfo_unload(soinfo *si)
|
||||
@ -925,9 +925,9 @@ unsigned soinfo_unload(soinfo *si)
|
||||
*/
|
||||
if (phdr_table_unprotect_gnu_relro(si->phdr, si->phnum,
|
||||
si->load_bias) < 0) {
|
||||
DL_ERR("%5d %s: could not undo GNU_RELRO protections. "
|
||||
DL_ERR("%s: could not undo GNU_RELRO protections. "
|
||||
"Expect a crash soon. errno=%d (%s)",
|
||||
pid, si->name, errno, strerror(errno));
|
||||
si->name, errno, strerror(errno));
|
||||
}
|
||||
|
||||
for(d = si->dynamic; *d; d += 2) {
|
||||
@ -945,8 +945,8 @@ unsigned soinfo_unload(soinfo *si)
|
||||
soinfo_unload(lsi);
|
||||
}
|
||||
else
|
||||
DL_ERR("%5d %s: could not unload dependent library",
|
||||
pid, si->name);
|
||||
DL_ERR("\"%s\": could not unload dependent library",
|
||||
si->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,12 +972,10 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
||||
Elf32_Sym *symtab = si->symtab;
|
||||
const char *strtab = si->strtab;
|
||||
Elf32_Sym *s;
|
||||
unsigned base;
|
||||
Elf32_Addr offset;
|
||||
Elf32_Rel *start = rel;
|
||||
unsigned idx;
|
||||
|
||||
for (idx = 0; idx < count; ++idx, ++rel) {
|
||||
for (size_t idx = 0; idx < count; ++idx, ++rel) {
|
||||
unsigned type = ELF32_R_TYPE(rel->r_info);
|
||||
unsigned sym = ELF32_R_SYM(rel->r_info);
|
||||
unsigned reloc = (unsigned)(rel->r_offset + si->load_bias);
|
||||
@ -997,7 +995,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
||||
reference.. */
|
||||
s = &symtab[sym];
|
||||
if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
|
||||
DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
|
||||
DL_ERR("cannot locate \"%s\"...", sym_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1043,8 +1041,8 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
||||
not found in run-time. */
|
||||
#endif /* ANDROID_ARM_LINKER */
|
||||
default:
|
||||
DL_ERR("%5d unknown weak reloc type %d @ %p (%d)\n",
|
||||
pid, type, rel, (int) (rel - start));
|
||||
DL_ERR("unknown weak reloc type %d @ %p (%d)",
|
||||
type, rel, (int) (rel - start));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@ -1052,8 +1050,8 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
||||
#if 0
|
||||
if((base == 0) && (si->base != 0)){
|
||||
/* linking from libraries to main image is bad */
|
||||
DL_ERR("%5d cannot locate '%s'...",
|
||||
pid, strtab + symtab[sym].st_name);
|
||||
DL_ERR("cannot locate \"%s\"...",
|
||||
strtab + symtab[sym].st_name);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
@ -1140,8 +1138,8 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
||||
#endif /* ANDROID_*_LINKER */
|
||||
COUNT_RELOC(RELOC_RELATIVE);
|
||||
MARK(rel->r_offset);
|
||||
if(sym){
|
||||
DL_ERR("%5d odd RELATIVE form...", pid);
|
||||
if (sym) {
|
||||
DL_ERR("odd RELATIVE form...", pid);
|
||||
return -1;
|
||||
}
|
||||
TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
|
||||
@ -1180,8 +1178,8 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
||||
#endif /* ANDROID_ARM_LINKER */
|
||||
|
||||
default:
|
||||
DL_ERR("%5d unknown reloc type %d @ %p (%d)",
|
||||
pid, type, rel, (int) (rel - start));
|
||||
DL_ERR("unknown reloc type %d @ %p (%d)",
|
||||
type, rel, (int) (rel - start));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1240,7 +1238,7 @@ int mips_relocate_got(struct soinfo *si)
|
||||
reference.. */
|
||||
s = &symtab[g];
|
||||
if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
|
||||
DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
|
||||
DL_ERR("cannot locate \"%s\"...", sym_name);
|
||||
return -1;
|
||||
}
|
||||
*got = 0;
|
||||
@ -1320,9 +1318,8 @@ void soinfo_call_constructors(soinfo *si)
|
||||
TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
|
||||
} else {
|
||||
if (si->preinit_array) {
|
||||
DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x."
|
||||
" This is INVALID.", pid, si->name,
|
||||
(unsigned)si->preinit_array);
|
||||
DL_ERR("shared library \"%s\" has a preinit_array table @ 0x%08x. "
|
||||
"This is INVALID.", si->name, (unsigned) si->preinit_array);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1332,8 +1329,7 @@ void soinfo_call_constructors(soinfo *si)
|
||||
if(d[0] == DT_NEEDED){
|
||||
soinfo* lsi = (soinfo *)d[1];
|
||||
if (!validate_soinfo(lsi)) {
|
||||
DL_ERR("%5d bad DT_NEEDED pointer in %s",
|
||||
pid, si->name);
|
||||
DL_ERR("bad DT_NEEDED pointer in \"%s\"", si->name);
|
||||
} else {
|
||||
soinfo_call_constructors(lsi);
|
||||
}
|
||||
@ -1383,7 +1379,7 @@ static int nullify_closed_stdio (void)
|
||||
|
||||
dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
|
||||
if (dev_null < 0) {
|
||||
DL_ERR("Cannot open /dev/null.");
|
||||
DL_ERR("cannot open /dev/null: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null);
|
||||
@ -1392,24 +1388,22 @@ static int nullify_closed_stdio (void)
|
||||
with /dev/null, dup /dev/null to it. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* If it is /dev/null already, we are done. */
|
||||
if (i == dev_null)
|
||||
if (i == dev_null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i);
|
||||
/* The man page of fcntl does not say that fcntl(..,F_GETFL)
|
||||
can be interrupted but we do this just to be safe. */
|
||||
do {
|
||||
status = fcntl(i, F_GETFL);
|
||||
} while (status < 0 && errno == EINTR);
|
||||
status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
|
||||
|
||||
/* If file is openned, we are good. */
|
||||
if (status >= 0)
|
||||
continue;
|
||||
/* If file is opened, we are good. */
|
||||
if (status != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The only error we allow is that the file descriptor does not
|
||||
exist, in which case we dup /dev/null to it. */
|
||||
if (errno != EBADF) {
|
||||
DL_ERR("nullify_stdio: unhandled error %s", strerror(errno));
|
||||
DL_ERR("fcntl failed: %s", strerror(errno));
|
||||
return_value = -1;
|
||||
continue;
|
||||
}
|
||||
@ -1417,12 +1411,9 @@ static int nullify_closed_stdio (void)
|
||||
/* Try dupping /dev/null to this stdio file descriptor and
|
||||
repeat if there is a signal. Note that any errors in closing
|
||||
the stdio descriptor are lost. */
|
||||
do {
|
||||
status = dup2(dev_null, i);
|
||||
} while (status < 0 && errno == EINTR);
|
||||
|
||||
status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
|
||||
if (status < 0) {
|
||||
DL_ERR("nullify_stdio: dup2 error %s", strerror(errno));
|
||||
DL_ERR("dup2 failed: %s", strerror(errno));
|
||||
return_value = -1;
|
||||
continue;
|
||||
}
|
||||
@ -1431,12 +1422,9 @@ static int nullify_closed_stdio (void)
|
||||
/* If /dev/null is not one of the stdio file descriptors, close it. */
|
||||
if (dev_null > 2) {
|
||||
TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null);
|
||||
do {
|
||||
status = close(dev_null);
|
||||
} while (status < 0 && errno == EINTR);
|
||||
|
||||
if (status < 0) {
|
||||
DL_ERR("nullify_stdio: close error %s", strerror(errno));
|
||||
status = TEMP_FAILURE_RETRY(close(dev_null));
|
||||
if (status == -1) {
|
||||
DL_ERR("close failed: %s", strerror(errno));
|
||||
return_value = -1;
|
||||
}
|
||||
}
|
||||
@ -1464,7 +1452,7 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
si->dynamic = phdr_table_get_dynamic_section(phdr, phnum, base);
|
||||
if (si->dynamic == NULL) {
|
||||
if (!relocating_linker) {
|
||||
DL_ERR("%5d missing PT_DYNAMIC?!", pid);
|
||||
DL_ERR("missing PT_DYNAMIC?!");
|
||||
}
|
||||
goto fail;
|
||||
} else {
|
||||
@ -1485,8 +1473,8 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
/* We can't call DL_ERR if the linker's relocations haven't
|
||||
* been performed yet */
|
||||
if (!relocating_linker) {
|
||||
DL_ERR("%5d Can't unprotect segments for %s: %s",
|
||||
pid, si->name, strerror(errno));
|
||||
DL_ERR("can't unprotect segments for \"%s\": %s",
|
||||
si->name, strerror(errno));
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
@ -1537,7 +1525,7 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
#endif
|
||||
break;
|
||||
case DT_RELA:
|
||||
DL_ERR("%5d DT_RELA not supported", pid);
|
||||
DL_ERR("DT_RELA not supported");
|
||||
goto fail;
|
||||
case DT_INIT:
|
||||
si->init_func = (void (*)(void))(base + *d);
|
||||
@ -1633,7 +1621,7 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
pid, si->base, si->strtab, si->symtab);
|
||||
|
||||
if((si->strtab == 0) || (si->symtab == 0)) {
|
||||
DL_ERR("%5d missing essential tables", pid);
|
||||
DL_ERR("missing essential tables");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -1645,8 +1633,8 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
soinfo *lsi = find_library(ldpreload_names[i]);
|
||||
if(lsi == 0) {
|
||||
strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
|
||||
DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
|
||||
pid, ldpreload_names[i], si->name, tmp_err_buf);
|
||||
DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
|
||||
ldpreload_names[i], si->name, tmp_err_buf);
|
||||
goto fail;
|
||||
}
|
||||
lsi->refcount++;
|
||||
@ -1660,8 +1648,8 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
soinfo *lsi = find_library(si->strtab + d[1]);
|
||||
if(lsi == 0) {
|
||||
strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
|
||||
DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
|
||||
pid, si->strtab + d[1], si->name, tmp_err_buf);
|
||||
DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
|
||||
si->strtab + d[1], si->name, tmp_err_buf);
|
||||
goto fail;
|
||||
}
|
||||
/* Save the soinfo of the loaded DT_NEEDED library in the payload
|
||||
@ -1699,15 +1687,15 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
/* All relocations are done, we can protect our segments back to
|
||||
* read-only. */
|
||||
if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
|
||||
DL_ERR("%5d Can't protect segments for %s: %s",
|
||||
pid, si->name, strerror(errno));
|
||||
DL_ERR("can't protect segments for \"%s\": %s",
|
||||
si->name, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We can also turn on GNU RELRO protection */
|
||||
if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) {
|
||||
DL_ERR("%5d Can't enable GNU RELRO protection for %s: %s",
|
||||
pid, si->name, strerror(errno));
|
||||
DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
|
||||
si->name, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -1717,8 +1705,9 @@ static int soinfo_link_image(soinfo *si, unsigned wr_offset)
|
||||
ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
|
||||
|
||||
*/
|
||||
if (program_is_setuid)
|
||||
nullify_closed_stdio ();
|
||||
if (program_is_setuid) {
|
||||
nullify_closed_stdio();
|
||||
}
|
||||
notify_gdb_of_load(si);
|
||||
return 0;
|
||||
|
||||
@ -1728,53 +1717,43 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void parse_library_path(const char *path, char *delim)
|
||||
static void parse_path(const char* path, const char* delimiters,
|
||||
const char** array, char* buf, size_t buf_size, size_t max_count)
|
||||
{
|
||||
size_t len;
|
||||
char *ldpaths_bufp = ldpaths_buf;
|
||||
int i = 0;
|
||||
|
||||
len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf));
|
||||
|
||||
while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) {
|
||||
if (*ldpaths[i] != '\0')
|
||||
++i;
|
||||
if (path == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Forget the last path if we had to truncate; this occurs if the 2nd to
|
||||
* last char isn't '\0' (i.e. not originally a delim). */
|
||||
if (i > 0 && len >= sizeof(ldpaths_buf) &&
|
||||
ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') {
|
||||
ldpaths[i - 1] = NULL;
|
||||
} else {
|
||||
ldpaths[i] = NULL;
|
||||
}
|
||||
}
|
||||
size_t len = strlcpy(buf, path, buf_size);
|
||||
|
||||
static void parse_preloads(const char *path, char *delim)
|
||||
{
|
||||
size_t len;
|
||||
char *ldpreloads_bufp = ldpreloads_buf;
|
||||
int i = 0;
|
||||
|
||||
len = strlcpy(ldpreloads_buf, path, sizeof(ldpreloads_buf));
|
||||
|
||||
while (i < LDPRELOAD_MAX && (ldpreload_names[i] = strsep(&ldpreloads_bufp, delim))) {
|
||||
if (*ldpreload_names[i] != '\0') {
|
||||
size_t i = 0;
|
||||
char* buf_p = buf;
|
||||
while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
|
||||
if (*array[i] != '\0') {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Forget the last path if we had to truncate; this occurs if the 2nd to
|
||||
* last char isn't '\0' (i.e. not originally a delim). */
|
||||
if (i > 0 && len >= sizeof(ldpreloads_buf) &&
|
||||
ldpreloads_buf[sizeof(ldpreloads_buf) - 2] != '\0') {
|
||||
ldpreload_names[i - 1] = NULL;
|
||||
// Forget the last path if we had to truncate; this occurs if the 2nd to
|
||||
// last char isn't '\0' (i.e. wasn't originally a delimiter).
|
||||
if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
|
||||
array[i - 1] = NULL;
|
||||
} else {
|
||||
ldpreload_names[i] = NULL;
|
||||
array[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_LD_LIBRARY_PATH(const char* path) {
|
||||
parse_path(path, ":", ldpaths,
|
||||
ldpaths_buf, sizeof(ldpaths_buf), LDPATH_MAX);
|
||||
}
|
||||
|
||||
static void parse_LD_PRELOAD(const char* path) {
|
||||
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
|
||||
parse_path(path, " :", ldpreload_names,
|
||||
ldpreloads_buf, sizeof(ldpreloads_buf), LDPRELOAD_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* This code is called after the linker has linked itself and
|
||||
* fixed it's own GOT. It is safe to make references to externs
|
||||
@ -1917,13 +1896,9 @@ sanitize:
|
||||
si->dynamic = (unsigned *)-1;
|
||||
si->refcount = 1;
|
||||
|
||||
/* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
|
||||
if (ldpath_env)
|
||||
parse_library_path(ldpath_env, ":");
|
||||
|
||||
if (ldpreload_env) {
|
||||
parse_preloads(ldpreload_env, " :");
|
||||
}
|
||||
// Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
|
||||
parse_LD_LIBRARY_PATH(ldpath_env);
|
||||
parse_LD_PRELOAD(ldpreload_env);
|
||||
|
||||
if(soinfo_link_image(si, 0)) {
|
||||
char errmsg[] = "CANNOT LINK EXECUTABLE\n";
|
||||
@ -2047,7 +2022,7 @@ get_elf_exec_load_bias(const Elf32_Ehdr* elf)
|
||||
* relocations, any attempt to reference an extern variable, extern
|
||||
* function, or other GOT reference will generate a segfault.
|
||||
*/
|
||||
unsigned __linker_init(unsigned **elfdata) {
|
||||
extern "C" unsigned __linker_init(unsigned **elfdata) {
|
||||
unsigned linker_addr = find_linker_base(elfdata);
|
||||
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr;
|
||||
Elf32_Phdr *phdr =
|
@ -34,6 +34,10 @@
|
||||
#include <elf.h>
|
||||
#include <sys/exec_elf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#undef PAGE_MASK
|
||||
#undef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
@ -106,7 +110,7 @@ typedef struct soinfo soinfo;
|
||||
|
||||
struct soinfo
|
||||
{
|
||||
const char name[SOINFO_NAME_LEN];
|
||||
char name[SOINFO_NAME_LEN];
|
||||
const Elf32_Phdr *phdr;
|
||||
int phnum;
|
||||
unsigned entry;
|
||||
@ -244,4 +248,8 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
|
||||
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -28,6 +28,10 @@
|
||||
#ifndef LINKER_ENVIRON_H
|
||||
#define LINKER_ENVIRON_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Call this function before anything else. 'vecs' must be the pointer
|
||||
* to the environment block in the ELF data block. The function returns
|
||||
* the start of the aux vectors after the env block.
|
||||
@ -47,8 +51,12 @@ extern void linker_env_unset(const char* name);
|
||||
* after this function. */
|
||||
extern const char* linker_env_get(const char* name);
|
||||
|
||||
/* Remove unsecure environment variables. This should be used when
|
||||
/* Remove insecure environment variables. This should be used when
|
||||
* running setuid programs. */
|
||||
extern void linker_env_secure(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* LINKER_ENVIRON_H */
|
||||
|
@ -312,7 +312,7 @@ static int log_vprint(int prio, const char *tag, const char *fmt, va_list args)
|
||||
|
||||
#else /* !CUSTOM_LOG_VPRINT */
|
||||
|
||||
extern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap);
|
||||
extern "C" int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap);
|
||||
|
||||
#endif /* !CUSTOM_LOG_VPRINT */
|
||||
|
||||
|
@ -31,6 +31,10 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Formatting routines for the dynamic linker's debug traces */
|
||||
/* We want to avoid dragging the whole C library fprintf() */
|
||||
/* implementation into the dynamic linker since this creates */
|
||||
@ -38,4 +42,8 @@
|
||||
|
||||
int format_buffer(char *buffer, size_t bufsize, const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _LINKER_FORMAT_H */
|
||||
|
@ -180,24 +180,25 @@ void phdr_table_unload(void* phdr_mmap, Elf32_Addr phdr_memsize)
|
||||
* This returns 0 if there are no loadable segments.
|
||||
*/
|
||||
Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count)
|
||||
size_t phdr_count)
|
||||
{
|
||||
int nn;
|
||||
|
||||
Elf32_Addr min_vaddr = 0xFFFFFFFFU;
|
||||
Elf32_Addr max_vaddr = 0x00000000U;
|
||||
|
||||
for (nn = 0; nn < phdr_count; nn++) {
|
||||
const Elf32_Phdr* phdr = &phdr_table[nn];
|
||||
for (size_t i = 0; i < phdr_count; ++i) {
|
||||
const Elf32_Phdr* phdr = &phdr_table[i];
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
if (phdr->p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phdr->p_vaddr < min_vaddr)
|
||||
if (phdr->p_vaddr < min_vaddr) {
|
||||
min_vaddr = phdr->p_vaddr;
|
||||
}
|
||||
|
||||
if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
|
||||
if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
|
||||
max_vaddr = phdr->p_vaddr + phdr->p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_vaddr > max_vaddr) {
|
||||
@ -217,8 +218,6 @@ Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
||||
* Input:
|
||||
* phdr_table -> program header table
|
||||
* phdr_count -> number of entries in the tables
|
||||
* required_base -> for prelinked libraries, mandatory load address
|
||||
* of the first loadable segment. 0 otherwise.
|
||||
* Output:
|
||||
* load_start -> first page of reserved address space range
|
||||
* load_size -> size in bytes of reserved address space range
|
||||
@ -229,26 +228,19 @@ Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
||||
*/
|
||||
int
|
||||
phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count,
|
||||
Elf32_Addr required_base,
|
||||
void** load_start,
|
||||
Elf32_Addr* load_size,
|
||||
Elf32_Addr* load_bias)
|
||||
size_t phdr_count,
|
||||
void** load_start,
|
||||
Elf32_Addr* load_size,
|
||||
Elf32_Addr* load_bias)
|
||||
{
|
||||
Elf32_Addr size = phdr_table_get_load_size(phdr_table, phdr_count);
|
||||
void* start;
|
||||
int nn, mmap_flags;
|
||||
|
||||
if (size == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
if (required_base != 0)
|
||||
mmap_flags |= MAP_FIXED;
|
||||
|
||||
start = mmap((void*)required_base, size, PROT_NONE, mmap_flags, -1, 0);
|
||||
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
void* start = mmap(NULL, size, PROT_NONE, mmap_flags, -1, 0);
|
||||
if (start == MAP_FAILED) {
|
||||
return -1;
|
||||
}
|
||||
@ -257,8 +249,8 @@ phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
|
||||
*load_size = size;
|
||||
*load_bias = 0;
|
||||
|
||||
for (nn = 0; nn < phdr_count; nn++) {
|
||||
const Elf32_Phdr* phdr = &phdr_table[nn];
|
||||
for (size_t i = 0; i < phdr_count; ++i) {
|
||||
const Elf32_Phdr* phdr = &phdr_table[i];
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
*load_bias = (Elf32_Addr)start - PAGE_START(phdr->p_vaddr);
|
||||
break;
|
||||
@ -274,8 +266,6 @@ phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
|
||||
* Input:
|
||||
* phdr_table -> program header table
|
||||
* phdr_count -> number of entries in the table
|
||||
* load_start -> start address of reserved memory range.
|
||||
* load_size -> size of reserved memory range.
|
||||
* load_bias -> load offset.
|
||||
* fd -> input file descriptor.
|
||||
*
|
||||
@ -285,8 +275,6 @@ phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
|
||||
int
|
||||
phdr_table_load_segments(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count,
|
||||
void* load_start,
|
||||
Elf32_Addr load_size,
|
||||
Elf32_Addr load_bias,
|
||||
int fd)
|
||||
{
|
||||
|
@ -37,6 +37,10 @@
|
||||
|
||||
#include "linker.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* See linker_phdr.c for all usage documentation */
|
||||
|
||||
int
|
||||
@ -52,21 +56,18 @@ phdr_table_unload(void* phdr_mmap, Elf32_Addr phdr_memsize);
|
||||
|
||||
Elf32_Addr
|
||||
phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count);
|
||||
size_t phdr_count);
|
||||
|
||||
int
|
||||
phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count,
|
||||
Elf32_Addr required_base,
|
||||
void** load_start,
|
||||
Elf32_Addr* load_size,
|
||||
Elf32_Addr* load_bias);
|
||||
size_t phdr_count,
|
||||
void** load_start,
|
||||
Elf32_Addr* load_size,
|
||||
Elf32_Addr* load_bias);
|
||||
|
||||
int
|
||||
phdr_table_load_segments(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count,
|
||||
void* load_start,
|
||||
Elf32_Addr load_size,
|
||||
Elf32_Addr load_bias,
|
||||
int fd);
|
||||
|
||||
@ -109,4 +110,8 @@ phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
||||
int phdr_count,
|
||||
Elf32_Addr load_bias);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* LINKER_PHDR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user