this adds a -p option to ldconfig so you can do something like:
ldconfig -p /usr/local/lib/libsafe.so to set a preload, and: ldconfig -pm /usr/local/lib/libsafe.so to merge one. the major problem i know of with this patch is that setting a preload ELF library will hose your ability to run linux binaries. also, you probably need to: cp /usr/src/include/elf-hints.h /usr/include/elf-hints.h initially in order to build (is this indicative of larger build issues involved with installed include files being selected before the one in the source tree?)
--- include/elf-hints.h~ Fri Nov 30 23:10:12 2001 +++ include/elf-hints.h Fri Nov 30 23:11:15 2001 @@ -40,7 +40,10 @@ u_int32_t dirlist; /* Offset of directory list in string table */ u_int32_t dirlistlen; /* strlen(dirlist) */ - u_int32_t spare[26]; /* Room for expansion */ + u_int32_t preloadlist; /* Offset of preload list in + string table */ + u_int32_t preloadlistlen; /* strlen(preloadlist) */ + u_int32_t spare[24]; /* Room for expansion */ }; #define ELFHINTS_MAGIC 0x746e6845 --- libexec/rtld-elf/rtld.c~ Fri Nov 30 23:10:54 2001 +++ libexec/rtld-elf/rtld.c Fri Nov 30 23:11:02 2001 @@ -52,8 +52,10 @@ #include "debug.h" #include "rtld.h" -#define END_SYM "_end" -#define PATH_RTLD "/usr/libexec/ld-elf.so.1" +#define END_SYM "_end" +#define PATH_RTLD "/usr/libexec/ld-elf.so.1" +#define HINT_LIBRARY_PATH 0x01 +#define HINT_PRELOAD 0x02 /* Types. */ typedef void (*func_ptr_type)(); @@ -80,7 +82,7 @@ static void errmsg_restore(char *); static char *errmsg_save(void); static char *find_library(const char *, const Obj_Entry *); -static const char *gethints(void); +static char *gethints(int); static void init_dag(Obj_Entry *); static void init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *); static void init_rtld(caddr_t); @@ -91,7 +93,7 @@ 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(char *); static void lock_check(void); static Obj_Entry *obj_from_addr(const void *); @@ -359,7 +361,9 @@ sym_zero.st_shndx = SHN_ABS; dbg("loading LD_PRELOAD libraries"); - if (load_preload_objects() == -1) + if (load_preload_objects(ld_preload) == -1) + die(); + if (load_preload_objects(gethints(HINT_PRELOAD)) == -1) die(); preload_tail = obj_tail; @@ -805,7 +809,7 @@ if ((refobj != NULL && (pathname = search_library_path(name, refobj->rpath)) != NULL) || (pathname = search_library_path(name, ld_library_path)) != NULL || - (pathname = search_library_path(name, gethints())) != NULL || + (pathname = search_library_path(name, gethints(HINT_LIBRARY_PATH))) != NULL || (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL) return pathname; @@ -873,38 +877,54 @@ * necessary. Returns NULL if there are problems with the hints file, * or if the search path there is empty. */ -static const char * -gethints(void) +static char * +gethints(int hintflag) { - static char *hints; + static char *preload; + static char *library_path; - if (hints == NULL) { + if ((library_path == NULL) || (preload == NULL)) { int fd; struct elfhints_hdr hdr; char *p; /* Keep from trying again in case the hints file is bad. */ - hints = ""; + library_path = ""; + preload = ""; if ((fd = open(_PATH_ELF_HINTS, O_RDONLY)) == -1) return NULL; if (read(fd, &hdr, sizeof hdr) != sizeof hdr || hdr.magic != ELFHINTS_MAGIC || hdr.version != 1) { - close(fd); - return NULL; + goto cleanup; } p = xmalloc(hdr.dirlistlen + 1); if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 || read(fd, p, hdr.dirlistlen + 1) != hdr.dirlistlen + 1) { free(p); - close(fd); - return NULL; + goto cleanup; } - hints = p; + library_path = p; + p = xmalloc(hdr.preloadlistlen + 1); + if (hdr.preloadlistlen == 0 || + lseek(fd, hdr.strtab + hdr.preloadlist, SEEK_SET) == -1 || + read(fd, p, hdr.preloadlistlen + 1) != hdr.preloadlistlen + 1) { + free(p); + goto cleanup; + } + preload = p; +cleanup: close(fd); } - return hints[0] != '\0' ? hints : NULL; + switch (hintflag) { + case HINT_LIBRARY_PATH: + return library_path[0] != '\0' ? library_path : NULL; + case HINT_PRELOAD: + return preload[0] != '\0' ? preload : NULL; + default: + return NULL; + } } static void @@ -1077,9 +1097,8 @@ } static int -load_preload_objects(void) +load_preload_objects(char *p) { - char *p = ld_preload; static const char delim[] = " \t:;"; if (p == NULL) --- sbin/ldconfig/ldconfig.c~ Fri Nov 30 23:10:29 2001 +++ sbin/ldconfig/ldconfig.c Fri Nov 30 23:11:33 2001 @@ -71,6 +71,7 @@ static int justread; static int merge; static int rescan; +static int preload; static char *hints_file; struct shlib_list { @@ -117,7 +118,7 @@ hints_file = is_aout ? _PATH_LD_HINTS : _PATH_ELF_HINTS; if (argc == 1) rescan = 1; - else while((c = getopt(argc, argv, "Rf:imrsv")) != -1) { + else while((c = getopt(argc, argv, "Rf:imrsvp")) != -1) { switch (c) { case 'R': rescan = 1; @@ -140,6 +141,9 @@ case 'v': verbose = 1; break; + case 'p': + preload = 1; + break; default: usage(); break; @@ -150,8 +154,12 @@ if (justread) list_elf_hints(hints_file); else - update_elf_hints(hints_file, argc - optind, - argv + optind, merge || rescan); + if (preload) + update_elf_preloads(hints_file, argc - optind, + argv + optind, merge || rescan); + else + update_elf_dirs(hints_file, argc - optind, + argv + optind, merge || rescan); return 0; } --- sbin/ldconfig/ldconfig.h~ Fri Nov 30 23:10:25 2001 +++ sbin/ldconfig/ldconfig.h Fri Nov 30 23:11:33 2001 @@ -35,7 +35,8 @@ __BEGIN_DECLS void list_elf_hints __P((const char *)); -void update_elf_hints __P((const char *, int, char **, int)); +void update_elf_dirs __P((const char *, int, char **, int)); +void update_elf_preloads __P((const char *, int, char **, int)); __END_DECLS #endif --- sbin/ldconfig/elfhints.c~ Fri Nov 30 23:10:36 2001 +++ sbin/ldconfig/elfhints.c Fri Nov 30 23:54:52 2001 @@ -44,18 +44,56 @@ #include "ldconfig.h" #define MAXDIRS 1024 /* Maximum directories in path */ +#define MAXPRELOADS 1024 /* Maximum preloaded libraries */ #define MAXFILESIZE (16*1024) /* Maximum hints file size */ static void add_dir(const char *, const char *, int); +static void add_preload(const char *, const char *, int); static void read_dirs_from_file(const char *, const char *); static void read_elf_hints(const char *, int); static void write_elf_hints(const char *); static const char *dirs[MAXDIRS]; +static const char *preloads[MAXPRELOADS]; static int ndirs; +static int npreloads; int insecure; static void +add_preload(const char *hintsfile, const char *name, int trusted) +{ + struct stat stbuf; + int i; + + if (!trusted && !insecure) { + if (stat(name, &stbuf) == -1) { + warn("%s", name); + return; + } + if (stbuf.st_uid != 0) { + warnx("%s: ignoring library not owned by root", name); + return; + } + if ((stbuf.st_mode & S_IWOTH) != 0) { + warnx("%s: ignoring world-writable library", name); + return; + } + if ((stbuf.st_mode & S_IWGRP) != 0) { + warnx("%s: ignoring group-writable directory", name); + return; + } + } + + for (i = 0; i < npreloads; i++) + if (strcmp(preloads[i], name) == 0) + return; + if (npreloads >= MAXPRELOADS) + errx(1, "\"%s\": Too many preloaded libraries", hintsfile); + preloads[npreloads++] = name; +} + + +static void add_dir(const char *hintsfile, const char *name, int trusted) { struct stat stbuf; @@ -97,6 +135,10 @@ read_elf_hints(hintsfile, 1); printf("%s:\n", hintsfile); + printf("\tpreloaded libraries:"); + for (i = 0; i < npreloads; i++) + printf("%c%s", i == 0 ? ' ' : ':', preloads[i]); + printf("\n"); printf("\tsearch directories:"); for (i = 0; i < ndirs; i++) printf("%c%s", i == 0 ? ' ' : ':', dirs[i]); @@ -192,6 +234,7 @@ struct elfhints_hdr *hdr; char *strtab; char *dirlist; + char *preloadlist; char *p; if ((fd = open(hintsfile, O_RDONLY)) == -1) { @@ -222,19 +265,47 @@ strtab = (char *)mapbase + hdr->strtab; dirlist = strtab + hdr->dirlist; + preloadlist = strtab + hdr->preloadlist; if (*dirlist != '\0') while ((p = strsep(&dirlist, ":")) != NULL) add_dir(hintsfile, p, 1); +printf("%d dirs loaded\n", ndirs); + if (*preloadlist != '\0' && hdr->preloadlistlen != 0) + while ((p = strsep(&preloadlist, ":")) != NULL) + add_preload(hintsfile, p, 1); +printf("%d preloads loaded\n", npreloads); } void -update_elf_hints(const char *hintsfile, int argc, char **argv, int merge) +update_elf_preloads(const char *hintsfile, int argc, char **argv, int merge) { int i; - if (merge) - read_elf_hints(hintsfile, 0); + read_elf_hints(hintsfile, 0); + if (!merge) + npreloads = 0; + for (i = 0; i < argc; i++) { + struct stat s; + + if (stat(argv[i], &s) == -1) + warn("warning: %s", argv[i]); + else if (!S_ISREG(s.st_mode)) + warn("not a regular file: %s", argv[i]); + else + add_preload(hintsfile, argv[i], 0); + } + write_elf_hints(hintsfile); +} + +void +update_elf_dirs(const char *hintsfile, int argc, char **argv, int merge) +{ + int i; +printf("update_elf_dirs\n"); + read_elf_hints(hintsfile, 0); + if (!merge) + ndirs = 0; for (i = 0; i < argc; i++) { struct stat s; @@ -271,6 +342,8 @@ hdr.strtab = sizeof hdr; hdr.strsize = 0; hdr.dirlist = 0; + hdr.preloadlistlen = 0; + memset(hdr.spare, 0, sizeof hdr.spare); /* Count up the size of the string table. */ @@ -281,6 +354,16 @@ } hdr.dirlistlen = hdr.strsize; hdr.strsize++; /* For the null terminator */ + hdr.preloadlist = hdr.strsize; + + if (npreloads > 0) { + hdr.preloadlistlen += strlen(preloads[0]); + for (i = 1; i < npreloads; i++) + hdr.preloadlistlen += 1 + strlen(preloads[i]); + } + + hdr.strsize += hdr.preloadlistlen; + hdr.strsize++; /* For the null terminator */ /* Write the header. */ if (fwrite(&hdr, 1, sizeof hdr, fp) != sizeof hdr) @@ -293,6 +376,17 @@ if (fprintf(fp, ":%s", dirs[i]) < 0) err(1, "%s: write error", tempname); } + if (putc('\0', fp) == EOF) + err(1, "%s: write error", tempname); + + if (npreloads > 0) { + if (fputs(preloads[0], fp) == EOF) + err(1, "%s: write error", tempname); + for (i = 1; i < npreloads; i++) + if (fprintf(fp, ":%s", preloads[i]) < 0) + err(1, "%s: write error", tempname); + } + if (putc('\0', fp) == EOF || fclose(fp) == EOF) err(1, "%s: write error", tempname); --- sbin/ldconfig/ldconfig.8~ Sat Dec 1 00:05:20 2001 +++ sbin/ldconfig/ldconfig.8 Sat Dec 1 00:04:13 2001 @@ -38,7 +38,7 @@ .Sh SYNOPSIS .Nm .Op Fl aout | Fl elf -.Op Fl Rimrsv +.Op Fl Rimrsvp .Op Fl f Ar hints_file .Op Ar directory | Ar .Sh DESCRIPTION @@ -128,6 +128,8 @@ for shared libraries. .It Fl v Switch on verbose mode. +.It Fl p +The arguments are taken to be libraries to globally preload. .El .Sh Security Special care must be taken when loading shared libraries into the address