diff options
author | Rich Felker <dalias@aerifal.cx> | 2012-07-11 01:41:20 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2012-07-11 01:41:20 -0400 |
commit | 0420b874465db7544a9e1f320969b4920c9405d8 (patch) | |
tree | a6685f74c0ae8dd478a300533c3054516d7f121a /src/ldso/dynlink.c | |
parent | bd1cf09c375e56c7fba6b7a1036b33b9591b5dba (diff) | |
download | musl-0420b874465db7544a9e1f320969b4920c9405d8.tar.gz |
fix lots of breakage on dlopen, mostly with explicit pathnames
most importantly, the name for such libs was being set from an
uninitialized buffer. also, shortname always had an initial '/'
character, making it useless for looking up already-loaded libraries
by name, and thus causing repeated searches through the library path.
major changes now:
- shortname is the base name for library lookups with no explicit
pathname. it's initially clear for libraries loaded with an explicit
pathname (and for the main program), but will be set if the same
library (detected via inodes match) is later found by a search.
- exact name match is never used to identify libraries loaded with an
explicit pathname. in this case, there's no explicit search, so we
can just stat the file and check for inode match.
Diffstat (limited to 'src/ldso/dynlink.c')
-rw-r--r-- | src/ldso/dynlink.c | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 263593ab..0a64ef8a 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -322,6 +322,7 @@ static void decode_dyn(struct dso *p) static struct dso *load_library(const char *name) { char buf[2*NAME_MAX+2]; + const char *pathname; unsigned char *base, *map; size_t dyno, map_len; struct dso *p; @@ -346,16 +347,17 @@ static struct dso *load_library(const char *name) } } } - /* Search for the name to see if it's already loaded */ - for (p=head->next; p; p=p->next) { - if (!strcmp(p->shortname, name)) { - p->refcnt++; - return p; - } - } if (strchr(name, '/')) { + pathname = name; fd = open(name, O_RDONLY); } else { + /* Search for the name to see if it's already loaded */ + for (p=head->next; p; p=p->next) { + if (p->shortname && !strcmp(p->shortname, name)) { + p->refcnt++; + return p; + } + } if (strlen(name) > NAME_MAX) return 0; fd = -1; if (r_path) fd = path_open(name, r_path, buf, sizeof buf); @@ -372,6 +374,7 @@ static struct dso *load_library(const char *name) if (sys_path) fd = path_open(name, sys_path, buf, sizeof buf); else fd = path_open(name, "/lib:/usr/local/lib:/usr/lib", buf, sizeof buf); } + pathname = buf; } if (fd < 0) return 0; if (fstat(fd, &st) < 0) { @@ -380,6 +383,10 @@ static struct dso *load_library(const char *name) } for (p=head->next; p; p=p->next) { if (p->dev == st.st_dev && p->ino == st.st_ino) { + /* If this library was previously loaded with a + * pathname but a search found the same inode, + * setup its shortname so it can be found by name. */ + if (!p->shortname) p->shortname = strrchr(p->name, '/')+1; close(fd); p->refcnt++; return p; @@ -388,7 +395,7 @@ static struct dso *load_library(const char *name) map = map_library(fd, &map_len, &base, &dyno); close(fd); if (!map) return 0; - p = calloc(1, sizeof *p + strlen(buf) + 1); + p = calloc(1, sizeof *p + strlen(pathname) + 1); if (!p) { munmap(map, map_len); return 0; @@ -404,15 +411,15 @@ static struct dso *load_library(const char *name) p->ino = st.st_ino; p->refcnt = 1; p->name = p->buf; - strcpy(p->name, buf); - if (!strchr(name, '/')) p->shortname = strrchr(p->name, '/'); - if (!p->shortname) p->shortname = p->name; + strcpy(p->name, pathname); + /* Add a shortname only if name arg was not an explicit pathname. */ + if (pathname != name) p->shortname = strrchr(p->name, '/')+1; tail->next = p; p->prev = tail; tail = p; - if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, buf, base); + if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, pathname, base); return p; } @@ -576,7 +583,7 @@ void *__dynlink(int argc, char **argv) if (phdr->p_type == PT_PHDR) app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr); } - app->name = app->shortname = argv[0]; + app->name = argv[0]; app->dynv = (void *)(app->base + find_dyn( (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT])); } else { @@ -605,7 +612,7 @@ void *__dynlink(int argc, char **argv) } runtime = 0; close(fd); - app->name = app->shortname = argv[0]; + app->name = argv[0]; app->dynv = (void *)(app->base + dyno); aux[AT_ENTRY] = ehdr->e_entry; } |