[yocto] [prelink-cross] [PATCH] x86_64: allow prelinking of PIE executables with COPY relocs

Mark Hatle mark.hatle at windriver.com
Fri Oct 12 14:05:57 PDT 2018


On 10/10/18 3:50 PM, Sergei Trofimovich wrote:
> COPY relocs are fine to have in PIE executables (as opposed to
> shared libraries).
> 
> By enabling prelink on PIEs we achieve a few goals:
> - prelink more PIE files on system: nicer for uniformity,
> - avoid spurious warnings about shared libraries with COPY relocs
> 
> It's usefult to prelink PIEs when kernel ASLR is disabled:
> kernel.randomize_va_space=0 + PIE-randomization patches.
> 
> I have gcc built as `--enable-default-pie` (generates PIE
> executables by default).
> 
> Testsute results before the change:
>   PASS:  14
>   FAIL:  31
> 
> After the change:
>   PASS:  32
>   FAIL:  13

After applying this patch, I think it uncovered another issue.

See:

http://git.yoctoproject.org/cgit/cgit.cgi/prelink-cross/log/?h=cross_prelink_staging

specifically:

http://git.yoctoproject.org/cgit/cgit.cgi/prelink-cross/commit/?h=cross_prelink_staging&id=b10e14218646d8b74773b82b0f8b395bce698fa2


Running the test suite, I was getting 4 failures that each manifested themselves as:

FAIL: layout1.sh  ../src/prelink: testsuite/layout1: section file offsets not
monotonically increasing
FAIL: cxx2.sh     ../src/prelink: testsuite/cxx2: section file offsets not
monotonically increasing
FAIL: cxx3.sh     ../src/prelink: testsuite/cxx3: section file offsets not
monotonically increasing
FAIL: quick1.sh   ../src/prelink: testsuite/quick1.tree/usr/bin/bin3: section
file offsets not monotonically increasing

Before this patch they would report:

   COPY relocations don't point into .bss or .sbss section

So I suspect that enabling the PIE executable prelinking has either triggered a
corner case or uncovered a bug in the existing function.

What I am seeing happen, if I dump the sections is:

   section 15 .fini file offset range 000012f4 and 000012fd
   section 16 .gnu.conflict file offset range 00001300 and 00002080
   section 17 .rodata file offset range 00002000 and 000020a3
   section 18 .eh_frame_hdr file offset range 000020a4 and 00002118

When the .gnu.conflict section is added and processed, it ends up inserting
immediately after .fini.   It then ends up taking more space then the gap allows
for (by 0x80 bytes in this case.)

I looked at the code for a couple of hours, and I'm not making any real progress
on it.

Do you have time to investigate this?

My little hack is enough to identify when this over write happens and abort..
but I suspect it's probably fixable instead.  (I don't intend to keep the hack
commit when transferring this over....)

--Mark

> Signed-off-by: Sergei Trofimovich <slyfox at gentoo.org>
> ---
>  src/arch-x86_64.c |  4 ++--
>  src/dso.c         | 19 +++++++++++++++++++
>  src/prelink.h     |  1 +
>  3 files changed, 22 insertions(+), 2 deletions(-)
> 
> 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/dso.c b/src/dso.c
> index a5fcec5..9fcfc3d 100644
> --- a/src/dso.c
> +++ b/src/dso.c
> @@ -1106,6 +1106,25 @@ dso_is_rdwr (DSO *dso)
>    return dso->elfro != NULL;
>  }
>  
> +/* 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_old_to_new (DSO *dso, GElf_Addr addr)
>  {
> diff --git a/src/prelink.h b/src/prelink.h
> index 93dbf7a..d8a00c6 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);
> 



More information about the yocto mailing list