From 27f1b2c66c67e601dd619a1def70a8fd7ca5eeba Mon Sep 17 00:00:00 2001 From: Leonid Lisovskiy Date: Wed, 13 Jan 2016 21:00:05 +0300 Subject: libdl: dlopen() mustn't forget RTLD_NODELETE flag If RTLD_NODELETE is passed to dlopen() rather than set on shared library itself, flag propagation to rtld_flags is missed. Test-case taken from glibc. Signed-off-by: Leonid Lisovskiy Signed-off-by: Waldemar Brodkorb --- ldso/libdl/libdl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'ldso/libdl') diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index 2c4b06411..08619bc37 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -394,7 +394,7 @@ static void *do_dlopen(const char *libname, int flag, ElfW(Addr) from) dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); memset(dyn_chain, 0, sizeof(struct dyn_elf)); dyn_chain->dyn = tpnt; - tpnt->rtld_flags |= (flag & RTLD_GLOBAL); + tpnt->rtld_flags |= (flag & (RTLD_GLOBAL|RTLD_NODELETE)); dyn_chain->next_handle = _dl_handles; _dl_handles = dyn_ptr = dyn_chain; @@ -407,7 +407,7 @@ static void *do_dlopen(const char *libname, int flag, ElfW(Addr) from) dyn_chain->init_fini.init_fini = handle->init_fini.init_fini; dyn_chain->init_fini.nlist = handle->init_fini.nlist; for (i = 0; i < dyn_chain->init_fini.nlist; i++) - dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL); + dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & (RTLD_GLOBAL|RTLD_NODELETE)); dyn_chain->next = handle->next; break; } @@ -439,7 +439,7 @@ static void *do_dlopen(const char *libname, int flag, ElfW(Addr) from) if (!tpnt1) goto oops; - tpnt1->rtld_flags |= (flag & RTLD_GLOBAL); + tpnt1->rtld_flags |= (flag & (RTLD_GLOBAL|RTLD_NODELETE)); /* This list is for dlsym() and relocation */ dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); -- cgit v1.2.3