prevent passing PT_INTERP name to dlopen from double-loading libc
[musl] / src / ldso / dynlink.c
index 1ef981a..814f5c7 100644 (file)
@@ -318,8 +318,12 @@ static void *map_library(int fd, struct dso *dso)
        size_t i;
 
        ssize_t l = read(fd, buf, sizeof buf);
-       if (l<sizeof *eh) return 0;
+       if (l<(int)sizeof *eh) return 0;
        eh = buf;
+       if (eh->e_type != ET_DYN && eh->e_type != ET_EXEC) {
+               errno = ENOEXEC;
+               return 0;
+       }
        phsize = eh->e_phentsize * eh->e_phnum;
        if (phsize + sizeof *eh > l) return 0;
        if (eh->e_phoff + phsize > l) {
@@ -362,6 +366,12 @@ static void *map_library(int fd, struct dso *dso)
         * amount of virtual address space to map over later. */
        map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
        if (map==MAP_FAILED) return 0;
+       /* If the loaded file is not relocatable and the requested address is
+        * not available, then the load operation must fail. */
+       if (eh->e_type != ET_DYN && addr_min && map!=(void *)addr_min) {
+               errno = EBUSY;
+               goto error;
+       }
        base = map - addr_min;
        dso->phdr = 0;
        dso->phnum = 0;
@@ -448,6 +458,7 @@ static struct dso *load_library(const char *name)
        struct stat st;
        size_t alloc_size;
        int n_th = 0;
+       int is_self = 0;
 
        /* Catch and block attempts to reload the implementation itself */
        if (name[0]=='l' && name[1]=='i' && name[2]=='b') {
@@ -470,15 +481,19 @@ static struct dso *load_library(const char *name)
                                                        ldso->base);
                                        }
                                }
-                               if (!ldso->prev) {
-                                       tail->next = ldso;
-                                       ldso->prev = tail;
-                                       tail = ldso->next ? ldso->next : ldso;
-                               }
-                               return ldso;
+                               is_self = 1;
                        }
                }
        }
+       if (!strcmp(name, ldso->name)) is_self = 1;
+       if (is_self) {
+               if (!ldso->prev) {
+                       tail->next = ldso;
+                       ldso->prev = tail;
+                       tail = ldso->next ? ldso->next : ldso;
+               }
+               return ldso;
+       }
        if (strchr(name, '/')) {
                pathname = name;
                fd = open(name, O_RDONLY|O_CLOEXEC);
@@ -715,7 +730,7 @@ static void do_fini()
                        while (n--) ((void (*)(void))*--fn)();
                }
 #ifndef NO_LEGACY_INITFINI
-               if (dyn[0] & (1<<DT_FINI))
+               if ((dyn[0] & (1<<DT_FINI)) && dyn[DT_FINI])
                        ((void (*)(void))(p->base + dyn[DT_FINI]))();
 #endif
        }
@@ -738,7 +753,7 @@ static void do_init_fini(struct dso *p)
                        fini_head = p;
                }
 #ifndef NO_LEGACY_INITFINI
-               if (dyn[0] & (1<<DT_INIT))
+               if ((dyn[0] & (1<<DT_INIT)) && dyn[DT_INIT])
                        ((void (*)(void))(p->base + dyn[DT_INIT]))();
 #endif
                if (dyn[0] & (1<<DT_INIT_ARRAY)) {
@@ -896,7 +911,7 @@ void *__dynlink(int argc, char **argv)
        lib->phdr = (void *)(aux[AT_BASE]+ehdr->e_phoff);
        find_map_range(lib->phdr, ehdr->e_phnum, ehdr->e_phentsize, lib);
        lib->dynv = (void *)(lib->base + find_dyn(lib->phdr,
-                    ehdr->e_phnum, ehdr->e_phentsize));
+               ehdr->e_phnum, ehdr->e_phentsize));
        decode_dyn(lib);
 
        if (aux[AT_PHDR]) {