Subject: bin/5890: dlsym() of ld.elf_so searches wrong objects
To: None <gnats-bugs@gnats.netbsd.org>
From: None <yasufu-i@is.aist-nara.ac.jp>
List: netbsd-bugs
Date: 08/01/1998 17:40:42
>Number:         5890
>Category:       bin
>Synopsis:       dlsym() of ld.elf_so searches wrong objects
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Aug  1 01:50:00 1998
>Last-Modified:
>Originator:     ITOH Yasufumi
>Organization:
	Nara Institute of Science and Technology, Nara, Japan
>Release:        1.3F (July 31, 1998)
>Environment:
System: NetBSD libble.my.domain 1.3F NetBSD 1.3F (LIBBLE) #1: Sat Jul 25 03:56:40 JST 1998 itohy@libble.my.domain:/usr/src/sys/arch/alpha/compile/LIBBLE alpha


>Description:
	dlsym() of ELF (in /usr/libexec/ld.elf_so) searches
	not the specified (by dlopen()) object,
	but the currently loaded objects.

	This makes dlopen() useless.

>How-To-Repeat:
	Here is an example program.  Save this as  "foo.c".

	Note that some architectures insert an "_" at the top
	of C symbol names.
	If you try running this on such architecture, please insert
	"_" to the each of the 2nd arg of dlsym() (e.g. "_mkdir").

BEGIN--cut here--cut here
#include <dlfcn.h>

int printf(const char *, ...);
double sin();
int mkfifo();

/* fake version of libc function */
mkdir()
{
	return 0;
}

main()
{
	void *handle, *libc_mkdir, *libc_mkfifo, *libc_sin;

	/* we're going to lookup in libc.so */
	handle  = dlopen("libc.so", RTLD_LAZY);
	printf("(a) handle %p\n", handle);

	libc_mkdir = dlsym(handle, "mkdir");
	printf("(b) libc_mkdir %p, mkdir %p\n", libc_mkdir, mkdir);

	libc_mkfifo = dlsym(handle, "mkfifo");
	printf("(c) libc_mkfifo %p, mkfifo %p\n", libc_mkfifo, mkfifo);

	libc_sin = dlsym(handle, "sin");
	printf("(d) libc_sin %p, sin %p\n", libc_sin, sin);

	return 0;
}
END--cut here--cut here

	Here is a sample run on NetBSD/alpha (ELF):

% cc foo.c -lm
% ./a.out
(a) handle 0x160110600
(b) libc_mkdir 0x120000b60, mkdir 0x120000b60
(c) libc_mkfifo 0x160384ad4, mkfifo 0x160384ad4
(d) libc_sin 0x160224540, sin 0x160224540

	(a) A handle of "libc.so" is open.
	    libc.so is mapped around the address.

	(b) The function "mkdir" is in both the program and the libc.so.
	    dlsym() shall return the address of libc one,
	    but the address is that of the other one, which is 
	    out of the specified object.
	    I think this is wrong.

	(c) dlsym() seems work correct without a local definition
	    (only at a glance?).

	(d) The function "sin" is not defined in libc.so,
	    but an address is returned.  The address is in libm.so.
	    I think this is wrong.
	    The result should be NULL, which indicates "not found."


	Here is a sample run on NetBSD/x68k (a.out) for comparison:
	(I inserted "_" for each symbol name.)

% cc foo.c -lm
% ./a.out
(a) handle 0x40171c0
(b) libc_mkdir 0x4055e0e, mkdir 0x27e0
(c) libc_mkfifo 0x4055dfa, mkfifo 0x4094
(d) libc_sin 0x0, sin 0x408c

	(b) An address in libc.so is returned.  This is correct.
	(d) A NULL (not found) is returned.  This is correct.

>Fix:
	Fix the ld.elf_so so that the dlsym() should search
	the specified (dlopen()'ed) object.

	The following patch is optimized for size, and is somewhat obscure.
	Please make cleaner changes :-).

diff -uF^[a-zA-Z_][a-z 	A-Z0-9_]*(.*[^;]$ src/libexec/ld.elf_so/rtld.c.orig src/libexec/ld.elf_so/rtld.c
--- src/libexec/ld.elf_so/rtld.c.orig	Thu Jul 16 20:08:10 1998
+++ src/libexec/ld.elf_so/rtld.c	Fri Jul 31 18:15:30 1998
@@ -506,10 +506,9 @@ _rtld_dlsym(
 	return NULL;
 
     /*
-     * FIXME - This isn't correct.  The search should include the whole
-     * DAG rooted at the given object.
+     * Search the dlopen()ed object only
      */
-    def = _rtld_find_symdef(_rtld_objlist, 0, name, obj, &defobj, false);
+    def = _rtld_find_symdef(obj, 0, name, NULL, &defobj, false);
     if (def != NULL)
 	return defobj->relocbase + def->st_value;
 
diff -uF^[a-zA-Z_][a-z 	A-Z0-9_]*(.*[^;]$ src/libexec/ld.elf_so/symbol.c.orig src/libexec/ld.elf_so/symbol.c
--- src/libexec/ld.elf_so/symbol.c.orig	Wed Mar 25 21:18:27 1998
+++ src/libexec/ld.elf_so/symbol.c	Fri Jul 31 18:08:33 1998
@@ -137,6 +137,10 @@ _rtld_find_symdef(
     const Elf_Sym *ref;
     const Obj_Entry *obj;
     unsigned long hash;
+    int one_obj_only = (refobj == NULL);
+
+    if (one_obj_only)
+	refobj = obj_list;
 
     if (name == NULL) {
 	ref = refobj->symtab + symnum;
@@ -164,6 +168,8 @@ _rtld_find_symdef(
 		return def;
 	    }
 	}
+	if (one_obj_only)
+	    break;
     }
 
     if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
>Audit-Trail:
>Unformatted: