diff options
Diffstat (limited to 'trunk/src/gather.c')
-rw-r--r-- | trunk/src/gather.c | 209 |
1 files changed, 141 insertions, 68 deletions
diff --git a/trunk/src/gather.c b/trunk/src/gather.c index 2752e4b..16ed21b 100644 --- a/trunk/src/gather.c +++ b/trunk/src/gather.c @@ -61,8 +61,8 @@ gather_deps (DSO *dso, struct prelink_entry *ent) { int i, j, seen = 0; FILE *f = NULL; - const char *argv[5]; - const char *envp[4]; + const char *argv[6]; + const char *envp[5]; char *line = NULL, *p, *q = NULL; const char **depends = NULL; size_t ndepends = 0, ndepends_alloced = 0; @@ -143,11 +143,6 @@ gather_deps (DSO *dso, struct prelink_entry *ent) i = 0; argv[i++] = dl; - if (ld_library_path) - { - argv[i++] = "--library-path"; - argv[i++] = ld_library_path; - } if (strchr (ent->filename, '/') != NULL) ent_filename = ent->filename; else @@ -158,13 +153,55 @@ gather_deps (DSO *dso, struct prelink_entry *ent) memcpy (tp + 2, ent->filename, flen + 1); ent_filename = tp; } - argv[i++] = ent_filename; - argv[i] = NULL; - envp[0] = "LD_TRACE_LOADED_OBJECTS=1"; - envp[1] = "LD_TRACE_PRELINKING=1"; - envp[2] = "LD_WARN="; - envp[3] = NULL; - f = execve_open (dl, (char * const *)argv, (char * const *)envp); + + if (prelink_rtld == NULL) + { + i = 0; + argv[i++] = dl; + if (ld_library_path) + { + argv[i++] = "--library-path"; + argv[i++] = ld_library_path; + } + argv[i++] = ent_filename; + argv[i] = NULL; + envp[0] = "LD_TRACE_LOADED_OBJECTS=1"; + envp[1] = "LD_TRACE_PRELINKING=1"; + envp[2] = "LD_WARN="; + envp[3] = NULL; + f = execve_open (dl, (char * const *)argv, (char * const *)envp); + } + else + { + char *path; + i = 0; + argv[i++] = prelink_rtld; + if (ld_library_path) + { + argv[i++] = "--library-path"; + argv[i++] = ld_library_path; + } + argv[i++] = "--target-paths"; + argv[i++] = ent_filename; + argv[i] = NULL; + envp[0] = "RTLD_TRACE_PRELINKING=1"; + envp[1] = "LD_WARN="; + path = alloca (sizeof "PATH=" + strlen (getenv ("PATH"))); + sprintf (path, "PATH=%s", getenv ("PATH")); + envp[2] = path; + + if (sysroot) + { + envp[3] = alloca (sizeof "PRELINK_SYSROOT=" + strlen (sysroot)); + sprintf ((char *) envp[3], "PRELINK_SYSROOT=%s", sysroot); + envp[4] = NULL; + } + else + envp[3] = NULL; + + f = execve_open (prelink_rtld, (char * const *)argv, (char * const *)envp); + } + if (f == NULL) goto error_out; @@ -183,8 +220,8 @@ gather_deps (DSO *dso, struct prelink_entry *ent) q = strstr (p, " ("); if (q == NULL && strcmp (p, " => not found") == 0) { - error (0, 0, "%s: Could not find one of the dependencies", - ent->filename); + error (0, 0, "%s: Could not find one of the dependencies: %s", + ent->filename, line); goto error_out; } } @@ -551,7 +588,9 @@ make_unprelinkable: } dl = dynamic_linker ?: dso->arch->dynamic_linker; - if (strcmp (dl, data->d_buf) != 0) + if (strcmp (dl, data->d_buf) != 0 + && (dynamic_linker != NULL || dso->arch->dynamic_linker_alt == NULL + || strcmp (dso->arch->dynamic_linker_alt, data->d_buf) != 0)) { error (0, 0, "%s: Using %s, not %s as dynamic linker", dso->filename, (char *) data->d_buf, dl); @@ -634,6 +673,77 @@ add_dir_to_dirlist (const char *name, dev_t dev, int flags) return 0; } +/* Determine if a buffer holding an ELF header and program header + table may be that of a position-independent executable. */ +static int +maybe_pie (unsigned char *e_ident, int big_endian, int sixty_four) +{ + uint16_t num_phdrs; + uint16_t phdr; + size_t p_type_offset; + size_t phnum_offset; + unsigned char *phdr_table; + unsigned char *this_phdr; + + if (sixty_four) + { + uint64_t phdr_offset; + + p_type_offset = offsetof (Elf64_Phdr, p_type); + phnum_offset = offsetof (Elf64_Ehdr, e_phnum); + if (big_endian) + phdr_offset = buf_read_ube64 (&e_ident [offsetof (Elf64_Ehdr, + e_phoff)]); + else + phdr_offset = buf_read_ule64 (&e_ident [offsetof (Elf64_Ehdr, + e_phoff)]); + phdr_table = e_ident + phdr_offset; + } + else + { + uint32_t phdr_offset; + + p_type_offset = offsetof (Elf32_Phdr, p_type); + phnum_offset = offsetof (Elf32_Ehdr, e_phnum); + if (big_endian) + phdr_offset = buf_read_ube32 (&e_ident [offsetof (Elf32_Ehdr, + e_phoff)]); + else + phdr_offset = buf_read_ule32 (&e_ident [offsetof (Elf32_Ehdr, + e_phoff)]); + phdr_table = e_ident + phdr_offset; + } + + this_phdr = phdr_table; + + if (big_endian) + num_phdrs = buf_read_ube16 (&e_ident [phnum_offset]); + else + num_phdrs = buf_read_ule16 (&e_ident [phnum_offset]); + + for (phdr = 0; phdr < num_phdrs; phdr++) + { + unsigned char *p_type_start = this_phdr + p_type_offset; + uint32_t p_type; + + if (big_endian) + p_type = buf_read_ube32 (p_type_start); + else + p_type = buf_read_ule32 (p_type_start); + + if (p_type == PT_PHDR) + return 1; + + /* Any PT_PHDR entry must come before any PT_LOAD entry. */ + if (p_type == PT_LOAD) + return 0; + + this_phdr += sixty_four ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); + } + + return 0; +} + static int gather_func (const char *name, const struct stat64 *st, int type, struct FTW *ftwp) @@ -693,13 +803,14 @@ gather_func (const char *name, const struct stat64 *st, int type, if (st->st_size < sizeof (e_ident)) return FTW_CONTINUE; - fd = open (name, O_RDONLY); + fd = wrap_open (name, O_RDONLY); if (fd == -1) return FTW_CONTINUE; if (read (fd, e_ident, sizeof (e_ident)) != sizeof (e_ident)) { close_it: + fsync (fd); close (fd); return FTW_CONTINUE; } @@ -718,6 +829,7 @@ make_unprelinkable: ent->type = ET_UNPRELINKABLE; } } + fsync (fd); close (fd); return FTW_CONTINUE; } @@ -733,17 +845,7 @@ make_unprelinkable: goto make_unprelinkable; else if (e_ident [EI_CLASS] == ELFCLASS32) { - if (e_ident [offsetof (Elf32_Ehdr, e_phoff)] - == sizeof (Elf32_Ehdr) - && memcmp (e_ident + offsetof (Elf32_Ehdr, e_phoff) + 1, - "\0\0\0", 3) == 0 - && (e_ident [offsetof (Elf32_Ehdr, e_phnum)] - || e_ident [offsetof (Elf32_Ehdr, e_phnum) + 1]) - && e_ident [sizeof (Elf32_Ehdr) - + offsetof (Elf32_Phdr, p_type)] == PT_PHDR - && memcmp (e_ident + sizeof (Elf32_Ehdr) - + offsetof (Elf32_Phdr, p_type) + 1, - "\0\0\0", 3) == 0) + if (maybe_pie (e_ident, 0, 0)) { maybe_pie: dso = fdopen_dso (fd, name); @@ -760,17 +862,7 @@ maybe_pie: } else if (e_ident [EI_CLASS] == ELFCLASS64) { - if (e_ident [offsetof (Elf64_Ehdr, e_phoff)] - == sizeof (Elf64_Ehdr) - && memcmp (e_ident + offsetof (Elf64_Ehdr, e_phoff) + 1, - "\0\0\0\0\0\0\0", 7) == 0 - && (e_ident [offsetof (Elf64_Ehdr, e_phnum)] - || e_ident [offsetof (Elf64_Ehdr, e_phnum) + 1]) - && e_ident [sizeof (Elf64_Ehdr) - + offsetof (Elf64_Phdr, p_type)] == PT_PHDR - && memcmp (e_ident + sizeof (Elf64_Ehdr) - + offsetof (Elf64_Phdr, p_type) + 1, - "\0\0\0", 3) == 0) + if (maybe_pie (e_ident, 0, 1)) goto maybe_pie; goto close_it; } @@ -787,35 +879,13 @@ maybe_pie: goto make_unprelinkable; else if (e_ident [EI_CLASS] == ELFCLASS32) { - if (e_ident [offsetof (Elf32_Ehdr, e_phoff) + 3] - == sizeof (Elf32_Ehdr) - && memcmp (e_ident + offsetof (Elf32_Ehdr, e_phoff), - "\0\0\0", 3) == 0 - && (e_ident [offsetof (Elf32_Ehdr, e_phnum)] - || e_ident [offsetof (Elf32_Ehdr, e_phnum) + 1]) - && e_ident [sizeof (Elf32_Ehdr) - + offsetof (Elf32_Phdr, p_type) + 3] - == PT_PHDR - && memcmp (e_ident + sizeof (Elf32_Ehdr) - + offsetof (Elf32_Phdr, p_type), - "\0\0\0", 3) == 0) + if (maybe_pie (e_ident, 1, 0)) goto maybe_pie; goto close_it; } else if (e_ident [EI_CLASS] == ELFCLASS64) { - if (e_ident [offsetof (Elf64_Ehdr, e_phoff) + 7] - == sizeof (Elf64_Ehdr) - && memcmp (e_ident + offsetof (Elf64_Ehdr, e_phoff), - "\0\0\0\0\0\0\0", 7) == 0 - && (e_ident [offsetof (Elf64_Ehdr, e_phnum)] - || e_ident [offsetof (Elf64_Ehdr, e_phnum) + 1]) - && e_ident [sizeof (Elf64_Ehdr) - + offsetof (Elf64_Phdr, p_type) + 3] - == PT_PHDR - && memcmp (e_ident + sizeof (Elf64_Ehdr) - + offsetof (Elf64_Phdr, p_type), - "\0\0\0", 3) == 0) + if (maybe_pie (e_ident, 1, 1)) goto maybe_pie; goto close_it; } @@ -891,7 +961,7 @@ gather_binlib (const char *name, const struct stat64 *st) return 0; } - fd = open (name, O_RDONLY); + fd = wrap_open (name, O_RDONLY); if (fd == -1) { error (0, errno, "Could not open %s", name); @@ -901,6 +971,7 @@ gather_binlib (const char *name, const struct stat64 *st) if (read (fd, e_ident, sizeof (e_ident)) != sizeof (e_ident)) { error (0, errno, "Could not read ELF header from %s", name); + fsync (fd); close (fd); return 1; } @@ -910,6 +981,7 @@ gather_binlib (const char *name, const struct stat64 *st) if (memcmp (e_ident, ELFMAG, SELFMAG) != 0) { error (0, 0, "%s is not an ELF object", name); + fsync (fd); close (fd); return 1; } @@ -934,6 +1006,7 @@ gather_binlib (const char *name, const struct stat64 *st) { unsupported_type: error (0, 0, "%s is neither ELF executable nor ELF shared library", name); + fsync (fd); close (fd); return 1; } @@ -979,7 +1052,7 @@ gather_object (const char *name, int deref, int onefs) { struct stat64 st; - if (stat64 (name, &st) < 0) + if (wrap_stat64 (name, &st) < 0) { if (implicit) return 0; @@ -1002,7 +1075,7 @@ gather_object (const char *name, int deref, int onefs) if (!all && implicit && ! deref) return 0; ++implicit; - ret = nftw64 (name, gather_func, 20, flags | FTW_ACTIONRETVAL); + ret = wrap_nftw64 (name, gather_func, 20, flags | FTW_ACTIONRETVAL); --implicit; if (ret < 0) error (0, errno, "Failed searching %s", name); @@ -1265,7 +1338,7 @@ add_to_blacklist (const char *name, int deref, int onefs) size_t len; struct stat64 st; - if (stat64 (name, &st) < 0) + if (wrap_stat64 (name, &st) < 0) { if (implicit) return 0; |