[PATCH] x86: Make protected symbols local for -shared
H.J. Lu
hjl.tools@gmail.com
Tue Jul 19 01:44:00 GMT 2022
On Mon, Jun 27, 2022 at 09:18:27PM -0700, Fangrui Song wrote:
> On 2022-06-27, H.J. Lu wrote:
> > On Mon, Jun 27, 2022 at 8:44 PM Fangrui Song <i@maskray.me> wrote:
> > >
> > > On 2022-06-27, H.J. Lu wrote:
> > > >On Mon, Jun 27, 2022 at 8:07 PM Fangrui Song <i@maskray.me> wrote:
> > > >>
> > > >> On 2022-06-27, H.J. Lu wrote:
> > > >> >On Mon, Jun 27, 2022 at 11:46 AM Fangrui Song <i@maskray.me> wrote:
> > > >> >>
> > > >> >> On 2022-06-27, H.J. Lu wrote:
> > > >> >> >On Mon, Jun 27, 2022 at 10:53 AM Fangrui Song <i@maskray.me> wrote:
> > > >> >> >>
> > > >> >> >> On 2022-06-27, H.J. Lu wrote:
> > > >> >> >> >On Mon, Jun 27, 2022 at 10:09 AM Fangrui Song <i@maskray.me> wrote:
> > > >> >> >> >>
> > > >> >> >> >> On 2022-06-27, H.J. Lu wrote:
> > > >> >> >> >> >On Sun, Jun 26, 2022 at 12:03 PM Fangrui Song <i@maskray.me> wrote:
> > > >> >> >> >> >>
> > > >> >> >> >> >> On 2022-06-26, H.J. Lu wrote:
> > > >> >> >> >> >> >On Sat, Jun 25, 2022 at 10:44 AM Fangrui Song <i@maskray.me> wrote:
> > > >> >> >> >> >> >>
> > > >> >> >> >> >> >> Call _bfd_elf_symbol_refs_local_p with local_protected==true. This has
> > > >> >> >> >> >> >> 2 noticeable effects for -shared:
> > > >> >> >> >> >> >>
> > > >> >> >> >> >> >> * GOT-generating relocations referencing a protected data symbol no
> > > >> >> >> >> >> >> longer lead to a GLOB_DAT (similar to a hidden symbol).
> > > >> >> >> >> >> >> * Direct access relocations (e.g. R_X86_64_PC32) no longer has the
> > > >> >> >> >> >> >> confusing diagnostic below.
> > > >> >> >> >> >> >>
> > > >> >> >> >> >> >> __attribute__((visibility("protected"))) void *foo() {
> > > >> >> >> >> >> >> return (void *)foo;
> > > >> >> >> >> >> >> }
> > > >> >> >> >> >> >>
> > > >> >> >> >> >> >> // gcc -fpic -shared -fuse-ld=bfd
> > > >> >> >> >> >> >> relocation R_X86_64_PC32 against protected symbol `foo' can not be used when making a shared object
> > > >> >> >> >> >> >>
> > > >> >> >> >> >> >> The new behavior matches arm, aarch64 (commit
> > > >> >> >> >> >> >> 83c325007c5599fa9b60b8d5f7b84842160e1d1b), and powerpc ports, and other
> > > >> >> >> >> >> >> linkers: gold and ld.lld.
> > > >> >> >> >> >> >>
> > > >> >> >> >> >> >> Note: if some code tries to use direct access relocations to take the
> > > >> >> >> >> >> >> address of foo, the pointer equality will break, but the error should be
> > > >> >> >> >> >> >> reported on the executable link, not on the innocent shared object link.
> > > >> >> >> >> >> >> glibc 2.36 will give a warning at relocation resolving time.
> > > >> >> >> >> >> >
> > > >> >> >> >> >> >It should be controlled by -z [no]indirect-extern-access. Can you enable
> > > >> >> >> >> >> >-z indirect-extern-access with -shared by default instead?
> > > >> >> >> >> >>
> > > >> >> >> >> >> If I set `link_info.indirect_extern_access = 1;` in ld/ldmain.c,
> > > >> >> >> >> >> bfd/elf-properties.c:654 will create a
> > > >> >> >> >> >> GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS note.
> > > >> >> >> >> >> This will probably be unexpected (and check-ld will have 280+ failures).
> > > >> >> >> >> >
> > > >> >> >> >> >This is normal when the default behavior is changed. You can pass
> > > >> >> >> >> >-z noindirect-extern-access to these testcases.
> > > >> >> >> >>
> > > >> >> >> >> Adding GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS will be a
> > > >> >> >> >> significant behavior change and may unnecessarily break user programs
> > > >> >> >> >> (glibc will report an error instead of a warning).
> > > >> >> >> >
> > > >> >> >> >If glibc reports an error, it is a real bug with unknown consequences
> > > >> >> >> >when the copy in the executable is out of sync with the protected
> > > >> >> >> >symbol in the shared library,
> > > >> >> >>
> > > >> >> >> Not necessary.
> > > >> >> >>
> > > >> >> >> In glibc, GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS has two effects,
> > > >> >> >> 1 (copy relocations) and 2 (non-zero value of an undefined function
> > > >> >> >> symbol) on
> > > >> >> >> https://sourceware.org/pipermail/libc-alpha/2022-June/139552.html
> > > >> >> >>
> > > >> >> >> 2 does not necessarily cause a problem. In many cases it doesn't as
> > > >> >> >> function pointer equality is not an invariant a program relies upon
> > > >> >> >> (at least, for many functions, the property is not used). My previous
> > > >> >> >> comment has mentioned two cases.
> > > >> >> >>
> > > >> >> >> 1 likely causes a problem, but technically the shared object can define
> > > >> >> >> a protected data symbol without accessing it..
> > > >> >> >
> > > >> >> >These are unknown consequences. We don't know what the worst
> > > >> >> >cases are.
> > > >> >>
> > > >> >> They are, just like when a shared object is linked with -Bsymbolic.
> > > >> >
> > > >> >They have to deal with it since it is done on purpose.
> > > >> >
> > > >> >> This patch focuses on changing the x86 default to a sane value (matching
> > > >> >> aarch64/arm/powerpc64/riscv/etc) and enabling future removal of
> > > >> >> `extern_protected_data`. If you want to switch to
> > > >> >> indirect-extern-access default for x86, while I think unnecessary, I will not object.
> > > >> >
> > > >> >extern_protected_data can be safely removed only when
> > > >> >direct access to external symbols are disallowed. We can't
> > > >> >have both ways.
> > > >>
> > > >> Just define has_no_copy_on_protected to 1 to catch the usage at link
> > > >
> > > >This is the same as using -z indirect-extern-access on executable.
> > > >
> > > >> time. ld's aarch64 port has such an error by default. gold and ld.lld
> > > >> has such an error for a long time now.
> > > >>
> > > >> We don't need to worry about whether this stricter behavior breaks user
> > > >> programs. As is, protected symbol using GCC+binutils provides no
> > > >> benefit. Programs just avoid protected data symbols.
> > > >
> > > >Then there should be no problems with
> > > >GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
> > > >I'd like to disallow copy relocation on protected symbols at run-time
> > > >when there are unknown consequences.
> > >
> > > Enabling GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS for x86 by default
> > > has these effects:
> > >
> > > * 280+ check-ld tests will fail
> >
> > They should be updated.
>
> That will be a huge effort and may not be so necessary. See below.
>
> > > * The GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS note appears
> >
> > It will disallow copy relocation on protected symbols at run-time.
> >
> > > redundant. It encodes an intention explicit but the intention is
> > > in ld aarch64, gold (all ports), and lld (all ports) with no extra option.
> > >
> > > IMO, we should do these:
> > >
> > > * push this commit
> > > * treat elf_has_no_copy_on_protected as always true and remove all GNU_PROPERTY_NO_COPY_ON_PROTECTED
> > >
> > > Again, I understand that there is concern about protected data symbols
> > > in shared object. But as is, nobody uses protected symbols in shared objects.
> > > My
> > >
> > > // gcc -fpic -shared -fuse-ld=bfd
> > > __attribute__((visibility("protected"))) void *foo() {
> > > return (void *)foo;
> > > }
> > >
> > > example indicates that protected future symbol is also broken.
> >
> > To get protected symbol to work properly on x86-64, copy relocation on protected
> > symbols should be disallowed at run-time.
>
> Yes that GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS will change the
> glibc warning to an error, but we don't need to hurry making the cases
> an error. Since protected symbols do not have performance benefits (in
> gcc's many ports and GNU ld's x86 port), people avoid using it. My
> advise is to just let ld stop producing executables which will trigger
> glibc warning/error (this has precedent in gold and ld.lld and FreeBSD's
> adoption of ld.lld means that this goes actually very well). Projects
> will gradually fix their builds to enable indirect external access in
> the rare case they encounter protected symbols in shared objects. Then
> in a few years, the glibc warning can naturally upgrade to an error,
> with possibly a method (e.g. similar to LD_DYNAMIC_WEAK) to downgrade to
> a warning. Finally, remove the opt-out method.
>
> With this scheme no GNU property is needed.
Then, linker should disallow copy relocation against protected symbols
and non-canonical reference to canonical protected functions.
Something like this.
H.J.
----
x86: Disallow invalid relocations against protected symbols
Since glibc 2.36 will issue warnings for copy relocation against
protected symbols and non-canonical reference to canonical protected
functions, change the linker to always disallow such relocations.
bfd/
* elf32-i386.c (elf_i386_scan_relocs): Remove check for
elf_has_indirect_extern_access.
* elf64-x86-64.c (elf_x86_64_scan_relocs): Likewise.
(elf_x86_64_relocate_section): Remove check for
elf_has_no_copy_on_protected.
* elfxx-x86.c (elf_x86_allocate_dynrelocs): Check for building
executable instead of elf_has_no_copy_on_protected.
(_bfd_x86_elf_adjust_dynamic_symbol): Disallow copy relocation
against non-copyable protected symbol.
* elfxx-x86.h (SYMBOL_NO_COPYRELOC): Remove check for
elf_has_no_copy_on_protected.
ld/
* testsuite/ld-i386/i386.exp: Expect linker error for PR ld/17709
test.
* testsuite/ld-i386/pr17709.rd: Removed.
* testsuite/ld-i386/pr17709.err: New file.
* testsuite/ld-x86-64/pr17709.rd: Removed.
* testsuite/ld-x86-64/pr17709.err: New file.
* testsuite/ld-x86-64/pr28875-func.err: Updated.
* testsuite/ld-x86-64/x86-64.exp: Expect linker error for PR
ld/17709 test. Add tests for function pointer against protected
function.
---
bfd/elf32-i386.c | 3 +--
bfd/elf64-x86-64.c | 10 +++-------
bfd/elfxx-x86.c | 21 +++++++++++++++++++--
bfd/elfxx-x86.h | 3 +--
ld/testsuite/ld-i386/i386.exp | 2 +-
ld/testsuite/ld-i386/pr17709.err | 2 ++
ld/testsuite/ld-i386/pr17709.rd | 4 ----
ld/testsuite/ld-x86-64/pr17709.err | 2 ++
ld/testsuite/ld-x86-64/pr17709.rd | 4 ----
ld/testsuite/ld-x86-64/pr28875-func.err | 2 +-
ld/testsuite/ld-x86-64/x86-64.exp | 18 +++++++++++++++++-
11 files changed, 47 insertions(+), 24 deletions(-)
create mode 100644 ld/testsuite/ld-i386/pr17709.err
delete mode 100644 ld/testsuite/ld-i386/pr17709.rd
create mode 100644 ld/testsuite/ld-x86-64/pr17709.err
delete mode 100644 ld/testsuite/ld-x86-64/pr17709.rd
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 04a972e646d..cfb0085b245 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1812,8 +1812,7 @@ elf_i386_scan_relocs (bfd *abfd,
&& h->type == STT_FUNC
&& eh->def_protected
&& !SYMBOL_DEFINED_NON_SHARED_P (h)
- && h->def_dynamic
- && elf_has_indirect_extern_access (h->root.u.def.section->owner))
+ && h->def_dynamic)
{
/* Disallow non-canonical reference to canonical
protected function. */
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 3abc68a4127..62a9a22317a 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2255,8 +2255,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
&& h->type == STT_FUNC
&& eh->def_protected
&& !SYMBOL_DEFINED_NON_SHARED_P (h)
- && h->def_dynamic
- && elf_has_indirect_extern_access (h->root.u.def.section->owner))
+ && h->def_dynamic)
{
/* Disallow non-canonical reference to canonical
protected function. */
@@ -3156,8 +3155,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
|| (h != NULL
&& !h->root.linker_def
&& !h->root.ldscript_def
- && eh->def_protected
- && elf_has_no_copy_on_protected (h->root.u.def.section->owner)));
+ && eh->def_protected));
if ((input_section->flags & SEC_ALLOC) != 0
&& (input_section->flags & SEC_READONLY) != 0
@@ -4097,9 +4095,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
{
case R_X86_64_32S:
sec = h->root.u.def.section;
- if ((info->nocopyreloc
- || (eh->def_protected
- && elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
+ if ((info->nocopyreloc || eh->def_protected)
&& !(h->root.u.def.section->flags & SEC_CODE))
return elf_x86_64_need_pic (info, input_bfd, input_section,
h, NULL, NULL, howto);
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 18f3d335458..7fb972752b3 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -524,8 +524,7 @@ 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))
+ if (eh->def_protected && bfd_link_executable (info))
{
/* Disallow copy relocation against non-copyable protected
symbol. */
@@ -3041,6 +3040,24 @@ _bfd_x86_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
}
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
+ if (eh->def_protected && bfd_link_executable (info))
+ for (p = h->dyn_relocs; p != NULL; p = p->next)
+ {
+ /* Disallow copy relocation against non-copyable protected
+ symbol. */
+ 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;
+ }
+ }
+
srel->size += htab->sizeof_reloc;
h->needs_copy = 1;
}
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 77fb1ad72bc..7d23893938c 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -135,12 +135,11 @@
/* Should copy relocation be generated for a symbol. Don't generate
copy relocation against a protected symbol defined in a shared
- object with GNU_PROPERTY_NO_COPY_ON_PROTECTED. */
+ object. */
#define SYMBOL_NO_COPYRELOC(INFO, EH) \
((EH)->def_protected \
&& ((EH)->elf.root.type == bfd_link_hash_defined \
|| (EH)->elf.root.type == bfd_link_hash_defweak) \
- && elf_has_no_copy_on_protected ((EH)->elf.root.u.def.section->owner) \
&& ((EH)->elf.root.u.def.section->owner->flags & DYNAMIC) != 0 \
&& ((EH)->elf.root.u.def.section->flags & SEC_CODE) == 0)
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index b4f7de49fd5..0ab9c001336 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -224,7 +224,7 @@ set i386tests {
"--32 -mx86-used-note=yes" {pr17709a.s} {} "libpr17709.so"}
{"PR ld/17709 (2)" "-melf_i386 tmpdir/libpr17709.so" ""
"--32 -mx86-used-note=yes"
- {pr17709b.s} {{readelf -r pr17709.rd}} "pr17709"}
+ {pr17709b.s} {{ld "pr17709.err"}} "pr17709"}
{"Build pr19827a.o" "" ""
"--32 -mx86-used-note=yes" { pr19827a.S }}
{"Build pr19827b.so" "-melf_i386 -shared" ""
diff --git a/ld/testsuite/ld-i386/pr17709.err b/ld/testsuite/ld-i386/pr17709.err
new file mode 100644
index 00000000000..fa6a4bacce3
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr17709.err
@@ -0,0 +1,2 @@
+.*: tmpdir/pr17709b.o: copy relocation against non-copyable protected symbol `foo' in tmpdir/libpr17709.so
+#...
diff --git a/ld/testsuite/ld-i386/pr17709.rd b/ld/testsuite/ld-i386/pr17709.rd
deleted file mode 100644
index 8414784b736..00000000000
--- a/ld/testsuite/ld-i386/pr17709.rd
+++ /dev/null
@@ -1,4 +0,0 @@
-
-Relocation section '.rel\..*' at offset .* contains 1 entry:
- Offset Info Type Sym\.Value Sym\. Name
-[0-9a-f ]+R_386_COPY +[0-9a-f]+ +foo
diff --git a/ld/testsuite/ld-x86-64/pr17709.err b/ld/testsuite/ld-x86-64/pr17709.err
new file mode 100644
index 00000000000..fa6a4bacce3
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr17709.err
@@ -0,0 +1,2 @@
+.*: tmpdir/pr17709b.o: copy relocation against non-copyable protected symbol `foo' in tmpdir/libpr17709.so
+#...
diff --git a/ld/testsuite/ld-x86-64/pr17709.rd b/ld/testsuite/ld-x86-64/pr17709.rd
deleted file mode 100644
index beffd3cb34c..00000000000
--- a/ld/testsuite/ld-x86-64/pr17709.rd
+++ /dev/null
@@ -1,4 +0,0 @@
-
-Relocation section '.rela\..*' at offset .* contains 1 entry:
- +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
-[0-9a-f ]+R_X86_64_COPY+[0-9a-f ]+ +foo \+ 0
diff --git a/ld/testsuite/ld-x86-64/pr28875-func.err b/ld/testsuite/ld-x86-64/pr28875-func.err
index 64e961cb3d4..f6f4658deaf 100644
--- a/ld/testsuite/ld-x86-64/pr28875-func.err
+++ b/ld/testsuite/ld-x86-64/pr28875-func.err
@@ -1,2 +1,2 @@
-.*: tmpdir/protected-func-1b.o: non-canonical reference to canonical protected function `protected_func_1a' in tmpdir/libprotected-func-2b.so
+.*: tmpdir/protected-func-1b.o: non-canonical reference to canonical protected function `protected_func_1a' in tmpdir/libprotected-func-2..so
#...
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index a096c0b9d0f..e6a834a2a61 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -177,7 +177,7 @@ set x86_64tests {
{"PR ld/17709 (1)" "-melf_x86_64 -shared" ""
"--64" {pr17709a.s} {} "libpr17709.so"}
{"PR ld/17709 (2)" "-melf_x86_64 tmpdir/libpr17709.so" ""
- "--64" {pr17709b.s} {{readelf -rW pr17709.rd}} "pr17709"}
+ "--64" {pr17709b.s} {{ld "pr17709.err"}} "pr17709"}
{"Build pr19827a.o" "" ""
"--64" { pr19827a.S }}
{"Build pr19827b.so" "-melf_x86_64 -shared" ""
@@ -1383,6 +1383,22 @@ if { [isnative] && [check_compiler_available] } {
{{error_output "pr28875-func.err"}} \
"protected-func-2" \
] \
+ [list \
+ "Build libprotected-func-2c.so" \
+ "-shared" \
+ "-fPIC -Wa,-mx86-used-note=yes" \
+ { protected-func-2c.c } \
+ {} \
+ "libprotected-func-2c.so" \
+ ] \
+ [list \
+ "Build protected-func-2a without PIE" \
+ "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2c.so" \
+ "$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
+ { protected-func-1b.c } \
+ {{error_output "pr28875-func.err"}} \
+ "protected-func-2a" \
+ ] \
[list \
"Build libprotected-data-1a.so" \
"-shared -z noindirect-extern-access" \
--
2.36.1
More information about the Binutils
mailing list