Index: etc/defaults/rc.conf =================================================================== RCS file: /cvs/src/etc/defaults/rc.conf,v retrieving revision 1.395 diff -u -p -r1.395 rc.conf --- etc/defaults/rc.conf 23 Oct 2011 09:08:42 -0000 1.395 +++ etc/defaults/rc.conf 13 Mar 2012 16:42:12 -0000 @@ -626,6 +626,10 @@ ldconfig_local_dirs="/usr/local/libdata/ ldconfig_local32_dirs="/usr/local/libdata/ldconfig32" # Local directories with 32-bit compatibility ldconfig # configuration files. +#ldconfig_os_versions="6" + # specify OS versions to run ldconfig for +#ldconfig_6_path="/usr/local/lib/compat/6" + # sample FreeBSD 6 library search path kern_securelevel_enable="NO" # kernel security level (see security(7)) kern_securelevel="-1" # range: -1..3 ; `-1' is the most insecure # Note that setting securelevel to 0 will result Index: libexec/rtld-elf/rtld.1 =================================================================== RCS file: /cvs/src/libexec/rtld-elf/rtld.1,v retrieving revision 1.51 diff -u -p -r1.51 rtld.1 --- libexec/rtld-elf/rtld.1 25 Dec 2010 08:51:20 -0000 1.51 +++ libexec/rtld-elf/rtld.1 13 Mar 2012 16:42:12 -0000 @@ -101,10 +101,13 @@ utility recognizes a number of environment variables that can be used to modify its behaviour. On 64-bit architectures, the linker for 32-bit objects recognizes -all the environment variables listed below, but is being prefixed with +all the environment variables listed below, but checks the environment +variables prefixed with .Ev LD_32_ , -for example: -.Ev LD_32_TRACE_LOADED_OBJECTS . +first for example: +.Ev LD_32_TRACE_LOADED_OBJECTS +then +.Ev LD_TRACE_LOADED_OBJECTS . .Bl -tag -width ".Ev LD_LIBMAP_DISABLE" .It Ev LD_DUMP_REL_POST If set, @@ -143,6 +146,9 @@ This variable is unset for set-user-ID a A colon separated list of directories, overriding the default search path for shared libraries. This variable is unset for set-user-ID and set-group-ID programs. +The search mechanism has been extended to search the the sub-directories +of each path for the directory specified by the OSVERSION of the +compiled binary, the OS major and then just the path itself. .It Ev LD_PRELOAD A list of shared libraries, separated by colons and/or white space, to be linked in before any @@ -153,6 +159,9 @@ the directories specified by will be searched first followed by the set of built-in standard directories. This variable is unset for set-user-ID and set-group-ID programs. +The search mechanism has been extend to search the the sub-directories +prefixing the name of the library specified by the OSVERSION of the +compiled binary, the OS major and then nothing at all. .It Ev LD_BIND_NOW When set to a nonempty string, causes .Nm @@ -236,6 +245,10 @@ from the filter object. Hints file. .It Pa /var/run/ld-elf32.so.hints Hints file for 32-bit binaries on 64-bit system. +.It Pa /var/run/ld-elf-.so.hints +Hints file for OS level of the operating system system. +.It Pa /var/run/ld-elf-.so.hints +Hints file for release level of the operating system system. .It Pa /etc/libmap.conf The libmap configuration file. .It Pa /etc/libmap32.conf Index: libexec/rtld-elf/rtld.c =================================================================== RCS file: /cvs/src/libexec/rtld-elf/rtld.c,v retrieving revision 1.179 diff -u -p -r1.179 rtld.c --- libexec/rtld-elf/rtld.c 8 Oct 2011 12:39:47 -0000 1.179 +++ libexec/rtld-elf/rtld.c 13 Mar 2012 16:42:12 -0000 @@ -92,6 +92,7 @@ static void errmsg_restore(char *); static char *errmsg_save(void); static void *fill_search_info(const char *, size_t, void *); static char *find_library(const char *, const Obj_Entry *); +static char *ld_library_path_add_os_version(char *search_path); static const char *gethints(void); static void init_dag(Obj_Entry *); static void init_rtld(caddr_t, Elf_Auxinfo **); @@ -102,7 +103,7 @@ static void linkmap_delete(Obj_Entry *); static void load_filtees(Obj_Entry *, int flags, RtldLockState *); static void unload_filtees(Obj_Entry *); static int load_needed_objects(Obj_Entry *, int); -static int load_preload_objects(void); +static int load_preload_objects(char *); static Obj_Entry *load_object(const char *, const Obj_Entry *, int); static void map_stacks_exec(RtldLockState *); static Obj_Entry *obj_from_addr(const void *); @@ -162,7 +163,15 @@ 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_elf_hints_path; /* Environment variable for alternative hints path */ +#define _PATH_ELF_OS_HINTS_FMT "/var/run/ld-elf-%u.so.hints" +static char *ld_elf_os_hints_path = NULL; /* OS hints path */ +static char *ld_elf_os_major_hints_path = NULL; /* OS major hints path */ 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 */ @@ -269,6 +278,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. @@ -300,6 +318,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_ Obj_Entry **preload_tail; Objlist initlist; RtldLockState lockstate; + size_t len; /* * On entry, the dynamic linker itself has not been relocated yet. @@ -350,6 +369,14 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_ _rtld_error("environment corrupt; aborting"); die(); } +#ifdef COMPAT_32BIT + if (unsetenv(LD_32_ "PRELOAD") || unsetenv(LD_32_ "LIBMAP") || + unsetenv(LD_32_ "LIBRARY_PATH") || unsetenv(LD_32_ "LIBMAP_DISABLE") || + unsetenv(LD_32_ "DEBUG") || unsetenv(LD_32_ "ELF_HINTS_PATH")) { + _rtld_error("environment corrupt; aborting"); + die(); + } +#endif } ld_debug = getenv(LD_ "DEBUG"); libmap_disable = getenv(LD_ "LIBMAP_DISABLE") != NULL; @@ -363,6 +390,25 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_ (ld_elf_hints_path != NULL) || ld_loadfltr; 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"); + if (ld_tracing == NULL) + ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS"); + ld_utrace = getenv(LD_32_ "UTRACE"); +#endif if ((ld_elf_hints_path == NULL) || strlen(ld_elf_hints_path) == 0) ld_elf_hints_path = _PATH_ELF_HINTS; @@ -407,6 +453,26 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_ 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, "%u", obj_main->nver); + os_version_try[1] = xmalloc(OS_VERSION_LEN); + snprintf(os_version_try[1], OS_VERSION_LEN, "%u", obj_main->nver + / OS_VERSION_MAJOR); + os_version_try[2] = ""; + len = sizeof(_PATH_ELF_OS_HINTS_FMT) + OS_VERSION_LEN; + ld_elf_os_hints_path = xmalloc(len); + ld_elf_os_major_hints_path = xmalloc(len); + snprintf(ld_elf_os_hints_path, len, _PATH_ELF_OS_HINTS_FMT, + obj_main->nver); + snprintf(ld_elf_os_major_hints_path, len, + _PATH_ELF_OS_HINTS_FMT, obj_main->nver / OS_VERSION_MAJOR); + ld_library_path = ld_library_path_add_os_version(ld_library_path); +#ifdef COMPAT_32BIT + ld32_library_path = ld_library_path_add_os_version(ld32_library_path); +#endif + } + if (aux_info[AT_EXECPATH] != 0) { char *kexecpath; char buf[MAXPATHLEN]; @@ -467,8 +533,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"); @@ -651,6 +723,58 @@ basename(const char *name) return p != NULL ? p + 1 : name; } +/* + * Helper function to append OS Version and OS major to ld_library + * paths so that forked and exec'ed programs that are from a + * different OS build don't pick up incompatible libraries. To + * use this just put the libraries in a sub-directory based on + * either the OS major release number or OS Version. + */ + +static char * +ld_library_path_add_os_version(char *search_path) +{ + char *path, *new = NULL; + size_t new_len = 0; + + if (search_path == NULL) + return search_path; + + new = xmalloc(1); + *new = '\0'; + path = search_path; + path += strspn(path, ":;"); + while (*path != '\0') { + size_t len; + char temp, *temp_new, *delim = ""; + int i; + + len = strcspn(path, ":;"); + temp = path[len]; + path[len] = '\0'; + + for (i = 0; os_version_try[i] != NULL; i++) { + new_len = strlen(new) + strlen(path) + strlen(os_version_try[i]) + + 3; + temp_new = xcalloc(new_len); + snprintf(temp_new, new_len, "%s%s%s/%s", new, delim, path, + os_version_try[i]); + delim = ":"; + free(new); + new = temp_new; + } + new[strlen(new)] = *delim; + + path[len] = temp; + path += len; + path += strspn(path, ":;"); + } + + /* remove trailing ":" */ + new[strlen(new) - 1] = '\000'; + return new; +} + static struct utsname uts; static int @@ -1043,6 +1167,7 @@ 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(); @@ -1061,6 +1186,18 @@ digest_phdr(const Elf_Phdr *phdr, int ph for (ph = phdr; ph < phlimit; ph++) { switch (ph->p_type) { + case PT_NOTE: + nh = (const Elf_Note *)(ph->p_vaddr + obj->relocbase); + if (nh->n_type == NT_PRSTATUS) { + obj->ndesc = &((char *)nh)[sizeof(nh->n_namesz) + + sizeof(nh->n_descsz) + sizeof(nh->n_type)]; + obj->nver = *(u_int32_t *)(&((const char *) + ((const Elf_Phdr *)(nh))) + [sizeof(nh->n_namesz) + sizeof(nh->n_descsz) + + sizeof(nh->n_type) + nh->n_namesz]); + } + break; + case PT_INTERP: obj->interp = (const char *)(ph->p_vaddr + obj->relocbase); break; @@ -1201,7 +1338,12 @@ 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 || + (pathname = search_library_path(name, ld_library_path)) != NULL || +#else if ((pathname = search_library_path(name, ld_library_path)) != NULL || +#endif (refobj != NULL && (pathname = search_library_path(name, refobj->rpath)) != NULL) || (pathname = search_library_path(name, gethints())) != NULL || @@ -1304,7 +1446,12 @@ find_symdef(unsigned long symnum, const /* * Return the search path from the ldconfig hints file, reading it if * necessary. Returns NULL if there are problems with the hints file, - * or if the search path there is empty. + * or if the search path there is empty. Add capability to search for + * a hints file based on OS Version or OS major. This way, a different + * hints file can be used based on the program being run. Idea from + * 32 bit on 64 bit support. Doing it from the hints file is the + * safest way to ensure no conflict between ports /usr/local/lib and + * standard system libs. */ static const char * gethints(void) @@ -1319,7 +1466,9 @@ gethints(void) /* Keep from trying again in case the hints file is bad. */ hints = ""; - if ((fd = open(ld_elf_hints_path, O_RDONLY)) == -1) + if (((fd = open(ld_elf_os_hints_path, O_RDONLY)) == -1) + && ((fd = open(ld_elf_os_major_hints_path, O_RDONLY)) == -1) + && ((fd = open(ld_elf_hints_path, O_RDONLY)) == -1)) return NULL; if (read(fd, &hdr, sizeof hdr) != sizeof hdr || hdr.magic != ELFHINTS_MAGIC || @@ -1580,10 +1729,12 @@ load_needed_objects(Obj_Entry *first, in } static int -load_preload_objects(void) +load_preload_objects(char *preload) { - char *p = ld_preload; + char *p = preload; static const char delim[] = " \t:;"; + int i; + char *temp, *new, new_path[PATH_MAX]; if (p == NULL) return 0; @@ -1595,8 +1746,26 @@ load_preload_objects(void) savech = p[len]; p[len] = '\0'; - if (load_object(p, NULL, 0) == NULL) - return -1; /* XXX - cleanup */ + + new = p; + for (i = 0; os_version_try[i] != NULL; i++) { + if (os_version_try[i][0] == '\0') + new = p; + else { + bzero(new_path, sizeof(new_path)); + bcopy(p, new_path, strlen(p) + 1); + temp = rindex(new_path, '/'); + temp++; + *temp = '\0'; + strncat(new_path, os_version_try[i], sizeof(new_path)); + temp = rindex(p, '/'); + strncat(new_path, temp, sizeof(new_path)); + new = new_path; + if (access(new, F_OK) == 0) + break; + } + } + load_object(new, NULL, 0); p[len] = savech; p += len; p += strspn(p, delim); @@ -3188,19 +3357,30 @@ symlook_obj1(SymLook *req, const Obj_Ent static void trace_loaded_objects(Obj_Entry *obj) { - char *fmt1, *fmt2, *fmt, *main_local, *list_containers; + char *fmt1 = NULL, *fmt2 = NULL, *fmt; + char *main_local = NULL, *list_containers = NULL; int c; - if ((main_local = getenv(LD_ "TRACE_LOADED_OBJECTS_PROGNAME")) == NULL) +#ifdef COMPAT_32BIT + main_local = getenv(LD_32_ "TRACE_LOADED_OBJECTS_PROGNAME"); + fmt1 = getenv(LD_32_ "TRACE_LOADED_OBJECTS_FMT1"); + fmt2 = getenv(LD_32_ "TRACE_LOADED_OBJECTS_FMT2"); + list_containers = getenv(LD_32_ "TRACE_LOADED_OBJECTS_ALL"); +#endif + if (main_local == NULL + && (main_local = getenv(LD_ "TRACE_LOADED_OBJECTS_PROGNAME")) == NULL) main_local = ""; - if ((fmt1 = getenv(LD_ "TRACE_LOADED_OBJECTS_FMT1")) == NULL) + if (fmt1 == NULL + && (fmt1 = getenv(LD_ "TRACE_LOADED_OBJECTS_FMT1")) == NULL) fmt1 = "\t%o => %p (%x)\n"; - if ((fmt2 = getenv(LD_ "TRACE_LOADED_OBJECTS_FMT2")) == NULL) + if (fmt2 == NULL + && (fmt2 = getenv(LD_ "TRACE_LOADED_OBJECTS_FMT2")) == NULL) fmt2 = "\t%o (%x)\n"; - list_containers = getenv(LD_ "TRACE_LOADED_OBJECTS_ALL"); + if (list_containers == NULL) + list_containers = getenv(LD_ "TRACE_LOADED_OBJECTS_ALL"); for (; obj; obj = obj->next) { Needed_Entry *needed; @@ -3211,8 +3391,9 @@ trace_loaded_objects(Obj_Entry *obj) rtld_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: libexec/rtld-elf/rtld.h =================================================================== RCS file: /cvs/src/libexec/rtld-elf/rtld.h,v retrieving revision 1.51 diff -u -p -r1.51 rtld.h --- libexec/rtld-elf/rtld.h 24 Aug 2011 20:05:13 -0000 1.51 +++ libexec/rtld-elf/rtld.h 13 Mar 2012 16:42:12 -0000 @@ -47,7 +47,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 @@ -237,6 +237,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 Index: sbin/ldconfig/ldconfig.8 =================================================================== RCS file: /cvs/src/sbin/ldconfig/ldconfig.8,v retrieving revision 1.36 diff -u -p -r1.36 ldconfig.8 --- sbin/ldconfig/ldconfig.8 9 Dec 2005 03:12:25 -0000 1.36 +++ sbin/ldconfig/ldconfig.8 13 Mar 2012 16:42:12 -0000 @@ -37,6 +37,7 @@ .Nd configure the shared library cache .Sh SYNOPSIS .Nm +.Op Fl os Ns = Ns Ar version .Op Fl 32 .Op Fl aout | Fl elf .Op Fl Rimrsv @@ -104,6 +105,10 @@ utility is typically run as part of the The following options are recognized by .Nm : .Bl -tag -width indent +.It Cm os Ns = Ns Ar version +Generate a separate hints file for binaries created on the OS +.Ar version +to search for libaries for that OS version. .It Fl 32 Generate the hints for 32-bit ABI shared libraries on 64-bit systems that support running 32-bit binaries. @@ -196,6 +201,11 @@ invocations with Conventional configuration files containing directory names for invocations with .Fl 32 . +.It Pa /var/run/ld-elf-.so.hints +Conventional configuration files containing directory names for +invocations with +.Fl os +. .It Pa /etc/objformat Determines whether .Fl aout Index: sbin/ldconfig/ldconfig.c =================================================================== RCS file: /cvs/src/sbin/ldconfig/ldconfig.c,v retrieving revision 1.48 diff -u -p -r1.48 ldconfig.c --- sbin/ldconfig/ldconfig.c 29 Dec 2009 21:07:17 -0000 1.48 +++ sbin/ldconfig/ldconfig.c 13 Mar 2012 16:42:12 -0000 @@ -64,6 +64,13 @@ static const char rcsid[] = #define _PATH_LD32_HINTS "/var/run/ld32.so.hints" #define _PATH_ELF32_HINTS "/var/run/ld-elf32.so.hints" +/* + * Format string is used to specify an alternate hints file for + * application that are compiled on a different version of FreeBSD. + * This is needed to ensure there are no conflicts with libraries + * named the same in /usr/local/lib, system locations etc. + */ +#define _PATH_ELFOS_HINTS_FMT "/var/run/ld-elf-%u.so.hints" #undef major #undef minor @@ -104,6 +111,9 @@ main(int argc, char **argv) int rval = 0; int is_aout = 0; int is_32 = 0; + size_t len; + u_int32_t is_os = 0; + char *path = NULL; while (argc > 1) { if (strcmp(argv[1], "-aout") == 0) { @@ -118,12 +128,22 @@ main(int argc, char **argv) is_32 = 1; argc--; argv++; + } else if (strncmp(argv[1], "-os=", 4) == 0) { + is_os = (u_int32_t)strtoul(&argv[1][4], + (char **)NULL, 10); + argc--; + argv++; } else { break; } } - if (is_32) + if (!is_aout && is_os) { + len = sizeof(_PATH_ELFOS_HINTS_FMT) + 10; + path = (char *)malloc(len); + snprintf(path, len, _PATH_ELFOS_HINTS_FMT, is_os); + hints_file = path; + } else if (is_32) hints_file = is_aout ? _PATH_LD32_HINTS : _PATH_ELF32_HINTS; else hints_file = is_aout ? _PATH_LD_HINTS : _PATH_ELF_HINTS; @@ -225,7 +245,7 @@ static void usage(void) { fprintf(stderr, - "usage: ldconfig [-32] [-aout | -elf] [-Rimrsv] [-f hints_file] [directory | file ...]\n"); + "usage: ldconfig [-os=version] [-32] [-aout | -elf] [-Rimrsv] [-f hints_file] [directory | file ...]\n"); exit(1); }