public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] libdwfl: Fix relocation overlap sanity check.
@ 2018-11-23 20:20 Mark Wielaard
  2018-11-26 10:37 ` Mark Wielaard
  0 siblings, 1 reply; 2+ messages in thread
From: Mark Wielaard @ 2018-11-23 20:20 UTC (permalink / raw)
  To: elfutils-devel; +Cc: Mark Wielaard

We would not relocate when the relocation section data or the target
section date would overlap with one of the ELF headers. This is only
really necessary if the data comes directly from the mmapped file.
Otherwise there is no real overlap and the relocations can be safely
applied.

One particular thing we got wrong with the original sanity check was
when the relocation data or target data section was compressed. In
that case it could happen we overestimated the size (because the Shdr
would have been updated to show the uncompressed data size). But
uncompressed data is always malloced and so cannot overlap with the
mmapped Elf header structures.

When building with CFLAGS="-g -Og" this showed up as a failure in
run-strip-reloc.sh for strip-compressed.o. Where the .debug_loc
section decompressed would "overlap" with the shdrs at the end of
the file and so wouldn't get relocations applied.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---

The diff might look big, but without the whitespace changes it is just:

@@ -561,7 +562,13 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
      shdrs or phdrs data then we refuse to do the relocations.  It
      isn't illegal for ELF section data to overlap the header data,
      but updating the (relocation) data might corrupt the in-memory
-     libelf headers causing strange corruptions or errors.  */
+     libelf headers causing strange corruptions or errors.
+
+     This is only an issue if the ELF is mmapped and the section data
+     comes from the mmapped region (is not malloced or decompressed).
+  */
+  if (relocated->map_address != NULL)
+    {
       size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
       if (unlikely (shdr->sh_offset < ehsize
 		    || tshdr->sh_offset < ehsize))
@@ -574,10 +581,14 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
       /* Overflows will have been checked by elf_getshdrnum/get|rawdata.  */
       size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
       GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
-  if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size
-		 && shdr->sh_offset < shdrs_end)
-		|| (shdrs_start < tshdr->sh_offset + tshdr->sh_size
-		    && tshdr->sh_offset < shdrs_end)))
+      if (unlikely (shdrs_start < shdr->sh_offset + shdr->sh_size
+		    && shdr->sh_offset < shdrs_end))
+	if ((scn->flags & ELF_F_MALLOCED) == 0)
+	  return DWFL_E_BADELF;
+
+      if (unlikely (shdrs_start < tshdr->sh_offset + tshdr->sh_size
+		    && tshdr->sh_offset < shdrs_end))
+	if ((tscn->flags & ELF_F_MALLOCED) == 0)
 	  return DWFL_E_BADELF;
 
       GElf_Off phdrs_start = ehdr->e_phoff;
@@ -589,11 +600,16 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
 	  /* Overflows will have been checked by elf_getphdrnum/get|rawdata.  */
 	  size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
 	  GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
-      if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size
-		     && shdr->sh_offset < phdrs_end)
-		    || (phdrs_start < tshdr->sh_offset + tshdr->sh_size
-			&& tshdr->sh_offset < phdrs_end)))
+	  if (unlikely (phdrs_start < shdr->sh_offset + shdr->sh_size
+			&& shdr->sh_offset < phdrs_end))
+	    if ((scn->flags & ELF_F_MALLOCED) == 0)
 	      return DWFL_E_BADELF;
+
+	  if (unlikely (phdrs_start < tshdr->sh_offset + tshdr->sh_size
+			&& tshdr->sh_offset < phdrs_end))
+	    if ((tscn->flags & ELF_F_MALLOCED) == 0)
+	      return DWFL_E_BADELF;
+	}
     }
 
   /* Fetch the relocation section and apply each reloc in it.  */
---

 libdwfl/ChangeLog  |  5 ++++
 libdwfl/relocate.c | 80 ++++++++++++++++++++++++++++++++----------------------
 2 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 45cc1b4..b96cebf 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2018-10-23  Mark Wielaard  <mark@klomp.org>
+
+	* relocate.c (relocate_section): Only sanity check mmapped Elf files
+	for overlap. Don't error when section data was malloced, not mmapped.
+
 2018-10-20  Mark Wielaard  <mark@klomp.org>
 
 	* libdwflP.h (__libdw_open_elf): New internal function declaration.
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 58c5678..88b5211 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -1,5 +1,5 @@
 /* Relocate debug information.
-   Copyright (C) 2005-2011, 2014, 2016 Red Hat, Inc.
+   Copyright (C) 2005-2011, 2014, 2016, 2018 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -30,6 +30,7 @@
 # include <config.h>
 #endif
 
+#include "libelfP.h"
 #include "libdwflP.h"
 
 typedef uint8_t GElf_Byte;
@@ -561,39 +562,54 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
      shdrs or phdrs data then we refuse to do the relocations.  It
      isn't illegal for ELF section data to overlap the header data,
      but updating the (relocation) data might corrupt the in-memory
-     libelf headers causing strange corruptions or errors.  */
-  size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
-  if (unlikely (shdr->sh_offset < ehsize
-		|| tshdr->sh_offset < ehsize))
-    return DWFL_E_BADELF;
-
-  GElf_Off shdrs_start = ehdr->e_shoff;
-  size_t shnums;
-  if (elf_getshdrnum (relocated, &shnums) < 0)
-    return DWFL_E_LIBELF;
-  /* Overflows will have been checked by elf_getshdrnum/get|rawdata.  */
-  size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
-  GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
-  if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size
-		 && shdr->sh_offset < shdrs_end)
-		|| (shdrs_start < tshdr->sh_offset + tshdr->sh_size
-		    && tshdr->sh_offset < shdrs_end)))
-    return DWFL_E_BADELF;
-
-  GElf_Off phdrs_start = ehdr->e_phoff;
-  size_t phnums;
-  if (elf_getphdrnum (relocated, &phnums) < 0)
-    return DWFL_E_LIBELF;
-  if (phdrs_start != 0 && phnums != 0)
+     libelf headers causing strange corruptions or errors.
+
+     This is only an issue if the ELF is mmapped and the section data
+     comes from the mmapped region (is not malloced or decompressed).
+  */
+  if (relocated->map_address != NULL)
     {
-      /* Overflows will have been checked by elf_getphdrnum/get|rawdata.  */
-      size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
-      GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
-      if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size
-		     && shdr->sh_offset < phdrs_end)
-		    || (phdrs_start < tshdr->sh_offset + tshdr->sh_size
-			&& tshdr->sh_offset < phdrs_end)))
+      size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
+      if (unlikely (shdr->sh_offset < ehsize
+		    || tshdr->sh_offset < ehsize))
 	return DWFL_E_BADELF;
+
+      GElf_Off shdrs_start = ehdr->e_shoff;
+      size_t shnums;
+      if (elf_getshdrnum (relocated, &shnums) < 0)
+	return DWFL_E_LIBELF;
+      /* Overflows will have been checked by elf_getshdrnum/get|rawdata.  */
+      size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
+      GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
+      if (unlikely (shdrs_start < shdr->sh_offset + shdr->sh_size
+		    && shdr->sh_offset < shdrs_end))
+	if ((scn->flags & ELF_F_MALLOCED) == 0)
+	  return DWFL_E_BADELF;
+
+      if (unlikely (shdrs_start < tshdr->sh_offset + tshdr->sh_size
+		    && tshdr->sh_offset < shdrs_end))
+	if ((tscn->flags & ELF_F_MALLOCED) == 0)
+	  return DWFL_E_BADELF;
+
+      GElf_Off phdrs_start = ehdr->e_phoff;
+      size_t phnums;
+      if (elf_getphdrnum (relocated, &phnums) < 0)
+	return DWFL_E_LIBELF;
+      if (phdrs_start != 0 && phnums != 0)
+	{
+	  /* Overflows will have been checked by elf_getphdrnum/get|rawdata.  */
+	  size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
+	  GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
+	  if (unlikely (phdrs_start < shdr->sh_offset + shdr->sh_size
+			&& shdr->sh_offset < phdrs_end))
+	    if ((scn->flags & ELF_F_MALLOCED) == 0)
+	      return DWFL_E_BADELF;
+
+	  if (unlikely (phdrs_start < tshdr->sh_offset + tshdr->sh_size
+			&& tshdr->sh_offset < phdrs_end))
+	    if ((tscn->flags & ELF_F_MALLOCED) == 0)
+	      return DWFL_E_BADELF;
+	}
     }
 
   /* Fetch the relocation section and apply each reloc in it.  */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] libdwfl: Fix relocation overlap sanity check.
  2018-11-23 20:20 [PATCH] libdwfl: Fix relocation overlap sanity check Mark Wielaard
@ 2018-11-26 10:37 ` Mark Wielaard
  0 siblings, 0 replies; 2+ messages in thread
From: Mark Wielaard @ 2018-11-26 10:37 UTC (permalink / raw)
  To: elfutils-devel

On Fri, 2018-11-23 at 21:20 +0100, Mark Wielaard wrote:
> We would not relocate when the relocation section data or the target
> section date would overlap with one of the ELF headers. This is only
> really necessary if the data comes directly from the mmapped file.
> Otherwise there is no real overlap and the relocations can be safely
> applied.
> 
> One particular thing we got wrong with the original sanity check was
> when the relocation data or target data section was compressed. In
> that case it could happen we overestimated the size (because the Shdr
> would have been updated to show the uncompressed data size). But
> uncompressed data is always malloced and so cannot overlap with the
> mmapped Elf header structures.
> 
> When building with CFLAGS="-g -Og" this showed up as a failure in
> run-strip-reloc.sh for strip-compressed.o. Where the .debug_loc
> section decompressed would "overlap" with the shdrs at the end of
> the file and so wouldn't get relocations applied.

Pushed to master.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-11-26 10:37 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-23 20:20 [PATCH] libdwfl: Fix relocation overlap sanity check Mark Wielaard
2018-11-26 10:37 ` Mark Wielaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).