diff options
-rw-r--r-- | ChangeLog | 38 | ||||
-rw-r--r-- | README | 9 | ||||
-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 | ||||
-rw-r--r-- | testsuite/Makefile.am | 2 | ||||
-rwxr-xr-x | testsuite/functions.sh | 6 | ||||
-rw-r--r-- | testsuite/reloc12.c | 19 | ||||
-rw-r--r-- | testsuite/reloc12.h | 11 | ||||
-rwxr-xr-x | testsuite/reloc12.sh | 22 | ||||
-rw-r--r-- | testsuite/reloc12lib1.c | 11 | ||||
-rw-r--r-- | testsuite/reloc12lib2.c | 16 | ||||
-rwxr-xr-x | testsuite/unprel1.sh | 2 |
19 files changed, 249 insertions, 27 deletions
@@ -1,3 +1,41 @@ +2019-06-24 Mark Hatle <mark.hatle@windriver.com> + * Merge with cross_prelink + +2018-10-12 Kyl Russel <bkylerussel@gmail.com + * doit.c, main.c prelink.h: Add -e option to return an error if + not everything can be prelinked. + +2018-10-12 Mark Hatle <mark.hatle@windriver.com> + * testsuite/order.sh: Explain failure in log + +2018-10-12 Mark Hatle <mark.hatle@windriver.com> + * testsuite/reloc12.sh: Detect if compiler/linker support test + +2018-10-12 Robert Yang <liezhi.yang@windriver.com> + * src/arch-mips.c: Make tls offset optional on tls usage + +2018-10-12 Sergei Trofimovich <slyfox@gentoo.org> + * src/arch-x86_64.c, src/dso.c, src/prelink.h: Allow prelink of + pie executables with COPY relocs + +2018-10-12 Sergei Trofimovich <slyfox@gentoo.org> + * tessuite/functions.sh: Avoid timestamp drift + +2018-10-12 Joseph Myers <joseph@codesourcery.com> + * testsuite/unprel1.sh: Fix for cross testing + +2018-10-12 Kyle Russell <bkylerussell@gmail.com> + * src/conflict.c, src/undo.c: Add knowledge of .data.rel.ro for + read-only dynamic symbols + +2018-10-12 Kyle Russell <bkylerussell@gmail.com> + * testsuite/Makefile.am, testsuite/reloc12.c, testsuite/reloc12.h, + testsuite/reloc12.sh, testsuite/reloc12lib1.c, testsuite/reloc12lib2.c: + Add a new test for these relocations + +2018-10-12 Mark Hatle <mark.hatle@windriver.com> + * Add 'Developer's Certificate of Origin' to patch requirements + 2018-08-29 Mark Hatle <mark.hatle@windriver.com> * Merge with cross_prelink @@ -19,6 +19,15 @@ Cc: yocto@yoctoproject.org Subject: [prelink-cross] .... +Additionally, a 'Developer's Certificate of Origin' statement will be required +for all submitted patches. See: + + https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin + +Effectively this means at then end of your commit, please add a +Signed-off-by: line. If you are not the original author of the patch, please +indicate this and then add your Signed-off-by: line after. + Known Issues ------------ 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) { diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 94ad5e9..867f650 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -5,7 +5,7 @@ AM_CFLAGS = -Wall TESTS = movelibs.sh \ reloc1.sh reloc2.sh reloc3.sh reloc4.sh reloc5.sh reloc6.sh \ - reloc7.sh reloc8.sh reloc9.sh reloc10.sh reloc11.sh \ + reloc7.sh reloc8.sh reloc9.sh reloc10.sh reloc11.sh reloc12.sh \ shuffle1.sh shuffle2.sh shuffle3.sh shuffle4.sh shuffle5.sh \ shuffle6.sh shuffle7.sh shuffle8.sh shuffle9.sh undo1.sh \ layout1.sh layout2.sh unprel1.sh \ diff --git a/testsuite/functions.sh b/testsuite/functions.sh index 85bf875..5e98725 100755 --- a/testsuite/functions.sh +++ b/testsuite/functions.sh @@ -4,6 +4,12 @@ CCLINK=${CCLINK:-${CC} -Wl,--dynamic-linker=`echo ./ld*.so.*[0-9]`} CXX="${CXX:-g++} ${LINKOPTS}" CXXLINK=${CXXLINK:-${CXX} -Wl,--dynamic-linker=`echo ./ld*.so.*[0-9]`} PRELINK=${PRELINK:-../src/prelink -c ./prelink.conf -C ./prelink.cache --ld-library-path=. --dynamic-linker=`echo ./ld*.so.*[0-9]`} + +# force deterministic timestamps to make double prelinking +# to produce unmodified binary. +PRELINK_TIMESTAMP=${PRELINK_TIMESTAMP:-12345678} +export PRELINK_TIMESTAMP + srcdir=${srcdir:-`dirname $0`} savelibs() { for i in $LIBS $BINS; do cp -p $i $i.orig; done diff --git a/testsuite/reloc12.c b/testsuite/reloc12.c new file mode 100644 index 0000000..cfa8888 --- /dev/null +++ b/testsuite/reloc12.c @@ -0,0 +1,19 @@ +#include "reloc12.h" +#include <stdlib.h> + +int main() +{ + A* ptr = find('b'); + if(b(ptr) != 0) + abort(); + + ptr = find('a'); + if(b(ptr) != 1) + abort(); + + ptr = find('r'); + if(b(ptr) != 2) + abort(); + + exit(0); +} diff --git a/testsuite/reloc12.h b/testsuite/reloc12.h new file mode 100644 index 0000000..8e09405 --- /dev/null +++ b/testsuite/reloc12.h @@ -0,0 +1,11 @@ +typedef struct + { + char a; + int b; + } A; + +extern A foo[] __attribute ((visibility ("protected"))); + +A* find(char a); +char a(const A*); +int b(const A*); diff --git a/testsuite/reloc12.sh b/testsuite/reloc12.sh new file mode 100755 index 0000000..74d1fa8 --- /dev/null +++ b/testsuite/reloc12.sh @@ -0,0 +1,22 @@ +#!/bin/bash +. `dirname $0`/functions.sh +rm -f reloc12 reloc12lib*.so reloc12.log +rm -f prelink.cache +$CC -shared -O2 -fpic -o reloc12lib1.so $srcdir/reloc12lib1.c +$CC -shared -O2 -fpic -o reloc12lib2.so $srcdir/reloc12lib2.c +if [ $? -ne 0 ]; then + echo "tested relocation not available in this GCC/Linker" + exit 77 +fi +BINS="reloc12" +LIBS="reloc12lib1.so reloc12lib2.so" +$CCLINK -o reloc12 $srcdir/reloc12.c -Wl,--rpath-link,. ${LIBS} +savelibs +echo $PRELINK ${PRELINK_OPTS--vm} ./reloc12 > reloc12.log +$PRELINK ${PRELINK_OPTS--vm} ./reloc12 >> reloc12.log 2>&1 || exit 1 +grep -q ^`echo $PRELINK | sed 's/ .*$/: /'` reloc12.log && exit 2 +LD_LIBRARY_PATH=. ./reloc12 || exit 3 +readelf -a ./reloc12 >> reloc12.log 2>&1 || exit 4 +# So that it is not prelinked again +chmod -x ./reloc12 +comparelibs >> reloc12.log 2>&1 || exit 5 diff --git a/testsuite/reloc12lib1.c b/testsuite/reloc12lib1.c new file mode 100644 index 0000000..db7e64f --- /dev/null +++ b/testsuite/reloc12lib1.c @@ -0,0 +1,11 @@ +#include "reloc12.h" + +char a(const A *d) +{ + return d ? d->a : 0; +} + +int b(const A *d) +{ + return d ? d->b : -1; +} diff --git a/testsuite/reloc12lib2.c b/testsuite/reloc12lib2.c new file mode 100644 index 0000000..ffa60a0 --- /dev/null +++ b/testsuite/reloc12lib2.c @@ -0,0 +1,16 @@ +#include "reloc12.h" + +A foo[] = { + { 'b', 0 }, + { 'a', 1 }, + { 'r', 2 } +}; + +A* find(char a) +{ + for(A* ptr = foo; ptr < foo + sizeof(foo)/sizeof(foo[0]); ptr++) + if(ptr->a == a) + return ptr; + + return 0; +} diff --git a/testsuite/unprel1.sh b/testsuite/unprel1.sh index 0463358..401f8bf 100755 --- a/testsuite/unprel1.sh +++ b/testsuite/unprel1.sh @@ -43,7 +43,7 @@ grep -q 'lib/lib2.so because its dependency unprel1.tree/opt/lib1.so could not b unprel1.log || exit 4 grep -q 'bin/bin1 because its dependency unprel1.tree/lib/lib2.so could not be prelinked' \ unprel1.log || exit 5 -unprel1.tree/bin/bin1 || exit 6 +$RUN unprel1.tree/bin/bin1 || exit 6 # So that it is not prelinked again chmod -x unprel1.tree/bin/bin1 LIBS=unprel1.tree/lib/lib1.so |