Date: Thu, 1 Jul 1999 12:45:10 +0700 (NSS) From: fjoe@iclub.nsu.ru To: FreeBSD-gnats-submit@freebsd.org Subject: bin/12471: rtld-elf error handling in dlopen is broken Message-ID: <199907010545.MAA26360@iclub.nsu.ru>
index | next in thread | raw e-mail
>Number: 12471
>Category: bin
>Synopsis: rtld-elf error handling in dlopen is broken
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Wed Jun 30 22:50:01 PDT 1999
>Closed-Date:
>Last-Modified:
>Originator: Max Khon
>Release: FreeBSD 3.2-STABLE i386
>Organization:
Internet Club, Novosibirsk State University
>Environment:
FreeBSD/i386 3.2-STABLE, Jun 19 12:41:40 NSS 1999
-current might be affected too.
>Description:
dlopen returns "valid" dlh when trying to open faulty
object second time.
>How-To-Repeat:
in the following code `dlopen' returns NULL
on the first iteration (because g() is not defined) -- it's ok
but on the second iteration `dlopen' returns "valid" dlh
--- cut here (Makefile) ---
CFLAGS = -g
all: dl.so main4
dl.so: dl.c
gcc -o dl.so $(CFLAGS) -shared -fpic -fPIC dl.c
main4: main4.o
gcc -o main4 -export-dynamic main4.o
clean:
rm -f dl.so main4.o
--- cut here ---
--- cut here (dl.c) ---
#include <stdio.h>
void f()
{
printf("Hello, world!\n");
g();
}
--- cut here ---
--- cut here (main4.c) ---
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
void *dlh = NULL;
void (*f)(void);
for (;;) {
getchar();
if (dlh != NULL) {
dlclose(dlh);
dlh = NULL;
}
dlh = dlopen("./dl.so", RTLD_NOW);
if (dlh == NULL) {
fprintf(stderr, "dlopen: %s\n", dlerror());
continue;
}
f = dlsym(dlh, "f");
if (f == NULL) {
fprintf(stderr, "dlsym: %s\n", dlerror());
dlh = NULL;
continue;
}
f();
}
dlclose(dlh);
return 0;
}
--- cut here ---
>Fix:
This is a patch for libexec/rtld-elf/rtld.c (-stable).
*** rtld.c.orig Thu Jul 1 12:00:50 1999
--- rtld.c Thu Jul 1 12:23:17 1999
*************** static void linkmap_delete(Obj_Entry *);
*** 84,89 ****
--- 84,90 ----
static int load_needed_objects(Obj_Entry *);
static int load_preload_objects(void);
static Obj_Entry *load_object(char *);
+ static void unload_object(Obj_Entry *obj, bool fini_self);
static Obj_Entry *obj_from_addr(const void *);
static int relocate_objects(Obj_Entry *, bool);
static void rtld_exit(void);
*************** load_object(char *path)
*** 967,972 ****
--- 968,1010 ----
return obj;
}
+ static void unload_object(Obj_Entry *root, bool fini_self)
+ {
+ root->dl_refcount--;
+ unref_object_dag(root);
+ if (root->refcount == 0) { /* We are finished with some objects. */
+ Obj_Entry *obj;
+ Obj_Entry **linkp;
+
+ /* Finalize objects that are about to be unmapped. */
+ for (obj = obj_list->next; obj != NULL; obj = obj->next) {
+ if (!fini_self && obj == root)
+ break;
+ if (obj->refcount == 0 && obj->fini != NULL)
+ (*obj->fini)();
+ }
+
+ /* Unmap all objects that are no longer referenced. */
+ linkp = &obj_list->next;
+ while ((obj = *linkp) != NULL) {
+ if (obj->refcount == 0) {
+ munmap(obj->mapbase, obj->mapsize);
+ free(obj->path);
+ while (obj->needed != NULL) {
+ Needed_Entry *needed = obj->needed;
+ obj->needed = needed->next;
+ free(needed);
+ }
+ linkmap_delete(obj);
+ *linkp = obj->next;
+ free(obj);
+ } else
+ linkp = &obj->next;
+ }
+ obj_tail = linkp;
+ }
+ }
+
static Obj_Entry *
obj_from_addr(const void *addr)
{
*************** dlclose(void *handle)
*** 1106,1143 ****
return -1;
GDB_STATE(RT_DELETE);
!
! root->dl_refcount--;
! unref_object_dag(root);
! if (root->refcount == 0) { /* We are finished with some objects. */
! Obj_Entry *obj;
! Obj_Entry **linkp;
!
! /* Finalize objects that are about to be unmapped. */
! for (obj = obj_list->next; obj != NULL; obj = obj->next)
! if (obj->refcount == 0 && obj->fini != NULL)
! (*obj->fini)();
!
! /* Unmap all objects that are no longer referenced. */
! linkp = &obj_list->next;
! while ((obj = *linkp) != NULL) {
! if (obj->refcount == 0) {
! munmap(obj->mapbase, obj->mapsize);
! free(obj->path);
! while (obj->needed != NULL) {
! Needed_Entry *needed = obj->needed;
! obj->needed = needed->next;
! free(needed);
! }
! linkmap_delete(obj);
! *linkp = obj->next;
! free(obj);
! } else
! linkp = &obj->next;
! }
! obj_tail = linkp;
! }
!
GDB_STATE(RT_CONSISTENT);
return 0;
--- 1144,1150 ----
return -1;
GDB_STATE(RT_DELETE);
! unload_object(root, true);
GDB_STATE(RT_CONSISTENT);
return 0;
*************** dlopen(const char *name, int mode)
*** 1174,1183 ****
/* XXX - Clean up properly after an error. */
if (load_needed_objects(obj) == -1) {
! obj->dl_refcount--;
obj = NULL;
} else if (relocate_objects(obj, mode == RTLD_NOW) == -1) {
! obj->dl_refcount--;
obj = NULL;
} else
call_init_functions(obj);
--- 1181,1192 ----
/* XXX - Clean up properly after an error. */
if (load_needed_objects(obj) == -1) {
! GDB_STATE(RT_DELETE);
! unload_object(obj, false);
obj = NULL;
} else if (relocate_objects(obj, mode == RTLD_NOW) == -1) {
! GDB_STATE(RT_DELETE);
! unload_object(obj, false);
obj = NULL;
} else
call_init_functions(obj);
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199907010545.MAA26360>
