Change the __canonicalize_funcptr_for_compare() implementation to stop
authorkettenis <kettenis@openbsd.org>
Mon, 9 Jan 2023 21:18:47 +0000 (21:18 +0000)
committerkettenis <kettenis@openbsd.org>
Mon, 9 Jan 2023 21:18:47 +0000 (21:18 +0000)
trying to read a branch instruction and decode it to extract the address
of the ld.so resolver function.  Instead, directly execute that branch
instruction.

This is effectively a C runtime ABI change.  In order to cross this if
you are building from source, make sure you install an updated ld.so
first.

ok deraadt@

gnu/gcc/gcc/config/pa/fptr.c

index af207a3..6949c46 100644 (file)
@@ -96,33 +96,12 @@ __canonicalize_funcptr_for_compare (fptr_t fptr)
      as the result is invariant.  */
   if (!fixup)
     {
-      int i;
-      unsigned int *iptr;
-
-      /* Find the first "bl" branch in the offset search list.  This is a
-        call to fixup or a magic branch to fixup at the beginning of the
-        trampoline template.  The fixup function does the actual runtime
-        resolution of function descriptors.  We only look for "bl" branches
-        with a 17-bit pc-relative displacement.  */
-      for (i = 0; i < NOFFSETS; i++)
-       {
-         iptr = (unsigned int *) (got[-2] + fixup_branch_offset[i]);
-         if ((*iptr & 0xfc00e000) == 0xe8000000)
-           break;
-       }
-
-      /* This should not happen... */
-      if (i == NOFFSETS)
-       return ~0;
-
-      /* Extract the 17-bit displacement from the instruction.  */
-      iptr += SIGN_EXTEND (GET_FIELD (*iptr, 19, 28) |
-                          GET_FIELD (*iptr, 29, 29) << 10 |
-                          GET_FIELD (*iptr, 11, 15) << 11 |
-                          GET_FIELD (*iptr, 31, 31) << 16, 17);
+      /* On OpenBSD, we have a magic branch to fixup just before the
+         trampoline template.  The fixup function does the actual
+         runtime resolution of function descriptors.  */
 
       /* Build a plabel for an indirect call to fixup.  */
-      fixup_plabel[0] = (unsigned int) iptr + 8;  /* address of fixup */
+      fixup_plabel[0] = got[-2] - 4;             /* address of fixup */
       fixup_plabel[1] = got[-1];                 /* ltp for fixup */
       fixup = (fixup_t) ((int) fixup_plabel | 3);
     }