diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arch-mips.c | 3 | ||||
-rw-r--r-- | src/arch-x86_64.c | 4 | ||||
-rw-r--r-- | src/conflict.c | 51 | ||||
-rw-r--r-- | src/doit.c | 16 | ||||
-rw-r--r-- | src/dso.c | 37 | ||||
-rw-r--r-- | src/exec.c | 9 | ||||
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/prelink.h | 3 | ||||
-rw-r--r-- | src/undo.c | 9 |
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; @@ -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; } @@ -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) { @@ -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) @@ -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); @@ -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) { |