aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arch-mips.c3
-rw-r--r--src/arch-x86_64.c4
-rw-r--r--src/conflict.c51
-rw-r--r--src/doit.c16
-rw-r--r--src/dso.c37
-rw-r--r--src/exec.c9
-rw-r--r--src/main.c8
-rw-r--r--src/prelink.h3
-rw-r--r--src/undo.c9
9 files changed, 115 insertions, 25 deletions
diff --git a/src/arch-mips.c b/src/arch-mips.c
index ccb1834..02c608f 100644
--- a/src/arch-mips.c
+++ b/src/arch-mips.c
@@ -567,7 +567,8 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset,
if (dso->ehdr.e_type == ET_EXEC)
{
value = info->resolve (info, r_sym, r_type);
- value += info->resolvetls->offset - TLS_TP_OFFSET;
+ if (info->resolvetls != NULL)
+ value += info->resolvetls->offset - TLS_TP_OFFSET;
if (r_type == R_MIPS_TLS_TPREL32)
mips_prelink_32bit_reloc (dso, rela, value);
else
diff --git a/src/arch-x86_64.c b/src/arch-x86_64.c
index 5c95f47..2f6c551 100644
--- a/src/arch-x86_64.c
+++ b/src/arch-x86_64.c
@@ -179,7 +179,7 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
value + rela->r_addend - info->resolvetls->offset);
break;
case R_X86_64_COPY:
- if (dso->ehdr.e_type == ET_EXEC)
+ if (dso->ehdr.e_type == ET_EXEC || dso_is_pie(dso))
/* COPY relocs are handled specially in generic code. */
return 0;
error (0, 0, "%s: R_X86_64_COPY reloc in shared library?", dso->filename);
@@ -503,7 +503,7 @@ x86_64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
write_le32 (dso, rela->r_offset, 0);
break;
case R_X86_64_COPY:
- if (dso->ehdr.e_type == ET_EXEC)
+ if (dso->ehdr.e_type == ET_EXEC || dso_is_pie(dso))
/* COPY relocs are handled specially in generic code. */
return 0;
error (0, 0, "%s: R_X86_64_COPY reloc in shared library?", dso->filename);
diff --git a/src/conflict.c b/src/conflict.c
index 9ae2ddb..5613ace 100644
--- a/src/conflict.c
+++ b/src/conflict.c
@@ -450,7 +450,7 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
int
prelink_build_conflicts (struct prelink_info *info)
{
- int i, ndeps = info->ent->ndepends + 1;
+ int i, reset_dynbss = 0, reset_sdynbss = 0, ndeps = info->ent->ndepends + 1;
struct prelink_entry *ent;
int ret = 0;
DSO *dso;
@@ -675,6 +675,11 @@ prelink_build_conflicts (struct prelink_info *info)
dso->filename);
goto error_out;
}
+
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[bss1].sh_name);
+ if (strcmp(name, ".data.rel.ro") == 0)
+ reset_sdynbss = 1;
+
firstbss2 = i;
info->sdynbss_size = cr.rela[i - 1].r_offset - cr.rela[0].r_offset;
info->sdynbss_size += cr.rela[i - 1].r_addend;
@@ -702,6 +707,10 @@ prelink_build_conflicts (struct prelink_info *info)
}
}
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[bss2].sh_name);
+ if (strcmp(name, ".data.rel.ro") == 0)
+ reset_dynbss = 1;
+
info->dynbss_size = cr.rela[cr.count - 1].r_offset
- cr.rela[firstbss2].r_offset;
info->dynbss_size += cr.rela[cr.count - 1].r_addend;
@@ -719,9 +728,9 @@ prelink_build_conflicts (struct prelink_info *info)
&& strcmp (name = strptr (dso, dso->ehdr.e_shstrndx,
dso->shdr[bss1].sh_name),
".dynbss") != 0
- && strcmp (name, ".sdynbss") != 0)
+ && strcmp (name, ".sdynbss") != 0 && strcmp (name, ".data.rel.ro") != 0)
{
- error (0, 0, "%s: COPY relocations don't point into .bss or .sbss section",
+ error (0, 0, "%s: COPY relocations don't point into .bss, .sbss, or .data.rel.ro sections",
dso->filename);
goto error_out;
}
@@ -730,9 +739,9 @@ prelink_build_conflicts (struct prelink_info *info)
&& strcmp (name = strptr (dso, dso->ehdr.e_shstrndx,
dso->shdr[bss2].sh_name),
".dynbss") != 0
- && strcmp (name, ".sdynbss") != 0)
+ && strcmp (name, ".sdynbss") != 0 && strcmp (name, ".data.rel.ro") != 0)
{
- error (0, 0, "%s: COPY relocations don't point into .bss or .sbss section",
+ error (0, 0, "%s: COPY relocations don't point into .bss, .sbss, or .data.rel.ro section",
dso->filename);
goto error_out;
}
@@ -768,16 +777,21 @@ prelink_build_conflicts (struct prelink_info *info)
}
assert (j < ndeps);
+ GElf_Addr symaddr = s->u.ent->base + s->value;
+ char *buf;
+
if (i < firstbss2)
- j = get_relocated_mem (info, ndso, s->u.ent->base + s->value,
- info->sdynbss + cr.rela[i].r_offset
- - info->sdynbss_base, cr.rela[i].r_addend,
- cr.rela[i].r_offset);
+ if (reset_sdynbss)
+ buf = get_data(dso, cr.rela[i].r_offset, NULL, NULL);
+ else
+ buf = info->sdynbss + cr.rela[i].r_offset - info->sdynbss_base;
else
- j = get_relocated_mem (info, ndso, s->u.ent->base + s->value,
- info->dynbss + cr.rela[i].r_offset
- - info->dynbss_base, cr.rela[i].r_addend,
- cr.rela[i].r_offset);
+ if (reset_dynbss)
+ buf = get_data(dso, cr.rela[i].r_offset, NULL, NULL);
+ else
+ buf = info->dynbss + cr.rela[i].r_offset - info->dynbss_base;
+
+ j = get_relocated_mem (info, ndso, symaddr, buf, cr.rela[i].r_addend, cr.rela[i].r_offset);
switch (j)
{
@@ -815,6 +829,17 @@ prelink_build_conflicts (struct prelink_info *info)
if (info->dsos[i])
close_dso (info->dsos[i]);
+ if (reset_sdynbss)
+ {
+ free (info->sdynbss);
+ info->sdynbss = NULL;
+ }
+
+ if (reset_dynbss)
+ {
+ free (info->dynbss);
+ info->dynbss = NULL;
+ }
info->dsos = NULL;
free (cr.rela);
return ret;
diff --git a/src/doit.c b/src/doit.c
index 1e32ad5..3784866 100644
--- a/src/doit.c
+++ b/src/doit.c
@@ -237,11 +237,11 @@ error_out:
return;
}
-void
+int
prelink_all (void)
{
struct collect_ents l;
- int i;
+ int i, fails = 0;
l.ents =
(struct prelink_entry **) alloca (prelink_entry_count
@@ -250,7 +250,13 @@ prelink_all (void)
htab_traverse (prelink_filename_htab, find_ents, &l);
for (i = 0; i < l.nents; ++i)
- if (l.ents[i]->done == 1
- || (l.ents[i]->done == 0 && l.ents[i]->type == ET_EXEC))
- prelink_ent (l.ents[i]);
+ {
+ if (l.ents[i]->done == 1
+ || (l.ents[i]->done == 0 && l.ents[i]->type == ET_EXEC))
+ prelink_ent (l.ents[i]);
+ if (l.ents[i]->type == ET_UNPRELINKABLE)
+ fails++;
+ }
+
+ return fails;
}
diff --git a/src/dso.c b/src/dso.c
index a5fcec5..949abf9 100644
--- a/src/dso.c
+++ b/src/dso.c
@@ -221,8 +221,22 @@ check_dso (DSO *dso)
|| RELOCATE_SCN (dso->shdr[last].sh_flags)
|| RELOCATE_SCN (dso->shdr[i].sh_flags))
{
- error (0, 0, "%s: section file offsets not monotonically increasing",
- dso->filename);
+ int j = 0;
+ for (j = 1; j < dso->ehdr.e_shnum; ++j) {
+ const char *name
+ = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[j].sh_name);
+
+ error(0, 0, "section %d %s file offset range %08lx and %08lx",
+ j, name,
+ dso->shdr[j].sh_offset,
+ dso->shdr[j].sh_offset + (dso->shdr[j].sh_type == SHT_NOBITS ? 0 : dso->shdr[j].sh_size));
+ }
+
+ error (0, 0, "%s: section [%d and %d] file offsets [%08lx and %08lx] not monotonically increasing",
+ dso->filename, last, i,
+ dso->shdr[last].sh_offset + (dso->shdr[last].sh_type == SHT_NOBITS ? 0 : dso->shdr[last].sh_size),
+ dso->shdr[i].sh_offset
+ );
return 1;
}
}
@@ -1126,6 +1140,25 @@ adjust_old_to_new (DSO *dso, GElf_Addr addr)
return addr;
}
+/* Return true is DSO is position independent executable.
+
+ There is no simple way to distinct between shared library
+ and PIE executable. Use presence of interpreter as a heuristic. */
+
+int dso_is_pie(DSO *dso)
+{
+ int i;
+
+ if (dso->ehdr.e_type != ET_DYN)
+ return 0;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ return 1;
+
+ return 0;
+}
+
GElf_Addr
adjust_new_to_old (DSO *dso, GElf_Addr addr)
{
diff --git a/src/exec.c b/src/exec.c
index 4f56629..ca7fd14 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1122,6 +1122,15 @@ error_out:
goto error_out;
if (set_dynamic (dso, DT_GNU_CONFLICTSZ, dso->shdr[i].sh_size, 1))
goto error_out;
+ /* Check if we're going to run over the next section */
+ if (dso->shdr[i].sh_offset
+ + (dso->shdr[i].sh_type == SHT_NOBITS
+ ? 0 : dso->shdr[i].sh_size) > dso->shdr[i+1].sh_offset)
+ {
+ error (0, ENOMEM, "%s: Could not create .gnu.conflict section [overwrites next section]",
+ dso->filename);
+ goto error_out;
+ }
}
if (undo != -1)
diff --git a/src/main.c b/src/main.c
index 0cea86d..6ba89d5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -47,6 +47,7 @@ int one_file_system;
int enable_cxx_optimizations = 1;
int exec_shield;
int undo, verify;
+int errors;
enum verify_method_t verify_method;
int quick;
int compute_checksum;
@@ -90,6 +91,7 @@ static struct argp_option options[] = {
{"black-list", 'b', "PATH", 0, "Blacklist path" },
{"cache-file", 'C', "CACHE", 0, "Use CACHE as cache file" },
{"config-file", 'c', "CONF", 0, "Use CONF as configuration file" },
+ {"errors", 'e', 0, 0, "Returns an error if all binaries are not prelinkable" },
{"force", 'f', 0, 0, "Force prelinking" },
{"dereference", 'h', 0, 0, "Follow symlinks when processing directory trees from command line" },
{"one-file-system", 'l', 0, 0, "Stay in local file system when processing directories from command line" },
@@ -139,6 +141,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
if (add_to_blacklist (arg, dereference, one_file_system))
exit (EXIT_FAILURE);
break;
+ case 'e':
+ errors = 1;
+ break;
case 'f':
force = 1;
break;
@@ -524,7 +529,8 @@ main (int argc, char *argv[])
prelink_load_cache ();
layout_libs ();
- prelink_all ();
+ if(prelink_all () && errors)
+ return EXIT_FAILURE;
if (! no_update && ! dry_run)
prelink_save_cache (all);
diff --git a/src/prelink.h b/src/prelink.h
index 93dbf7a..39c4390 100644
--- a/src/prelink.h
+++ b/src/prelink.h
@@ -298,6 +298,7 @@ int reopen_dso (DSO *dso, struct section_move *move, const char *);
int adjust_symbol_p (DSO *dso, GElf_Sym *sym);
int check_dso (DSO *dso);
int dso_is_rdwr (DSO *dso);
+int dso_is_pie(DSO *dso);
void read_dynamic (DSO *dso);
int set_dynamic (DSO *dso, GElf_Word tag, GElf_Addr value, int fatal);
int addr_to_sec (DSO *dso, GElf_Addr addr);
@@ -574,7 +575,7 @@ int get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
int layout_libs (void);
-void prelink_all (void);
+int prelink_all (void);
int undo_all (void);
diff --git a/src/undo.c b/src/undo.c
index 8a55bf2..4c38dab 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -633,6 +633,15 @@ prelink_undo (DSO *dso)
d->d_buf = NULL;
dso->shdr[i].sh_type = SHT_NOBITS;
}
+ else if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (name, ".data.rel.ro") == 0)
+ {
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (d != NULL && elf_getdata (scn, d) == NULL);
+ assert (d->d_size == dso->shdr[i].sh_size);
+ assert (memset(d->d_buf, 0, d->d_size) == d->d_buf);
+ }
else if (dso->shdr[i].sh_type == SHT_RELA
&& shdr[i].sh_type == SHT_REL)
{