From owner-freebsd-arch@FreeBSD.ORG Tue Mar 10 17:02:22 2009 Return-Path: Delivered-To: arch@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0FB49106564A; Tue, 10 Mar 2009 17:02:22 +0000 (UTC) (envelope-from ambrisko@ambrisko.com) Received: from mail.ambrisko.com (mail.ambrisko.com [64.174.51.43]) by mx1.freebsd.org (Postfix) with ESMTP id 9D58D8FC14; Tue, 10 Mar 2009 17:02:21 +0000 (UTC) (envelope-from ambrisko@ambrisko.com) X-Ambrisko-Me: Yes Received: from server2.ambrisko.com (HELO www.ambrisko.com) ([192.168.1.2]) by ironport.ambrisko.com with ESMTP; 10 Mar 2009 10:03:09 -0700 Received: from ambrisko.com (localhost [127.0.0.1]) by www.ambrisko.com (8.14.3/8.14.1) with ESMTP id n2AH2LcJ086299; Tue, 10 Mar 2009 10:02:21 -0700 (PDT) (envelope-from ambrisko@ambrisko.com) Received: (from ambrisko@localhost) by ambrisko.com (8.14.3/8.14.3/Submit) id n2AH2LJK086298; Tue, 10 Mar 2009 10:02:21 -0700 (PDT) (envelope-from ambrisko) From: Doug Ambrisko Message-Id: <200903101702.n2AH2LJK086298@ambrisko.com> In-Reply-To: To: brooks@freebsd.org Date: Tue, 10 Mar 2009 10:02:21 -0700 (PDT) X-Mailer: ELM [version 2.4ME+ PL94b (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII Cc: arch@freebsd.org Subject: Re: rtld enhancement to add osversion sub-directory search X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Mar 2009 17:02:22 -0000 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