From 97c0a07968a7c64e1de96abff8937d089f09b3e7 Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
Date: Fri, 2 Aug 2019 12:35:39 +0930
Subject: PR24871, readelf segv in dump_ia64_unwind

	PR 24871
	* readelf.c (ABSADDR): Delete.
	(dump_ia64_unwind): Expand ABSADDR.  Check validity of info.section.
---
 binutils/ChangeLog |  6 ++++++
 binutils/readelf.c | 22 +++++++++++++++-------
 2 files changed, 21 insertions(+), 7 deletions(-)

(limited to 'binutils')

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index f3be264..f3dc48c 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2019-08-02  Alan Modra  <amodra@gmail.com>
+
+	PR 24871
+	* readelf.c (ABSADDR): Delete.
+	(dump_ia64_unwind): Expand ABSADDR.  Check validity of info.section.
+
 2019-07-29  Martin Liska  <mliska@suse.cz>
 
 	PR 24768
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 6175b33..b896ad9 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -7415,11 +7415,6 @@ struct absaddr
   bfd_vma offset;
 };
 
-#define ABSADDR(a) \
-  ((a).section \
-   ? filedata->section_headers [(a).section].sh_addr + (a).offset \
-   : (a).offset)
-
 /* Find the nearest symbol at or below ADDR.  Returns the symbol
    name, if found, and the offset from the symbol to ADDR.  */
 
@@ -7565,8 +7560,21 @@ dump_ia64_unwind (Filedata * filedata, struct ia64_unw_aux_info * aux)
       if (aux->info == NULL)
 	continue;
 
+      offset = tp->info.offset;
+      if (tp->info.section)
+	{
+	  if (tp->info.section >= filedata->file_header.e_shnum)
+	    {
+	      warn (_("Invalid section %u in table entry %ld\n"),
+		    tp->info.section, (long) (tp - aux->table));
+	      res = FALSE;
+	      continue;
+	    }
+	  offset += filedata->section_headers[tp->info.section].sh_addr;
+	}
+      offset -= aux->info_addr;
       /* PR 17531: file: 0997b4d1.  */
-      if ((ABSADDR (tp->info) - aux->info_addr) >= aux->info_size)
+      if (offset >= aux->info_size)
 	{
 	  warn (_("Invalid offset %lx in table entry %ld\n"),
 		(long) tp->info.offset, (long) (tp - aux->table));
@@ -7574,7 +7582,7 @@ dump_ia64_unwind (Filedata * filedata, struct ia64_unw_aux_info * aux)
 	  continue;
 	}
 
-      head = aux->info + (ABSADDR (tp->info) - aux->info_addr);
+      head = aux->info + offset;
       stamp = byte_get ((unsigned char *) head, sizeof (stamp));
 
       printf ("  v%u, flags=0x%lx (%s%s), len=%lu bytes\n",
-- 
cgit v1.1