fix char signedness bug in dynlinker hash function
[musl] / src / ldso / dynlink.c
index ced1637..86d4b80 100644 (file)
@@ -1,3 +1,4 @@
+#ifdef __PIC__
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -60,7 +61,7 @@ static int runtime;
 static jmp_buf rtld_fail;
 static pthread_rwlock_t lock;
 
-#define AUX_CNT 15
+#define AUX_CNT 24
 #define DYN_CNT 34
 
 static void decode_vec(size_t *v, size_t *a, size_t cnt)
@@ -72,8 +73,9 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt)
        }
 }
 
-static uint32_t hash(const char *s)
+static uint32_t hash(const char *s0)
 {
+       const unsigned char *s = (void *)s0;
        uint_fast32_t h = 0;
        while (*s) {
                h = 16*h + *s++;
@@ -482,6 +484,13 @@ void *__dynlink(int argc, char **argv, size_t *got)
 
        decode_vec(auxv, aux, AUX_CNT);
 
+       /* Only trust user/env if kernel says we're not suid/sgid */
+       if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
+         || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
+               env_path = 0;
+               env_preload = 0;
+       }
+
        for (i=0; auxv[i]; i+=2) {
                if (auxv[i]==AT_SYSINFO_EHDR) {
                        vdso_base = auxv[i+1];
@@ -489,13 +498,6 @@ void *__dynlink(int argc, char **argv, size_t *got)
                }
        }
 
-       /* Only trust user/env if kernel says we're not suid/sgid */
-       if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
-         || aux[AT_GID]!=aux[AT_EGID]) {
-               env_path = 0;
-               env_preload = 0;
-       }
-
        /* Relocate ldso's DYNAMIC pointer and load vector */
        decode_vec((void *)(got[0] += aux[AT_BASE]), lib_dyn, DYN_CNT);
 
@@ -638,11 +640,16 @@ end:
        return p;
 }
 
-static void *do_dlsym(struct dso *p, const char *s)
+static void *do_dlsym(struct dso *p, const char *s, void *ra)
 {
        size_t i;
        uint32_t h;
        Sym *sym;
+       if (p == RTLD_NEXT) {
+               for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
+               if (!p) p=head;
+               p=p->next;
+       }
        if (p == head || p == RTLD_DEFAULT)
                return find_sym(head, s, 0);
        h = hash(s);
@@ -658,11 +665,11 @@ static void *do_dlsym(struct dso *p, const char *s)
        return 0;
 }
 
-void *dlsym(void *p, const char *s)
+void *__dlsym(void *p, const char *s, void *ra)
 {
        void *res;
        pthread_rwlock_rdlock(&lock);
-       res = do_dlsym(p, s);
+       res = do_dlsym(p, s, ra);
        pthread_rwlock_unlock(&lock);
        return res;
 }
@@ -676,3 +683,4 @@ int dlclose(void *p)
 {
        return 0;
 }
+#endif