x86: Properly handle function pointer reference
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 26 Apr 2022 16:08:54 +0000 (09:08 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 28 Apr 2022 16:20:30 +0000 (09:20 -0700)
Update

commit ebb191adac4ab45498dec0bfaac62f0a33537ba4
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Feb 9 15:51:22 2022 -0800

    x86: Disallow invalid relocation against protected symbol

to allow function pointer reference and make sure that PLT entry isn't
used for function reference due to function pointer reference.

bfd/

PR ld/29087
* elf32-i386.c (elf_i386_scan_relocs): Don't set
pointer_equality_needed nor check non-canonical reference for
function pointer reference.
* elf64-x86-64.c (elf_x86_64_scan_relocs): Likewise.

ld/

PR ld/29087
* testsuite/ld-x86-64/x86-64.exp: Run PR ld/29087 tests.
* testsuite/ld-x86-64/protected-func-3.c: New file.

bfd/elf32-i386.c
bfd/elf64-x86-64.c
ld/testsuite/ld-x86-64/protected-func-3.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index fb5ed161f50c4cde39e8d7b24fe843fe18aaad09..b034154fb97fd74d743607173c72e568f8e7588d 100644 (file)
@@ -1772,28 +1772,14 @@ elf_i386_scan_relocs (bfd *abfd,
                }
              else
                {
-                 h->pointer_equality_needed = 1;
-                 /* R_386_32 can be resolved at run-time.  */
+                 /* R_386_32 can be resolved at run-time.  Function
+                    pointer reference doesn't need PLT for pointer
+                    equality.  */
                  if (r_type == R_386_32
                      && (sec->flags & SEC_READONLY) == 0)
                    func_pointer_ref = true;
-               }
-
-             if (h->pointer_equality_needed
-                 && h->type == STT_FUNC
-                 && eh->def_protected
-                 && elf_has_indirect_extern_access (h->root.u.def.section->owner))
-               {
-                 /* Disallow non-canonical reference to canonical
-                    protected function.  */
-                 _bfd_error_handler
-                   /* xgettext:c-format */
-                   (_("%pB: non-canonical reference to canonical "
-                      "protected function `%s' in %pB"),
-                    abfd, h->root.root.string,
-                    h->root.u.def.section->owner);
-                 bfd_set_error (bfd_error_bad_value);
-                 goto error_return;
+                 else
+                   h->pointer_equality_needed = 1;
                }
 
              if (!func_pointer_ref)
@@ -1815,6 +1801,23 @@ elf_i386_scan_relocs (bfd *abfd,
                  if (!h->def_regular
                      || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
                    h->plt.refcount = 1;
+
+                 if (h->pointer_equality_needed
+                     && h->type == STT_FUNC
+                     && eh->def_protected
+                     && elf_has_indirect_extern_access (h->root.u.def.section->owner))
+                   {
+                     /* Disallow non-canonical reference to canonical
+                        protected function.  */
+                     _bfd_error_handler
+                       /* xgettext:c-format */
+                       (_("%pB: non-canonical reference to canonical "
+                          "protected function `%s' in %pB"),
+                        abfd, h->root.root.string,
+                        h->root.u.def.section->owner);
+                     bfd_set_error (bfd_error_bad_value);
+                     goto error_return;
+                   }
                }
            }
 
index 6cebc7ca2b32d7308041e67e2d434d4b8dcaa9e1..6d69d6141ee4a26b38052a5ef10146eb52a809b7 100644 (file)
@@ -2211,33 +2211,18 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
              else if (r_type != R_X86_64_PC32_BND
                       && r_type != R_X86_64_PC64)
                {
-                 h->pointer_equality_needed = 1;
                  /* At run-time, R_X86_64_64 can be resolved for both
                     x86-64 and x32. But R_X86_64_32 and R_X86_64_32S
-                    can only be resolved for x32.  */
+                    can only be resolved for x32.  Function pointer
+                    reference doesn't need PLT for pointer equality.  */
                  if ((sec->flags & SEC_READONLY) == 0
                      && (r_type == R_X86_64_64
                          || (!ABI_64_P (abfd)
                              && (r_type == R_X86_64_32
                                  || r_type == R_X86_64_32S))))
                    func_pointer_ref = true;
-               }
-
-             if (h->pointer_equality_needed
-                 && h->type == STT_FUNC
-                 && eh->def_protected
-                 && elf_has_indirect_extern_access (h->root.u.def.section->owner))
-               {
-                 /* Disallow non-canonical reference to canonical
-                    protected function.  */
-                 _bfd_error_handler
-                   /* xgettext:c-format */
-                   (_("%pB: non-canonical reference to canonical "
-                      "protected function `%s' in %pB"),
-                    abfd, h->root.root.string,
-                    h->root.u.def.section->owner);
-                 bfd_set_error (bfd_error_bad_value);
-                 goto error_return;
+                 else
+                   h->pointer_equality_needed = 1;
                }
 
              if (!func_pointer_ref)
@@ -2259,6 +2244,23 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (!h->def_regular
                      || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
                    h->plt.refcount = 1;
+
+                 if (h->pointer_equality_needed
+                     && h->type == STT_FUNC
+                     && eh->def_protected
+                     && elf_has_indirect_extern_access (h->root.u.def.section->owner))
+                   {
+                     /* Disallow non-canonical reference to canonical
+                        protected function.  */
+                     _bfd_error_handler
+                       /* xgettext:c-format */
+                       (_("%pB: non-canonical reference to canonical "
+                          "protected function `%s' in %pB"),
+                        abfd, h->root.root.string,
+                        h->root.u.def.section->owner);
+                     bfd_set_error (bfd_error_bad_value);
+                     goto error_return;
+                   }
                }
            }
 
diff --git a/ld/testsuite/ld-x86-64/protected-func-3.c b/ld/testsuite/ld-x86-64/protected-func-3.c
new file mode 100644 (file)
index 0000000..bbf433b
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdio.h>
+
+#include "protected-func-1.h"
+
+protected_func_type protected_func_1a_ptr = protected_func_1a;
+protected_func_type protected_func_1b_ptr = protected_func_1b;
+
+int
+protected_func_1b (void)
+{
+  return 3;
+}
+
+int
+main (void)
+{
+  int res = 0;
+
+  protected_func_1a ();
+  protected_func_1b ();
+
+  /* Check if we get the same address for the protected function symbol.  */
+  if (protected_func_1a_ptr != protected_func_1a_p ())
+    {
+      puts ("'protected_func_1a' in main and shared library doesn't have same address");
+      res = 1;
+    }
+
+  /* Check if we get the different addresses for the protected function
+     symbol.  */
+  if (protected_func_1b_ptr == protected_func_1b_p ())
+    {
+      puts ("'protected_func_1b' in main and shared library has same address");
+      res = 1;
+    }
+
+  if (!res)
+    puts ("PASS");
+
+  return res;
+}
index 1a7d1eddc97a9c260653d38935e00a388e0ec7bb..5e5636bcebee05ff8b701603d10a4518b817d22e 100644 (file)
@@ -1886,6 +1886,24 @@ if { [isnative] && [check_compiler_available] } {
            "pass.out" \
            "-fPIE" \
        ] \
+       [list \
+           "Run protected-func-3a without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-func-3.c } \
+           "protected-func-3a" \
+           "pass.out" \
+           "$NOPIE_CFLAGS" \
+       ] \
+       [list \
+           "Run protected-func-3b with PIE" \
+           "-Wl,--no-as-needed -pie tmpdir/libprotected-func-2a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-func-3.c } \
+           "protected-func-2b" \
+           "pass.out" \
+           "-fPIE" \
+       ] \
        [list \
            "Run protected-data-1a without PIE" \
            "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1a.so" \