aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fischer <matt.fischer@garmin.com>2009-12-31 12:09:10 -0600
committerJean-Baptiste Queru <jbq@google.com>2010-05-10 15:09:19 -0700
commit4fd42c1dc002fa19349fa0d4ef97757eb1815032 (patch)
tree76b67f6f6f087f8aced1da660754f7f3086c184f
parentd791da79432064bc954fedf8d4e4394aaafefe75 (diff)
downloadandroid_bionic-4fd42c1dc002fa19349fa0d4ef97757eb1815032.tar.gz
android_bionic-4fd42c1dc002fa19349fa0d4ef97757eb1815032.tar.bz2
android_bionic-4fd42c1dc002fa19349fa0d4ef97757eb1815032.zip
Added support for LD_PRELOAD
The LD_PRELOAD environment variable allows the user to specify a list of libraries which should be unconditionally loaded before any others. This makes possible some useful tricks, such as library interposers. Change-Id: I433d775ab08ef63a5fbe7b21f87a5642954fc32f
-rw-r--r--linker/linker.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/linker/linker.c b/linker/linker.c
index 451e96c2b..8dde9410b 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -58,6 +58,9 @@
#define LDPATH_BUFSIZE 512
#define LDPATH_MAX 8
+#define LDPRELOAD_BUFSIZE 512
+#define LDPRELOAD_MAX 8
+
/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
*
* Do NOT use malloc() and friends or pthread_*() code here.
@@ -112,6 +115,11 @@ static inline int validate_soinfo(soinfo *si)
static char ldpaths_buf[LDPATH_BUFSIZE];
static const char *ldpaths[LDPATH_MAX + 1];
+static char ldpreloads_buf[LDPRELOAD_BUFSIZE];
+static const char *ldpreload_names[LDPRELOAD_MAX + 1];
+
+static soinfo *preloads[LDPRELOAD_MAX + 1];
+
int debug_verbosity;
static int pid;
@@ -451,6 +459,7 @@ _do_lookup(soinfo *si, const char *name, unsigned *base)
Elf32_Sym *s;
unsigned *d;
soinfo *lsi = si;
+ int i;
/* Look for symbols in the local scope first (the object who is
* searching). This happens with C++ templates on i386 for some
@@ -459,6 +468,14 @@ _do_lookup(soinfo *si, const char *name, unsigned *base)
if(s != NULL)
goto done;
+ /* Next, look for it in the preloads list */
+ for(i = 0; preloads[i] != NULL; i++) {
+ lsi = preloads[i];
+ s = _do_lookup_in_so(lsi, name, &elf_hash);
+ if(s != NULL)
+ goto done;
+ }
+
for(d = si->dynamic; *d; d += 2) {
if(d[0] == DT_NEEDED){
lsi = (soinfo *)d[1];
@@ -1866,6 +1883,23 @@ static int link_image(soinfo *si, unsigned wr_offset)
goto fail;
}
+ /* if this is the main executable, then load all of the preloads now */
+ if(si->flags & FLAG_EXE) {
+ int i;
+ memset(preloads, 0, sizeof(preloads));
+ for(i = 0; ldpreload_names[i] != NULL; i++) {
+ 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);
+ goto fail;
+ }
+ lsi->refcount++;
+ preloads[i] = lsi;
+ }
+ }
+
for(d = si->dynamic; *d; d += 2) {
if(d[0] == DT_NEEDED){
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
@@ -1982,6 +2016,30 @@ static void parse_library_path(char *path, char *delim)
}
}
+static void parse_preloads(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') {
+ ++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;
+ } else {
+ ldpreload_names[i] = NULL;
+ }
+}
+
int main(int argc, char **argv)
{
return 0;
@@ -2001,6 +2059,7 @@ unsigned __linker_init(unsigned **elfdata)
soinfo *si;
struct link_map * map;
char *ldpath_env = NULL;
+ char *ldpreload_env = NULL;
/* Setup a temporary TLS area that is used to get a working
* errno for system calls.
@@ -2032,6 +2091,8 @@ unsigned __linker_init(unsigned **elfdata)
debug_verbosity = atoi(((char*) vecs[0]) + 6);
} else if(!strncmp((char*) vecs[0], "LD_LIBRARY_PATH=", 16)) {
ldpath_env = (char*) vecs[0] + 16;
+ } else if(!strncmp((char*) vecs[0], "LD_PRELOAD=", 11)) {
+ ldpreload_env = (char*) vecs[0] + 11;
}
vecs++;
}
@@ -2095,6 +2156,10 @@ unsigned __linker_init(unsigned **elfdata)
if (ldpath_env && getuid() == geteuid() && getgid() == getegid())
parse_library_path(ldpath_env, ":");
+ if (ldpreload_env && getuid() == geteuid() && getgid() == getegid()) {
+ parse_preloads(ldpreload_env, " :");
+ }
+
if(link_image(si, 0)) {
char errmsg[] = "CANNOT LINK EXECUTABLE\n";
write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));