Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-04-07 Thread Mathieu Malaterre
Package: src:cmake
Version: 3.0.2-1

Hi,

I've managed to find the cause of the openmpi segfault (#818909). It
might affect a number of different packages.

The segfault is caused by the interaction of the
new DT_MIPS_RLD_MAP_REL dynamic tag (from binutils 2.26) and chrpath.
Unlike all other tags, this tag is relative to the offset of the tag
within the executable. chrpath is used to remove rpaths from ELF files.
It does this by moving all of the other dynamic tags up one entry, but
since the DT_MIPS_RLD_MAP_REL is not updated, it now points to an
incorrect offset. The dynamic linker will then overwrite some other
memory when processing the DT_MIPS_RLD_MAP_REL tag.

The openmpi segfault was caused by a global variable being initialized
incorrectly (overwritten by the dynamic linker). I expect other
executables using chrpath will also be affected - possibly in strange
ways (not nessesarily a segfault).

It also seems that at least cmake uses the same technique for removing
the RPATH so any cmake reverse dependencies could be affected. The
DT_MIPS_RLD_MAP_REL is only created for executables which limits the
effect of this slightly. Only packages built using binutils
>= 2.25.51.20151014-1 will be affected.

There is a convinient way to test if a package is broken using the
presence of the old DT_MIPS_RLD_MAP tag. When correct
(DT_MIPS_RLD_MAP_REL + tag offset + executable base address) equals
DT_MIPS_RLD_MAP, so someone could analyze the archive to find which
packages are affected (any if any tools other than chrpath and cmake
are broken).

Based only on chrpath and cmake reverse dependencies, there is an upper
bound of about 1500 binNMUs (after the tools after fixed). Hopefully
that can be reduced!

I really don't have any time to fix all this. Please can someone else
have a look!

OpenMPI maintainers (and anyone else affected):
One possible workaround is to use chrpath -r ""  on mips*
architectures until this is fixed since that command does not cause any
tags to be moved. It has a tiny performance penalty but should
otherwise work properly.

James


signature.asc
Description: PGP signature


Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-04-09 Thread Mathieu Malaterre
Thanks to aurel32@d.o chrpath has been fixed. Could an equivalent
patch be included in cmake ?

On 2016-04-07 15:46, Mathieu Malaterre wrote:
> Package: src:chrpath
> Version: 0.16-1
>
> Hi,
>
> I've managed to find the cause of the openmpi segfault (#818909). It
> might affect a number of different packages.
>
> The segfault is caused by the interaction of the
> new DT_MIPS_RLD_MAP_REL dynamic tag (from binutils 2.26) and chrpath.
> Unlike all other tags, this tag is relative to the offset of the tag
> within the executable. chrpath is used to remove rpaths from ELF files.
> It does this by moving all of the other dynamic tags up one entry, but
> since the DT_MIPS_RLD_MAP_REL is not updated, it now points to an
> incorrect offset. The dynamic linker will then overwrite some other
> memory when processing the DT_MIPS_RLD_MAP_REL tag.

Please find below a patch to correctly handle this tag in chrpath. If
you are fine with the patch, a quick upload would be appreciated as
chrpath currently generates broken binaries. Thanks!

Aurelien


--- chrpath-0.16.orig/killrpath.c
+++ chrpath-0.16/killrpath.c
@@ -73,10 +73,26 @@
dynpos = 0;
for (i = 0; DYNSS(i, d_tag) != DT_NULL; i++)
  {
-   if (is_e32())
+   if (is_e32()) {
 ((Elf32_Dyn *)dyns)[dynpos] = ((Elf32_Dyn *)dyns)[i];
-   else
+#ifdef DT_MIPS_RLD_MAP_REL
+/* DT_MIPS_RLD_MAP_REL is relative to the offset of the tag.
+   Adjust it consequently.  */
+if (DYNSS(i, d_tag) == DT_MIPS_RLD_MAP_REL)
+ ((Elf32_Dyn *)dyns)[dynpos].d_un.d_val =
+  DO_SWAPU32(DYNSU(i, d_un.d_val) +
+  (i - dynpos) * sizeof(Elf32_Dyn));
+#endif
+   } else {
 ((Elf64_Dyn *)dyns)[dynpos] = ((Elf64_Dyn *)dyns)[i];
+#ifdef DT_MIPS_RLD_MAP_REL
+/* Ditto */
+if (DYNSS(i, d_tag) == DT_MIPS_RLD_MAP_REL)
+ ((Elf64_Dyn *)dyns)[dynpos].d_un.d_val =
+  DO_SWAPU64(DYNSU(i, d_un.d_val) +
+  (i - dynpos) * sizeof(Elf64_Dyn));
+#endif
+   }
if ( ! elf_dynpath_tag(DYNSS(i, d_tag)) )
 dynpos++;
  }

--
Aurelien Jarno  GPG: 4096R/1DDD8C9B
aurel...@aurel32.net http://www.aurel32.net



Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-04-09 Thread Aurelien Jarno
On 2016-04-09 13:22, Mathieu Malaterre wrote:
> Thanks to aurel32@d.o chrpath has been fixed. Could an equivalent
> patch be included in cmake ?

You mean that cmake is not calling chrpath, but instead has an embedded
copy? In that case I'll look at that later today.

-- 
Aurelien Jarno  GPG: 4096R/1DDD8C9B
aurel...@aurel32.net http://www.aurel32.net



Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-04-09 Thread Mathieu Malaterre
Salut Aurélien,

On Sat, Apr 9, 2016 at 2:14 PM, Aurelien Jarno  wrote:
> On 2016-04-09 13:22, Mathieu Malaterre wrote:
>> Thanks to aurel32@d.o chrpath has been fixed. Could an equivalent
>> patch be included in cmake ?
>
> You mean that cmake is not calling chrpath, but instead has an embedded
> copy? In that case I'll look at that later today.

That is how I understand the code in cmSystemTools::RemoveRPath (it
should hopefully be very close to chrpath implementation).

Brad, is this the only location that needs to be fixed ?

Thanks



Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-04-11 Thread Brad King
On 04/09/2016 11:01 AM, Mathieu Malaterre wrote:
> On Sat, Apr 9, 2016 at 2:14 PM, Aurelien Jarno wrote:
>> You mean that cmake is not calling chrpath, but instead has an embedded
>> copy? In that case I'll look at that later today.

Yes, CMake has a separate implementation.  It is not a copy of chrpath
but its own implementation, and was created because (at least at the time)
chrpath did not support changing cross-compiled binaries.

> That is how I understand the code in cmSystemTools::RemoveRPath (it
> should hopefully be very close to chrpath implementation).
> 
> Brad, is this the only location that needs to be fixed ?

Yes, IIRC.

-Brad



Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-10-06 Thread James Cowgill
Control: forwarded -1 https://gitlab.kitware.com/cmake/cmake/merge_requests/147
Control: tags -1 sid stretch

Hi,

I've submitted the above PR upstream which should fix this issue. The
patch was a bit bigger than what I would have liked due to the cmELF
class requiring some changes.

Tagging for stretch since jessie contains binutils 2.25 which is
unaffected.

Thanks,
James



signature.asc
Description: OpenPGP digital signature


Bug#820334: Segfaults caused by new DT_MIPS_RLD_MAP_REL tag and RPATH removers

2016-10-13 Thread James Cowgill
Control: tags -1 patch fixed-upstream

Hi,

On 06/10/16 09:42, James Cowgill wrote:
> Control: forwarded -1 
> https://gitlab.kitware.com/cmake/cmake/merge_requests/147
> Control: tags -1 sid stretch
> 
> Hi,
> 
> I've submitted the above PR upstream which should fix this issue. The
> patch was a bit bigger than what I would have liked due to the cmELF
> class requiring some changes.

The PR was accepted and I've attached a patch which backports it to 3.6.

Thanks,
James
From c51099bb1018191964e5ee05e17f133233160806 Mon Sep 17 00:00:00 2001
From: James Cowgill 
Date: Thu, 13 Oct 2016 11:00:00 +0100
Subject: [PATCH] MIPS: Handle DT_MIPS_RLD_MAP_REL tag when removing RPath from
 ELFs

This is a combination of 5 commits.

elf: remove tag switch from ELF_Dyn ByteSwap function
elf: add DynamicEntryList methods and rpath tag constants
cmSystemTools: rewrite RemoveRPath using DyanmicEntryList methods
cmSystemTools, elf: handle DT_MIPS_RLD_REL_MAP in RemoveRPath
elf: Remove GetDynamicEntryCount and ReadBytes methods

Backported from upstream 3.8.0 commit:
ea563a27a2042cfb3be33d0f74efecc7687b86bb
---
 Source/cmELF.cxx | 225 ---
 Source/cmELF.h   |  24 +++--
 Source/cmSystemTools.cxx |  72 ---
 3 files changed, 135 insertions(+), 186 deletions(-)

diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index 26f1a44..9fe8a43 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -134,18 +134,13 @@ public:
 
   // Forward to the per-class implementation.
   virtual unsigned int GetNumberOfSections() const = 0;
-  virtual unsigned int GetDynamicEntryCount() = 0;
   virtual unsigned long GetDynamicEntryPosition(int j) = 0;
+  virtual cmELF::DynamicEntryList GetDynamicEntries() = 0;
+  virtual std::vector EncodeDynamicEntries(
+const cmELF::DynamicEntryList&) = 0;
   virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0;
   virtual void PrintInfo(std::ostream& os) const = 0;
 
-  bool ReadBytes(unsigned long pos, unsigned long size, char* buf)
-  {
-this->Stream.seekg(pos);
-this->Stream.read(buf, size);
-return this->Stream ? true : false;
-  }
-
   // Lookup the SONAME in the DYNAMIC section.
   StringEntry const* GetSOName()
   {
@@ -246,10 +241,12 @@ public:
 return static_cast(this->ELFHeader.e_shnum);
   }
 
-  // Get the file position and size of a dynamic section entry.
-  virtual unsigned int GetDynamicEntryCount();
+  // Get the file position of a dynamic section entry.
   virtual unsigned long GetDynamicEntryPosition(int j);
 
+  virtual cmELF::DynamicEntryList GetDynamicEntries();
+  virtual std::vector EncodeDynamicEntries(const cmELF::DynamicEntryList&);
+
   // Lookup a string from the dynamic section with the given tag.
   virtual StringEntry const* GetDynamicSectionString(unsigned int tag);
 
@@ -289,6 +286,10 @@ public:
   }
 
 private:
+  // ByteSwap(ELF_Dyn) assumes d_val and d_ptr are the same size
+  typedef char dyn_size_assert
+[sizeof(ELF_Dyn().d_un.d_val) == sizeof(ELF_Dyn().d_un.d_ptr) ? 1 : -1];
+
   void ByteSwap(ELF_Ehdr& elf_header)
   {
 cmELFByteSwap(elf_header.e_type);
@@ -323,121 +324,7 @@ private:
   void ByteSwap(ELF_Dyn& dyn)
   {
 cmELFByteSwap(dyn.d_tag);
-switch (dyn.d_tag) {
-  case DT_NULL: /* dyn.d_un ignored */
-break;
-  case DT_NEEDED:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_PLTRELSZ:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_PLTGOT:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_HASH:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_STRTAB:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_SYMTAB:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_RELA:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_RELASZ:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_RELAENT:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_STRSZ:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_SYMENT:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_INIT:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_FINI:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_SONAME:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_RPATH:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_SYMBOLIC: /* dyn.d_un ignored */
-break;
-  case DT_REL:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_RELSZ:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_RELENT:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_PLTREL:
-cmELFByteSwap(dyn.d_un.d_val);
-break;
-  case DT_DEBUG:
-cmELFByteSwap(dyn.d_un.d_ptr);
-break;
-  case DT_TEXTREL: /*