prevent passing PT_INTERP name to dlopen from double-loading libc
authorRich Felker <dalias@aerifal.cx>
Wed, 31 Jul 2013 18:59:36 +0000 (14:59 -0400)
committerRich Felker <dalias@aerifal.cx>
Wed, 31 Jul 2013 18:59:36 +0000 (14:59 -0400)
the dev/inode for the main app and the dynamic linker ("interpreter")
are not available, so the subsequent checks don't work. in general we
don't want to make exact string matches to existing libraries prevent
loading new ones, since this breaks loading upgraded modules in
module-loading systems. so instead, special-case it.

the motivation for this fix is that calling dlopen on the names
returned by dl_iterate_phdr or walking the link map (obtained by
dlinfo) seem to be the only methods available to an application to
actually get a list of open dso handles.

src/ldso/dynlink.c

index f4988e7371a46eaa44d7957c4e28bef1d56d0679..814f5c7e4ec0da2be423463f630730e9df06fa00 100644 (file)
@@ -458,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') {
@@ -480,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);