fix theoretical out-of-bound access in dynamic linker
[musl] / src / ldso / dynlink.c
index 59ec5b7..2f399a5 100644 (file)
@@ -320,6 +320,10 @@ static void *map_library(int fd, struct dso *dso)
        ssize_t l = read(fd, buf, sizeof buf);
        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') {
@@ -456,7 +467,7 @@ static struct dso *load_library(const char *name)
                char *z = strchr(name, '.');
                if (z) {
                        size_t l = z-name;
-                       for (rp=reserved; *rp && memcmp(name+3, rp, l-3); rp+=strlen(rp)+1);
+                       for (rp=reserved; *rp && strncmp(name+3, rp, l-3); rp+=strlen(rp)+1);
                        if (*rp) {
                                if (ldd_mode) {
                                        /* Track which names have been resolved
@@ -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);