[committed] hppa: Add read access checks to __canonicalize_funcptr_for_compare

Message ID 83d49762-c58f-4cd1-9af9-fbbf9bd68cf2@bell.net
State New
Headers show
Series
  • [committed] hppa: Add read access checks to __canonicalize_funcptr_for_compare
Related show

Commit Message

John David Anglin March 7, 2018, 12:31 a.m.
The attached change fixes the build of the Debian cpputest package on 
hppa.  The testsuite
generates a segmentation fault canonicalizing the function pointer 
0xdeadbeef.  The attached
patch adds a routine from the hppa dynamic linker to check for read 
access permission.  So,
we are now less likely to generate a segmentation fault canonicalizing a 
function pointer.

Tested on hppa-unknown-linux-gnu with no observed regressions. Committed 
to trunk.

Dave

-- 
John David Anglin  dave.anglin@bell.net
2018-03-06  John David Anglin  <danglin@gcc.gnu.org>

	* config/pa/fptr.c (_dl_read_access_allowed): New.
	(__canonicalize_funcptr_for_compare): Use it.

Patch

Index: config/pa/fptr.c
===================================================================
--- config/pa/fptr.c	(revision 258235)
+++ config/pa/fptr.c	(working copy)
@@ -52,6 +52,16 @@ 
 typedef int (*fixup_t) (struct link_map *, unsigned int);
 extern unsigned int _GLOBAL_OFFSET_TABLE_;
 
+static inline int
+_dl_read_access_allowed (unsigned int *addr)
+{
+  int result;
+
+  asm ("proberi (%1),3,%0" : "=r" (result) : "r" (addr) : );
+
+  return result;
+}
+
 /* __canonicalize_funcptr_for_compare must be hidden so that it is not
    placed in the dynamic symbol table.  Like millicode functions, it
    must be linked into all binaries in order access the got table of 
@@ -82,6 +92,16 @@ 
      The second word in the plabel contains the relocation offset for the
      function.  */
   plabel = (unsigned int *) ((unsigned int) fptr & ~3);
+  if (!_dl_read_access_allowed (plabel))
+    return (unsigned int) fptr;
+
+  /* Load first word of candidate descriptor.  It should be a pointer
+     with word alignment and point to memory that can be read.  */
+  got = (unsigned int *) plabel[0];
+  if (((unsigned int) got & 3) != 0
+      || !_dl_read_access_allowed (got))
+    return (unsigned int) fptr;
+
   got = (unsigned int *) (plabel[0] + GOT_FROM_PLT_STUB);
 
   /* Return the address of the function if the plabel has been resolved.  */