rtld enhancement to add osversion sub-directory search
Doug Ambrisko
ambrisko at ambrisko.com
Tue Mar 10 10:02:22 PDT 2009
Doug Ambrisko writes:
| Brooks Davis writes:
| | On Fri, Feb 13, 2009 at 01:08:56PM -0800, Doug Ambrisko wrote:
| | > David Schultz writes:
| | > | On Thu, Feb 12, 2009, Doug Ambrisko wrote:
| | > | > Kostik Belousov writes:
| | > | > | There is a popular feature, unfortunately, not supported by FreeBSD
| | > | > | ld.so, called Dynamic String Tokens, see
| | > | > | http://docs.sun.com/app/docs/doc/817-1984/appendixc-4?l=en&a=view
| | > | > |
| | > | > | I have almost abandoned patch that adds support for $ORIGIN, $OSREL,
| | > | > | $OSNAME, and $PLATFORM. Quite amazingly, it merged with today CURRENT
| | > | > | without serious conflicts.
| | > | > | http://people.freebsd.org/~kib/misc/rtld_locks.4.patch
| | > | >
| | > | > That is an interesting feature, however, it almost seems backwards for
| | > | > me if I understand it correctly. I need old binaries to find the library
| | > | > it was built with and not new ones based on the base OS. The plus that
| | > | > I see with their feature is for a library that has been optimized for a
| | > | > specific type of CPU etc.
| | > |
| | > | The Solaris rtld features are very useful when you want to
| | > | export a volume with a bunch of apps over NFS, and the clients are
| | > | running different releases or different architectures. It can
| | > | probably also solve your problem if you bother to place different
| | > | library versions in different directories and set your library
| | > | path appropriately.
| | >
| | > Unless I missed something it seems to be an inverse feature to
| | > what I want since it expands based on the current kernel's
| | > uname type results. I need it to expand based on the original OS
| | > that it was built on. I'll have to see if my Solaris box at work
| | > has this feature or not. I can't change LD_LIBRARY_PATH etc.
| | > type things. Doing ldconfig -m of various things doesn't help
| | > since that can find the wrong one. My idea was to do something
| | > like what happens for 32bit on 64bit and Linux on FreeBSD in that
| | > it looks at osversion specific places then the standard.
| |
| | While I commented on the Dynamic String Tokens and think it might be
| | useful, that's a distraction for your proposal. I think you proposal
| | sounds useful as well. If it was in 7 by the time I upgrade my cluster
| | from 6, I'd probably use it to ease the transition.
|
| Since my scheme seems useful, then I'll proceed to clean up my patch
| some more then send it out for people to play with and comment on.
Below is the patch, got tied up with other issues. It include the
LD32_ then LD_ search as well. I use LD_MAP_UNKNOWN_OS_VERSION
to set the default version if the .note version is missing.
Once this gets into shape then I'll update the man page.
Thanks for looking,
Doug A.
Index: rtld.c
===================================================================
RCS file: /cvs/src/libexec/rtld-elf/rtld.c,v
retrieving revision 1.128
diff -u -p -w -r1.128 rtld.c
--- rtld.c 10 Oct 2008 00:16:32 -0000 1.128
+++ rtld.c 24 Feb 2009 00:05:10 -0000
@@ -103,7 +103,7 @@ static bool is_exported(const Elf_Sym *)
static void linkmap_add(Obj_Entry *);
static void linkmap_delete(Obj_Entry *);
static int load_needed_objects(Obj_Entry *);
-static int load_preload_objects(void);
+static int load_preload_objects(char *);
static Obj_Entry *load_object(const char *, const Obj_Entry *);
static Obj_Entry *obj_from_addr(const void *);
static void objlist_call_fini(Objlist *, int *lockstate);
@@ -157,6 +157,11 @@ static char *ld_debug; /* Environment v
static char *ld_library_path; /* Environment variable for search path */
static char *ld_preload; /* Environment variable for libraries to
load first */
+#ifdef COMPAT_32BIT
+static char *ld32_library_path; /* Environment variable for search path */
+static char *ld32_preload; /* Environment variable for libraries to
+ load first */
+#endif
static char *ld_tracing; /* Called from ldd to print libs */
static char *ld_utrace; /* Use utrace() to log events. */
static Obj_Entry *obj_list; /* Head of linked list of shared objects */
@@ -284,6 +289,15 @@ ld_utrace_log(int event, void *handle, v
}
/*
+ * OS Versions to try. Will iterate through the string list looking for
+ * sub-directories with that name. When a NULL is found it will stop
+ * iterating through the list. To search the standard location a ""
+ * version needs to be listed before the NULL.
+ */
+static char *os_version_try[] = {NULL, NULL, NULL};
+#define OS_VERSION_LEN 10 /* max ascii size of int */
+#define OS_VERSION_MAJOR 100000 /* divisor to get os major */
+/*
* Main entry point for dynamic linking. The first argument is the
* stack pointer. The stack is expected to be laid out as described
* in the SVR4 ABI specification, Intel 386 Processor Supplement.
@@ -363,6 +377,13 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
unsetenv(LD_ "LIBRARY_PATH");
unsetenv(LD_ "LIBMAP_DISABLE");
unsetenv(LD_ "DEBUG");
+#ifdef COMPAT_32BIT
+ unsetenv(LD_32_ "PRELOAD");
+ unsetenv(LD_32_ "LIBMAP");
+ unsetenv(LD_32_ "LIBRARY_PATH");
+ unsetenv(LD_32_ "LIBMAP_DISABLE");
+ unsetenv(LD_32_ "DEBUG");
+#endif
}
ld_debug = getenv(LD_ "DEBUG");
libmap_disable = getenv(LD_ "LIBMAP_DISABLE") != NULL;
@@ -373,6 +394,23 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
(ld_library_path != NULL) || (ld_preload != NULL);
ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS");
ld_utrace = getenv(LD_ "UTRACE");
+#ifdef COMPAT_32BIT
+ ld_debug = getenv(LD_32_ "DEBUG");
+ libmap_disable = getenv(LD_32_ "LIBMAP_DISABLE") != NULL;
+ libmap_override = getenv(LD_32_ "LIBMAP");
+ ld32_library_path = getenv(LD_32_ "LIBRARY_PATH");
+ ld32_preload = getenv(LD_32_ "PRELOAD");
+ if (ld32_library_path == NULL)
+ ld32_library_path = ld_library_path;
+ if (ld32_preload == NULL)
+ ld32_preload = ld_preload;
+ dangerous_ld_env = libmap_disable || (libmap_override != NULL) ||
+ (ld32_library_path != NULL) || (ld32_preload != NULL) ||
+ (ld_library_path != NULL) || (ld_preload != NULL);
+ dangerous_ld_env = 0;
+ ld_tracing = getenv(LD_32_ "TRACE_LOADED_OBJECTS");
+ ld_utrace = getenv(LD_32_ "UTRACE");
+#endif
if (ld_debug != NULL && *ld_debug != '\0')
debug = 1;
@@ -409,6 +447,25 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
if ((obj_main = digest_phdr(phdr, phnum, entry, argv0)) == NULL)
die();
}
+ if (obj_main->ndesc != NULL && strcmp(obj_main->ndesc, "FreeBSD") == 0) {
+ os_version_try[0] = xmalloc(OS_VERSION_LEN);
+ snprintf(os_version_try[0], OS_VERSION_LEN, "%d", obj_main->nver);
+ os_version_try[1] = xmalloc(OS_VERSION_LEN);
+ snprintf(os_version_try[1], OS_VERSION_LEN, "%d", obj_main->nver
+ / OS_VERSION_MAJOR);
+ os_version_try[2] = "";
+ } else {
+ /* Deal with FreeBSD 6 binaries that are missing version */
+ os_version_try[0] = getenv(LD_ "MAP_UNKNOWN_OS_VERSION");
+ if (os_version_try[0] == NULL) {
+ os_version_try[0] = "";
+ } else {
+ os_version_try[1] = xmalloc(OS_VERSION_LEN);
+ snprintf(os_version_try[1], OS_VERSION_LEN, "%d",
+ atoi(os_version_try[0]) / OS_VERSION_MAJOR);
+ os_version_try[2] = "";
+ }
+ }
obj_main->path = xstrdup(argv0);
obj_main->mainprog = true;
@@ -447,8 +504,14 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
libmap_disable = (bool)lm_init(libmap_override);
dbg("loading LD_PRELOAD libraries");
- if (load_preload_objects() == -1)
+#ifdef COMPAT_32BIT
+ if (load_preload_objects(ld32_preload) == -1)
+ if (load_preload_objects(ld_preload) == -1)
die();
+#else
+ if (load_preload_objects(ld_preload) == -1)
+ die();
+#endif
preload_tail = obj_tail;
dbg("loading needed objects");
@@ -861,12 +924,24 @@ digest_phdr(const Elf_Phdr *phdr, int ph
Obj_Entry *obj;
const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph;
+ const Elf_Note *nh;
int nsegs = 0;
obj = obj_new();
for (ph = phdr; ph < phlimit; ph++) {
switch (ph->p_type) {
+ case PT_NOTE:
+ nh = ((const Elf_Note *)(const Elf_Phdr *)ph->p_vaddr);
+ if (nh->n_type == NT_PRSTATUS) {
+ obj->ndesc = &((char *)((const Elf_Phdr *)ph->p_vaddr))
+ [sizeof(nh->n_namesz) + sizeof(nh->n_descsz) + sizeof(nh->n_type)];
+ obj->nver = *(u_int32_t *)(&((const char *)((const Elf_Phdr *)ph->p_vaddr))
+ [sizeof(nh->n_namesz) + sizeof(nh->n_descsz) + sizeof(nh->n_type)
+ + ((const Elf_Note *)(const Elf_Phdr *)ph->p_vaddr)->n_namesz]);
+ }
+ break;
+
case PT_PHDR:
if ((const Elf_Phdr *)ph->p_vaddr != phdr) {
_rtld_error("%s: invalid PT_PHDR", path);
@@ -994,6 +1069,9 @@ find_library(const char *xname, const Ob
{
char *pathname;
char *name;
+ int i;
+ char *temp;
+ char new_path[PATH_MAX];
if (strchr(xname, '/') != NULL) { /* Hard coded pathname */
if (xname[0] != '/' && !trust) {
@@ -1001,7 +1079,24 @@ find_library(const char *xname, const Ob
xname);
return NULL;
}
- return xstrdup(xname);
+ for (i = 0; os_version_try[i] != NULL; i++) {
+ if (os_version_try[i][0] == '\0')
+ temp = (char *)xname;
+ else {
+ bzero(new_path, sizeof(new_path));
+ bcopy(xname, new_path, strlen(xname) + 1);
+ temp = rindex(new_path, '/');
+ temp++;
+ *temp = '\0';
+ strncat(new_path, os_version_try[i], sizeof(new_path));
+ temp = rindex(xname, '/');
+ strncat(new_path, temp, sizeof(new_path));
+ temp = new_path;
+ }
+ if (access(temp, F_OK) == 0)
+ return xstrdup(temp);
+ }
+ return NULL;
}
if (libmap_disable || (refobj == NULL) ||
@@ -1010,6 +1105,14 @@ find_library(const char *xname, const Ob
dbg(" Searching for \"%s\"", name);
+#ifdef COMPAT_32BIT
+ if ((pathname = search_library_path(name, ld32_library_path)) != NULL ||
+ (refobj != NULL &&
+ (pathname = search_library_path(name, refobj->rpath)) != NULL) ||
+ (pathname = search_library_path(name, gethints())) != NULL ||
+ (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL)
+ return pathname;
+#endif
if ((pathname = search_library_path(name, ld_library_path)) != NULL ||
(refobj != NULL &&
(pathname = search_library_path(name, refobj->rpath)) != NULL) ||
@@ -1311,9 +1414,9 @@ load_needed_objects(Obj_Entry *first)
}
static int
-load_preload_objects(void)
+load_preload_objects(char *preload)
{
- char *p = ld_preload;
+ char *p = preload;
static const char delim[] = " \t:;";
if (p == NULL)
@@ -1326,6 +1429,7 @@ load_preload_objects(void)
savech = p[len];
p[len] = '\0';
+ if (find_library(p, NULL) != NULL)
if (load_object(p, NULL) == NULL)
return -1; /* XXX - cleanup */
p[len] = savech;
@@ -1731,26 +1835,36 @@ static void *
try_library_path(const char *dir, size_t dirlen, void *param)
{
struct try_library_args *arg;
+ char *version = NULL;
+ int temp_dirlen, i;
arg = param;
if (*dir == '/' || trust) {
char *pathname;
- if (dirlen + 1 + arg->namelen + 1 > arg->buflen)
- return (NULL);
-
+ for (i = 0; os_version_try[i] != NULL; i++) {
+ if (dirlen + 1 + arg->namelen + 1 + strlen(os_version_try[i]) + 1 > arg->buflen)
+ continue;
+ version = os_version_try[i];
+ temp_dirlen = dirlen;
pathname = arg->buffer;
- strncpy(pathname, dir, dirlen);
- pathname[dirlen] = '/';
- strcpy(pathname + dirlen + 1, arg->name);
-
+ pathname[0] = '\000';
+ strncpy(pathname, dir, temp_dirlen);
+ pathname[temp_dirlen] = '/';
+ if (version[0] != '\000') {
+ strcpy(pathname + temp_dirlen + 1, version);
+ temp_dirlen += strlen(os_version_try[i]) + 1;
+ pathname[temp_dirlen] = '/';
+ }
+ strcpy(pathname + temp_dirlen + 1, arg->name);
dbg(" Trying \"%s\"", pathname);
if (access(pathname, F_OK) == 0) { /* We found it */
- pathname = xmalloc(dirlen + 1 + arg->namelen + 1);
+ pathname = xmalloc(temp_dirlen + 1 + arg->namelen + 1);
strcpy(pathname, arg->buffer);
return (pathname);
}
}
+ }
return (NULL);
}
@@ -2729,8 +2843,9 @@ trace_loaded_objects(Obj_Entry *obj)
printf("%s:\n", obj->path);
for (needed = obj->needed; needed; needed = needed->next) {
if (needed->obj != NULL) {
- if (needed->obj->traced && !list_containers)
+ if (needed->obj->traced && !list_containers) {
continue;
+ }
needed->obj->traced = true;
path = needed->obj->path;
} else
Index: rtld.h
===================================================================
RCS file: /cvs/src/libexec/rtld-elf/rtld.h,v
retrieving revision 1.39
diff -u -p -w -r1.39 rtld.h
--- rtld.h 4 Apr 2008 20:59:26 -0000 1.39
+++ rtld.h 24 Feb 2009 00:05:10 -0000
@@ -45,7 +45,7 @@
#define _PATH_ELF_HINTS "/var/run/ld-elf32.so.hints"
/* For running 32 bit binaries */
#define STANDARD_LIBRARY_PATH "/lib32:/usr/lib32"
-#define LD_ "LD_32_"
+#define LD_32_ "LD_32_"
#endif
#ifndef STANDARD_LIBRARY_PATH
@@ -223,6 +223,9 @@ typedef struct Struct_Obj_Entry {
dev_t dev; /* Object's filesystem's device */
ino_t ino; /* Object's inode number */
void *priv; /* Platform-dependant */
+
+ char *ndesc; /* Note Description */
+ u_int32_t nver; /* FreeBSD Version */
} Obj_Entry;
#define RTLD_MAGIC 0xd550b87a
More information about the freebsd-arch
mailing list