x86: Disallow invalid relocation against protected symbol
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 9 Feb 2022 23:51:22 +0000 (15:51 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Fri, 11 Feb 2022 18:24:54 +0000 (10:24 -0800)
I am checking this into master and will backport it to 2.38 branch.

H.J
----
On x86, GCC 12 supports -mno-direct-extern-access to enable canonical
reference to protected function and disable copy relocation.  With
-mno-direct-extern-access, the canonical protected function symbols must
be accessed via canonical reference and the protected data symbols in
shared libraries are non-copyable. Under glibc 2.35, non-canonical
reference to the canonical protected function will get the run-time error:

./y: internal_f: ./libfoo.so: non-canonical reference to canonical protected function

and copy relocations against the non-copyable protected symbols will get
the run-time error:

./x: internal_i: ./libfoo.so: copy relocation against non-copyable protected symbol

Update x86 linker to disallow non-canonical reference to the canonical
protected function:

ld: plt.o: non-canonical reference to canonical protected function `internal_f' in libfoo.so
ld: failed to set dynamic section sizes: bad value

and copy relocation against the non-copyable protected symbol:

ld: main.o: copy relocation against non-copyable protected symbol `internal_i' in libfoo.so

at link-time.

bfd/

PR ld/28875
* elf-properties.c (_bfd_elf_parse_gnu_properties): Don't skip
shared libraries for GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
* elf32-i386.c (elf_i386_scan_relocs): Disallow non-canonical
reference to canonical protected function.
* elf64-x86-64.c (elf_x86_64_scan_relocs): Likewise.
* elfxx-x86.c (elf_x86_allocate_dynrelocs): Don't allow copy
relocation against non-copyable protected symbol.

ld/

PR ld/28875
* testsuite/ld-i386/i386.exp: Check non-canonical reference to
canonical protected function and check copy relocation against
non-copyable protected symbol.
* testsuite/ld-i386/pr21997-1.err: New file.
* testsuite/ld-i386/pr28875.err: Likewise.
* testsuite/ld-i386/pr28875a.c: Likewise.
* testsuite/ld-i386/pr28875b.c: Likewise.
* testsuite/ld-x86-64/pr21997-1a.err: Updated.
* testsuite/ld-x86-64/pr21997-1b.err: Likewise.
* testsuite/ld-x86-64/pr28875-data.err: New file.
* testsuite/ld-x86-64/pr28875-func.err: Likewise.
* testsuite/ld-x86-64/x86-64.exp: Check non-canonical reference
to canonical protected function and check copy relocation against
non-copyable protected symbol.

14 files changed:
bfd/elf-properties.c
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/elfxx-x86.c
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-i386/pr21997-1.err [new file with mode: 0644]
ld/testsuite/ld-i386/pr28875.err [new file with mode: 0644]
ld/testsuite/ld-i386/pr28875a.c [new file with mode: 0644]
ld/testsuite/ld-i386/pr28875b.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr21997-1a.err
ld/testsuite/ld-x86-64/pr21997-1b.err
ld/testsuite/ld-x86-64/pr28875-data.err [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr28875-func.err [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index bf4f70d62566e04cdb2867011464a3fd881af0df..d67aadde16b778477b2d8f73dce0eac74edb5417 100644 (file)
@@ -195,14 +195,11 @@ _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
                  prop = _bfd_elf_get_property (abfd, type, datasz);
                  prop->u.number |= bfd_h_get_32 (abfd, ptr);
                  prop->pr_kind = property_number;
-                 if ((abfd->flags & DYNAMIC) == 0
-                     && type == GNU_PROPERTY_1_NEEDED
+                 if (type == GNU_PROPERTY_1_NEEDED
                      && ((prop->u.number
                           & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
                          != 0))
                    {
-                     /* NB: Skip the shared library since it may not be
-                        the same at run-time.  */
                      elf_has_indirect_extern_access (abfd) = true;
                      /* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied.  */
                      elf_has_no_copy_on_protected (abfd) = true;
index 25977cc56bd6b73aa75205f11943ca08592ad631..fb5ed161f50c4cde39e8d7b24fe843fe18aaad09 100644 (file)
@@ -1779,6 +1779,23 @@ elf_i386_scan_relocs (bfd *abfd,
                    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;
+               }
+
              if (!func_pointer_ref)
                {
                  /* If this reloc is in a read-only section, we might
index 02ca55200bb2320549aaa4dd1eb03d555cadc8fc..b5718e71121fc58d6bf7277b81f57a45bdd42890 100644 (file)
@@ -2223,6 +2223,23 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
                    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;
+               }
+
              if (!func_pointer_ref)
                {
                  /* If this reloc is in a read-only section, we might
index d00dc45677b71832789002b9321f93a7951f4685..acb2cc8528db8f69bd5168da42cd64bcdabd1905 100644 (file)
@@ -524,6 +524,24 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       asection *sreloc;
 
+      if (eh->def_protected
+         && elf_has_no_copy_on_protected (h->root.u.def.section->owner))
+       {
+         /* Disallow copy relocation against non-copyable protected
+            symbol.  */
+         asection *s = p->sec->output_section;
+         if (s != NULL && (s->flags & SEC_READONLY) != 0)
+           {
+             info->callbacks->einfo
+               /* xgettext:c-format */
+               (_("%F%P: %pB: copy relocation against non-copyable "
+                  "protected symbol `%s' in %pB\n"),
+                p->sec->owner, h->root.root.string,
+                h->root.u.def.section->owner);
+             return false;
+           }
+       }
+
       sreloc = elf_section_data (p->sec)->sreloc;
 
       BFD_ASSERT (sreloc != NULL);
index 82e14ab38d05b842b8a7c4271c5bd771fdfaa1cb..d997c757325833847bb225e5ac1aa7e9c0c51404 100644 (file)
@@ -1288,6 +1288,30 @@ if { [isnative]
            {} \
            "pr22842.so" \
        ] \
+       [list \
+           "Build pr28875.so" \
+           "-shared -Wl,-z,indirect-extern-access" \
+           "-fPIC" \
+           { pr28875a.c } \
+           {} \
+           "pr28875.so" \
+       ] \
+       [list \
+           "Build pr28875" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/pr28875.so" \
+           "$NOPIE_CFLAGS" \
+           { pr28875b.c } \
+           {{error_output "pr28875.err"}} \
+           "pr28875" \
+       ] \
+       [list \
+           "Build pr21997-1" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,notext tmpdir/pr21997-1.so" \
+           "$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
+           { pr21997-1b.c } \
+           {{error_output "pr21997-1.err"}} \
+           "pr21997-1" \
+       ] \
     ]
 
     run_ld_link_exec_tests [list \
@@ -1343,15 +1367,6 @@ if { [isnative]
            "pass.out" \
            "-fPIC" \
        ] \
-       [list \
-           "Run pr21997-1" \
-           "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,notext tmpdir/pr21997-1.so" \
-           "-Wa,-mx86-used-note=yes" \
-           { pr21997-1b.c } \
-           "pr21997-1" \
-           "pass.out" \
-           "$NOPIE_CFLAGS" \
-       ] \
        [list \
            "Run pr21997-1 (PIC 1)" \
            "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/pr21997-1.so" \
diff --git a/ld/testsuite/ld-i386/pr21997-1.err b/ld/testsuite/ld-i386/pr21997-1.err
new file mode 100644 (file)
index 0000000..e46f1ce
--- /dev/null
@@ -0,0 +1,2 @@
+.*: tmpdir/pr21997-1b.o: copy relocation against non-copyable protected symbol `protected' in tmpdir/pr21997-1.so
+#...
diff --git a/ld/testsuite/ld-i386/pr28875.err b/ld/testsuite/ld-i386/pr28875.err
new file mode 100644 (file)
index 0000000..46f6f47
--- /dev/null
@@ -0,0 +1,2 @@
+.*: tmpdir/pr28875b.o: non-canonical reference to canonical protected function `internal_f' in tmpdir/pr28875.so
+#...
diff --git a/ld/testsuite/ld-i386/pr28875a.c b/ld/testsuite/ld-i386/pr28875a.c
new file mode 100644 (file)
index 0000000..d24cf29
--- /dev/null
@@ -0,0 +1,5 @@
+__attribute__ ((visibility("protected")))
+void
+internal_f (void)
+{
+}
diff --git a/ld/testsuite/ld-i386/pr28875b.c b/ld/testsuite/ld-i386/pr28875b.c
new file mode 100644 (file)
index 0000000..2c0381d
--- /dev/null
@@ -0,0 +1,7 @@
+extern void internal_f (void);
+
+int
+main ()
+{
+  return (int) &internal_f;
+}
index e57ebd1f4613333eaeb13717890f046a08f8261e..e46f1cebeb933a835a7f5600722ee1faa83fc32c 100644 (file)
@@ -1,2 +1,2 @@
-.*relocation R_X86_64_PC32 against protected symbol `protected' can not be used when making a P(D|I)E object; recompile with -fPIE
+.*: tmpdir/pr21997-1b.o: copy relocation against non-copyable protected symbol `protected' in tmpdir/pr21997-1.so
 #...
index a99fc1d5149e6a227cb8643312a3db88c71ea088..af028b7d5e9c612c268caf583048e4207c3f2aaa 100644 (file)
@@ -1,2 +1,2 @@
-.*relocation R_X86_64_32S against protected symbol `protected' can not be used when making a P(D|I)E object; recompile with -fPIE
+.*: tmpdir/pr21997-1c.o: copy relocation against non-copyable protected symbol `protected' in tmpdir/pr21997-1.so
 #...
diff --git a/ld/testsuite/ld-x86-64/pr28875-data.err b/ld/testsuite/ld-x86-64/pr28875-data.err
new file mode 100644 (file)
index 0000000..62dd5b0
--- /dev/null
@@ -0,0 +1,2 @@
+.*: tmpdir/protected-data-1b.o: copy relocation against non-copyable protected symbol `protected_data_1a' in tmpdir/libprotected-data-1b.so
+#...
diff --git a/ld/testsuite/ld-x86-64/pr28875-func.err b/ld/testsuite/ld-x86-64/pr28875-func.err
new file mode 100644 (file)
index 0000000..64e961c
--- /dev/null
@@ -0,0 +1,2 @@
+.*: tmpdir/protected-func-1b.o: non-canonical reference to canonical protected function `protected_func_1a' in tmpdir/libprotected-func-2b.so
+#...
index 3bfc5e6e467c6739c596576a57d21dece104790e..c6d88a97f497cfcac4fefa22e6a8f5502f628736 100644 (file)
@@ -1381,6 +1381,14 @@ if { [isnative] && [check_compiler_available] } {
            {{readelf -n indirect-extern-access.rd}}  \
            "libprotected-func-2b.so" \
        ] \
+       [list \
+           "Build protected-func-2 without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2b.so" \
+           "$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
+           { protected-func-1b.c } \
+           {{error_output "pr28875-func.err"}} \
+           "protected-func-2" \
+       ] \
        [list \
            "Build libprotected-data-1a.so" \
            "-shared -z noindirect-extern-access" \
@@ -1402,7 +1410,7 @@ if { [isnative] && [check_compiler_available] } {
            "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1b.so" \
            "$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
            { protected-data-1b.c } \
-           {} \
+           {{error_output "pr28875-data.err"}} \
            "protected-data-1" \
        ] \
        [list \
@@ -1468,6 +1476,14 @@ if { [isnative] && [check_compiler_available] } {
                "-Wa,-mx86-used-note=yes" \
                { pr25416-5d.s } \
            ] \
+           [list \
+               "Build pr21997-1b" \
+               "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,notext tmpdir/pr21997-1.so" \
+               "$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
+               { pr21997-1c.c } \
+               {{error_output "pr21997-1b.err"}} \
+               "pr21997-1b" \
+           ] \
        ]
 
        run_ld_link_exec_tests [list \
@@ -1480,15 +1496,6 @@ if { [isnative] && [check_compiler_available] } {
                "pass.out" \
                "$NOPIE_CFLAGS" \
            ] \
-           [list \
-               "Run pr21997-1b" \
-               "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,notext tmpdir/pr21997-1.so" \
-               "-Wa,-mx86-used-note=yes" \
-               { pr21997-1c.c } \
-               "pr21997-1b" \
-               "pass.out" \
-               "$NOPIE_CFLAGS" \
-           ] \
            [list \
                "Run pr25416-5a (GDesc -> IE -maddress-mode=short)" \
                "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/pr25416-5b.so" \