From owner-freebsd-bugs Wed Jun 30 22:50:21 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id E181215605 for ; Wed, 30 Jun 1999 22:50:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id WAA24438; Wed, 30 Jun 1999 22:50:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from iclub.nsu.ru (iclub.nsu.ru [193.124.222.66]) by hub.freebsd.org (Postfix) with ESMTP id 3E21F14D46 for ; Wed, 30 Jun 1999 22:45:41 -0700 (PDT) (envelope-from fjoe@iclub.nsu.ru) Received: (from fjoe@localhost) by iclub.nsu.ru (8.9.3/8.9.3) id MAA26360; Thu, 1 Jul 1999 12:45:10 +0700 (NSS) (envelope-from fjoe) Message-Id: <199907010545.MAA26360@iclub.nsu.ru> Date: Thu, 1 Jul 1999 12:45:10 +0700 (NSS) From: fjoe@iclub.nsu.ru Reply-To: fjoe@iclub.nsu.ru To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: bin/12471: rtld-elf error handling in dlopen is broken Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >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 void f() { printf("Hello, world!\n"); g(); } --- cut here --- --- cut here (main4.c) --- #include #include #include 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