summaryrefslogtreecommitdiffstats
path: root/trunk/src/gather.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/gather.c')
-rw-r--r--trunk/src/gather.c209
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;