This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] elf: Properly compute offsets of desc and next note


On Fri, Nov 24, 2017 at 2:42 PM, Simon Marchi <simon.marchi@ericsson.com> wrote:
> On 2017-11-24 05:20 PM, H.J. Lu wrote:
>> On Fri, Nov 24, 2017 at 12:53 PM, Simon Marchi
>> <simon.marchi@ericsson.com> wrote:
>>> Hi,
>>>
>>> Pedro found that this patch caused the GDB test "gdb.base/auxv.exp" to
>>> consume memory until the machine becomes unresponsive.  I was able to
>>> reproduce it too, so I chose to revert the patch, to reduce the risk
>>> of it happening on other developer's machines and buildbot builders.
>>>
>>> The test can be ran with:
>>>
>>>   gdb/$ make check TESTS="gdb.base/auxv.exp"
>>>
>>> (It's a good idea to ctrl-C quickly enough :))
>>>
>>> After running the test once, I was able to reproduce the issue by starting
>>> GDB manually like this:
>>>
>>>   gdb/$ ./gdb -ex "core /home/emaisin/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/auxv/auxv.corefile"
>>>
>>> There is an infinite loop in elf_parse_notes, the pointer "p" never
>>> gets advanced.
>>>
>>
>> This patch fixes the problem for me.  Please give it a try.
>>
>> Thanks.
>
> It works fine on my side, thanks.
>

Here is the patch against master branch.   Please give it try.

Thanks.


-- 
H.J.
From 276da9b31bd6e3eb8d1dd814c867266f59f29093 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 24 Nov 2017 14:49:36 -0800
Subject: [PATCH] Re-apply "elf: Properly compute offsets of note descriptor
 and next note"

CORE PT_NOTE segments may have p_align values of 0 or 1.  gABI specifies
that PT_NOTE alignment should be aligned to 4 bytes for 32-bit objects
and to 8 bytes for 64-bit objects.  If segment alignment is less than 4,
we use 4 byte alignment.
---
 bfd/ChangeLog          | 15 +++++++++++++++
 bfd/elf.c              | 31 +++++++++++++++++++++----------
 binutils/ChangeLog     |  7 +++++++
 binutils/readelf.c     |  8 ++++++--
 include/ChangeLog      |  7 +++++++
 include/elf/external.h | 16 ++++++++++++++++
 6 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 55fe3b4e61..0395dcf6cc 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,18 @@
+2017-11-24  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR binutils/22444
+	* elf.c (elf_read_notes): Add an argument for note aligment.
+	(elf_parse_notes): Likewise.
+	(_bfd_elf_make_section_from_shdr): Pass section aligment to
+	elf_parse_notes.
+	(bfd_section_from_phdr): Pass segment aligment to elf_read_notes.
+	(elf_parse_notes): Add an argument for note aligment.  Use
+	ELF_NOTE_DESC_OFFSET to get the offset of the note descriptor.
+	Use ELF_NOTE_NEXT_OFFSET to get the offset of the next note
+	entry.
+	(elf_read_notes): Add an argument for note aligment and pass it
+	to elf_parse_notes.
+
 2017-11-23  Alan Modra  <amodra@gmail.com>
 
 	* elf32-hppa.c (pc_dynrelocs): Define.
diff --git a/bfd/elf.c b/bfd/elf.c
index 8cd67ad59b..8f6aa53b5c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -52,9 +52,10 @@ static int elf_sort_sections (const void *, const void *);
 static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
 static bfd_boolean prep_headers (bfd *);
 static bfd_boolean swap_out_syms (bfd *, struct elf_strtab_hash **, int) ;
-static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
+static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type,
+				   size_t align) ;
 static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
-				    file_ptr offset);
+				    file_ptr offset, size_t align);
 
 /* Swap version information in and out.  The version information is
    currently size independent.  If that ever changes, this code will
@@ -1089,7 +1090,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       if (!bfd_malloc_and_get_section (abfd, newsect, &contents))
 	return FALSE;
 
-      elf_parse_notes (abfd, (char *) contents, hdr->sh_size, hdr->sh_offset);
+      elf_parse_notes (abfd, (char *) contents, hdr->sh_size,
+		       hdr->sh_offset, hdr->sh_addralign);
       free (contents);
     }
 
@@ -2990,7 +2992,8 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
     case PT_NOTE:
       if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "note"))
 	return FALSE;
-      if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
+      if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz,
+			    hdr->p_align))
 	return FALSE;
       return TRUE;
 
@@ -10970,14 +10973,21 @@ elfcore_write_register_note (bfd *abfd,
 }
 
 static bfd_boolean
-elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
+elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset,
+		 size_t align)
 {
   char *p;
 
+  /* NB: CORE PT_NOTE segments may have p_align values of 0 or 1.
+     gABI specifies that PT_NOTE alignment should be aligned to 4
+     bytes for 32-bit objects and to 8 bytes for 64-bit objects.  If
+     align is less than 4, we use 4 byte alignment.   */
+  if (align < 4)
+    align = 4;
+
   p = buf;
   while (p < buf + size)
     {
-      /* FIXME: bad alignment assumption.  */
       Elf_External_Note *xnp = (Elf_External_Note *) p;
       Elf_Internal_Note in;
 
@@ -10992,7 +11002,7 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
 	return FALSE;
 
       in.descsz = H_GET_32 (abfd, xnp->descsz);
-      in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
+      in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align);
       in.descpos = offset + (in.descdata - buf);
       if (in.descsz != 0
 	  && (in.descdata >= buf + size
@@ -11054,14 +11064,15 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
 	  break;
 	}
 
-      p = in.descdata + BFD_ALIGN (in.descsz, 4);
+      p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align);
     }
 
   return TRUE;
 }
 
 static bfd_boolean
-elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
+elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size,
+		size_t align)
 {
   char *buf;
 
@@ -11080,7 +11091,7 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
   buf[size] = 0;
 
   if (bfd_bread (buf, size, abfd) != size
-      || !elf_parse_notes (abfd, buf, size, offset))
+      || !elf_parse_notes (abfd, buf, size, offset, align))
     {
       free (buf);
       return FALSE;
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 32df4b98f7..eab683047e 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,10 @@
+2017-11-24  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR binutils/22444
+	* readelf.c (process_notes_at): Use ELF_NOTE_DESC_OFFSET to get
+	the offset of the note descriptor.  Use ELF_NOTE_NEXT_OFFSET to
+	get the offset of the next note entry.
+
 2017-11-23  Pavel I. Kryukov  <kryukov@frtk.ru>
 
 	PR 22485
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5944ebee96..739367d899 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -17969,9 +17969,13 @@ process_notes_at (Filedata *           filedata,
 	  inote.namesz   = BYTE_GET (external->namesz);
 	  inote.namedata = external->name;
 	  inote.descsz   = BYTE_GET (external->descsz);
-	  inote.descdata = inote.namedata + align_power (inote.namesz, 2);
+	  inote.descdata = ((char *) external
+			    + ELF_NOTE_DESC_OFFSET (inote.namesz,
+						    section->sh_addralign));
 	  inote.descpos  = offset + (inote.descdata - (char *) pnotes);
-	  next = inote.descdata + align_power (inote.descsz, 2);
+	  next = ((char *) external
+		  + ELF_NOTE_NEXT_OFFSET (inote.namesz, inote.descsz,
+					  section->sh_addralign));
 	}
       else
 	{
diff --git a/include/ChangeLog b/include/ChangeLog
index 670456cece..a7668678f8 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,10 @@
+2017-11-24  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR binutils/22444
+	* elf/external.h (ELF_ALIGN_UP): New.
+	(ELF_NOTE_DESC_OFFSET): Likewise.
+	(ELF_NOTE_NEXT_OFFSET): Likewise.
+
 2017-11-16  Tamar Christina  <tamar.christina@arm.com>
 
 	* opcode/aarch64.h: (AARCH64_FEATURE_F16_FML): New.
diff --git a/include/elf/external.h b/include/elf/external.h
index d65bae0b21..eb0a53a9a9 100644
--- a/include/elf/external.h
+++ b/include/elf/external.h
@@ -183,6 +183,22 @@ typedef struct {
   char		name[1];		/* Start of the name+desc data */
 } Elf_External_Note;
 
+/* Align an address upward to a boundary, expressed as a number of bytes.
+   E.g. align to an 8-byte boundary with argument of 8.  */
+#define ELF_ALIGN_UP(addr, boundary) \
+  (((bfd_vma) (addr) + ((boundary) - 1)) & ~ (bfd_vma) ((boundary) -1))
+
+/* Compute the offset of the note descriptor from size of note entry's
+   owner string and note alignment.  */
+#define ELF_NOTE_DESC_OFFSET(namesz, align) \
+  ELF_ALIGN_UP (offsetof (Elf_External_Note, name) + (namesz), (align))
+
+/* Compute the offset of the next note entry from size of note entry's
+   owner string, size of the note descriptor and note alignment.  */
+#define ELF_NOTE_NEXT_OFFSET(namesz, descsz, align) \
+  ELF_ALIGN_UP (ELF_NOTE_DESC_OFFSET ((namesz), (align)) + (descsz), \
+		(align))
+
 /* Relocation Entries */
 typedef struct {
   unsigned char r_offset[4];	/* Location at which to apply the action */
-- 
2.14.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]