Message ID | 20250102192006.1318325-2-adhemerval.zanella@linaro.org |
---|---|
State | New |
Headers | show |
Series | elf: Add GNU_PROPERTY_MEMORY_SEAL gnu property | expand |
On Fri, Jan 3, 2025 at 3:20 AM Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote: > > The GNU_PROPERTY_MEMORY_SEAL gnu property is a way to mark binaries > to be memory sealed by the loader, to avoid further changes of > PT_LOAD segments (such as unmapping or change permission flags). > This is done along with Linux kernel (the mseal syscall [1]), and > C runtime supports to instruct the kernel on the correct time during > program startup (for instance, after RELRO handling). This support > is added along the glibc support to handle the new gnu property [2]. > > This is a opt-in security features, like other security hardening > ones like NX-stack or RELRO. > > The new property is ignored if present on ET_REL objects, and only > added on ET_EXEC/ET_DYN if the linker option is used. A gnu property > is used instead of DT_FLAGS_1 flag to allow memory sealing to work > with ET_EXEC without PT_DYNAMIC support (at least on glibc some ports > still do no support static-pie). > > [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8be7258aad44b5e25977a98db136f677fa6f4370 > [2] https://sourceware.org/pipermail/libc-alpha/2024-September/160291.html > > Change-Id: Id47fadabecd24be0e83cff45653f7ce9a900ecf4 > --- > bfd/elf-properties.c | 85 +++++++++++++++++++++------ > bfd/elfxx-x86.c | 3 +- > binutils/readelf.c | 6 ++ > include/bfdlink.h | 3 + > include/elf/common.h | 1 + > ld/NEWS | 3 + > ld/emultempl/elf.em | 4 ++ > ld/ld.texi | 8 +++ > ld/lexsup.c | 4 ++ > ld/testsuite/ld-elf/property-seal-1.d | 16 +++++ > ld/testsuite/ld-elf/property-seal-1.s | 11 ++++ > ld/testsuite/ld-elf/property-seal-2.d | 17 ++++++ > ld/testsuite/ld-elf/property-seal-3.d | 16 +++++ > ld/testsuite/ld-elf/property-seal-4.d | 16 +++++ > ld/testsuite/ld-elf/property-seal-5.d | 15 +++++ > ld/testsuite/ld-elf/property-seal-6.d | 16 +++++ > ld/testsuite/ld-elf/property-seal-7.d | 14 +++++ > ld/testsuite/ld-elf/property-seal-8.d | 15 +++++ > 18 files changed, 235 insertions(+), 18 deletions(-) > create mode 100644 ld/testsuite/ld-elf/property-seal-1.d > create mode 100644 ld/testsuite/ld-elf/property-seal-1.s > create mode 100644 ld/testsuite/ld-elf/property-seal-2.d > create mode 100644 ld/testsuite/ld-elf/property-seal-3.d > create mode 100644 ld/testsuite/ld-elf/property-seal-4.d > create mode 100644 ld/testsuite/ld-elf/property-seal-5.d > create mode 100644 ld/testsuite/ld-elf/property-seal-6.d > create mode 100644 ld/testsuite/ld-elf/property-seal-7.d > create mode 100644 ld/testsuite/ld-elf/property-seal-8.d > > diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c > index 61f01bf5380..23634a9d9c9 100644 > --- a/bfd/elf-properties.c > +++ b/bfd/elf-properties.c > @@ -177,6 +177,20 @@ _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note) > prop->pr_kind = property_number; > goto next; > > + case GNU_PROPERTY_MEMORY_SEAL: > + if (datasz != 0) > + { > + _bfd_error_handler > + (_("warning: %pB: corrupt memory sealing size: 0x%x"), > + abfd, datasz); > + /* Clear all properties. */ > + elf_properties (abfd) = NULL; > + return false; > + } > + prop = _bfd_elf_get_property (abfd, type, datasz); > + prop->pr_kind = property_number; > + goto next; > + > default: > if ((type >= GNU_PROPERTY_UINT32_AND_LO > && type <= GNU_PROPERTY_UINT32_AND_HI) > @@ -254,6 +268,7 @@ elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd, > /* FALLTHROUGH */ > > case GNU_PROPERTY_NO_COPY_ON_PROTECTED: > + case GNU_PROPERTY_MEMORY_SEAL: > /* Return TRUE if APROP is NULL to indicate that BPROP should > be added to ABFD. */ > return aprop == NULL; > @@ -607,6 +622,33 @@ elf_write_gnu_properties (struct bfd_link_info *info, > } > } > > +static asection * > +_bfd_elf_link_create_gnu_property_sec (struct bfd_link_info *info, bfd *elf_bfd, > + unsigned int elfclass) > +{ > + asection *sec; > + > + sec = bfd_make_section_with_flags (elf_bfd, > + NOTE_GNU_PROPERTY_SECTION_NAME, > + (SEC_ALLOC > + | SEC_LOAD > + | SEC_IN_MEMORY > + | SEC_READONLY > + | SEC_HAS_CONTENTS > + | SEC_DATA)); > + if (sec == NULL) > + info->callbacks->einfo (_("%F%P: failed to create GNU property section\n")); > + > + if (!bfd_set_section_alignment (sec, > + elfclass == ELFCLASS64 ? 3 : 2)) > + info->callbacks->einfo (_("%F%pA: failed to align section\n"), > + sec); > + > + elf_section_type (sec) = SHT_NOTE; > + return sec; > +} > + > + > /* Set up GNU properties. Return the first relocatable ELF input with > GNU properties if found. Otherwise, return NULL. */ > > @@ -656,23 +698,7 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) > /* Support -z indirect-extern-access. */ > if (first_pbfd == NULL) > { > - sec = bfd_make_section_with_flags (elf_bfd, > - NOTE_GNU_PROPERTY_SECTION_NAME, > - (SEC_ALLOC > - | SEC_LOAD > - | SEC_IN_MEMORY > - | SEC_READONLY > - | SEC_HAS_CONTENTS > - | SEC_DATA)); > - if (sec == NULL) > - info->callbacks->einfo (_("%F%P: failed to create GNU property section\n")); > - > - if (!bfd_set_section_alignment (sec, > - elfclass == ELFCLASS64 ? 3 : 2)) > - info->callbacks->einfo (_("%F%pA: failed to align section\n"), > - sec); > - > - elf_section_type (sec) = SHT_NOTE; > + sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass); > first_pbfd = elf_bfd; > has_properties = true; > } > @@ -690,6 +716,31 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) > |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS; > } > > + if (elf_bfd != NULL) > + { > + if (info->memory_seal) > + { > + /* Support -z no-memory-seal. */ > + if (first_pbfd == NULL) > + { > + sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass); > + first_pbfd = elf_bfd; > + has_properties = true; > + } > + > + p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_MEMORY_SEAL, 0); > + if (p->pr_kind == property_unknown) > + { > + /* Create GNU_PROPERTY_NO_MEMORY_SEAL. */ > + p->u.number = GNU_PROPERTY_MEMORY_SEAL; > + p->pr_kind = property_number; > + } > + } > + else > + elf_find_and_remove_property (&elf_properties (elf_bfd), > + GNU_PROPERTY_MEMORY_SEAL, true); > + } > + > /* Do nothing if there is no .note.gnu.property section. */ > if (!has_properties) > return NULL; > diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c > index 60e81f518a7..7c164e9c131 100644 > --- a/bfd/elfxx-x86.c > +++ b/bfd/elfxx-x86.c > @@ -4892,7 +4892,8 @@ _bfd_x86_elf_link_fixup_gnu_properties > for (p = *listp; p; p = p->next) > { > unsigned int type = p->property.pr_type; > - if (type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED > + if (type == GNU_PROPERTY_MEMORY_SEAL > + || type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED > || type == GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED > || (type >= GNU_PROPERTY_X86_UINT32_AND_LO > && type <= GNU_PROPERTY_X86_UINT32_AND_HI) > diff --git a/binutils/readelf.c b/binutils/readelf.c > index 4f8f879cf91..0f29b65fe30 100644 > --- a/binutils/readelf.c > +++ b/binutils/readelf.c > @@ -21476,6 +21476,12 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote) > printf (_("<corrupt length: %#x> "), datasz); > goto next; > > + case GNU_PROPERTY_MEMORY_SEAL: > + printf ("memory seal "); > + if (datasz) > + printf (_("<corrupt length: %#x> "), datasz); > + goto next; > + > default: > if ((type >= GNU_PROPERTY_UINT32_AND_LO > && type <= GNU_PROPERTY_UINT32_AND_HI) > diff --git a/include/bfdlink.h b/include/bfdlink.h > index 85e7da84406..ae451075996 100644 > --- a/include/bfdlink.h > +++ b/include/bfdlink.h > @@ -429,6 +429,9 @@ struct bfd_link_info > /* TRUE if only one read-only, non-code segment should be created. */ > unsigned int one_rosegment: 1; > > + /* TRUE if GNU_PROPERTY_MEMORY_SEAL should be generated. */ > + unsigned int memory_seal: 1; > + > /* Nonzero if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment > should be created. 1 for DWARF2 tables, 2 for compact tables. */ > unsigned int eh_frame_hdr_type: 2; > diff --git a/include/elf/common.h b/include/elf/common.h > index 6077db7a8b7..2e2c486bf8d 100644 > --- a/include/elf/common.h > +++ b/include/elf/common.h > @@ -890,6 +890,7 @@ > /* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */ > #define GNU_PROPERTY_STACK_SIZE 1 > #define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2 > +#define GNU_PROPERTY_MEMORY_SEAL 3 > > /* A 4-byte unsigned integer property: A bit is set if it is set in all > relocatable inputs. */ > diff --git a/ld/NEWS b/ld/NEWS > index 4a19f5a7d5d..5d5fec4aed3 100644 > --- a/ld/NEWS > +++ b/ld/NEWS > @@ -33,6 +33,9 @@ Changes in 2.43: > > * Add -plugin-save-temps to store plugin intermediate files permanently. > > +* Add -z memory-seal/-z nomemory-seal options to ELF linker to mark the > + object to memory sealed. > + > Changes in 2.42: > > * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT > diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em > index 4d431995d2e..9a14eae749e 100644 > --- a/ld/emultempl/elf.em > +++ b/ld/emultempl/elf.em > @@ -1083,6 +1083,10 @@ fragment <<EOF > link_info.combreloc = false; > else if (strcmp (optarg, "nocopyreloc") == 0) > link_info.nocopyreloc = true; > + else if (strcmp (optarg, "memory-seal") == 0) > + link_info.memory_seal = true; > + else if (strcmp (optarg, "nomemory-seal") == 0) > + link_info.memory_seal = false; > EOF > if test -n "$COMMONPAGESIZE"; then > fragment <<EOF > diff --git a/ld/ld.texi b/ld/ld.texi > index da714a20855..d3d9f32d8f3 100644 > --- a/ld/ld.texi > +++ b/ld/ld.texi > @@ -1590,6 +1590,14 @@ Disable relocation overflow check. This can be used to disable > relocation overflow check if there will be no dynamic relocation > overflow at run-time. Supported for x86_64. > > +@item memory-seal > +@item nomemory-seal > +Instruct the executable or shared library that the all PT_LOAD segments > +should be sealed to avoid further manipulation (such as changing the > +protection flags, the segment size, or remove the mapping). > +This is a security hardening that requires system support. This > +generates GNU_PROPERTY_MEMORY_SEAL in .note.gnu.property section > + > @item now > When generating an executable or shared library, mark it to tell the > dynamic linker to resolve all symbols when the program is started, or > diff --git a/ld/lexsup.c b/ld/lexsup.c > index e63c4310c6e..9cf1a9a033b 100644 > --- a/ld/lexsup.c > +++ b/ld/lexsup.c > @@ -2265,6 +2265,10 @@ elf_shlib_list_options (FILE *file) > fprintf (file, _("\ > -z textoff Don't treat DT_TEXTREL in output as error\n")); > } > + fprintf (file, _("\ > + -z memory-seal Mark object be memory sealed\n")); > + fprintf (file, _("\ > + -z nomemory-seal Don't mark oject to be memory sealed (default)\n")); > } > > static void > diff --git a/ld/testsuite/ld-elf/property-seal-1.d b/ld/testsuite/ld-elf/property-seal-1.d > new file mode 100644 > index 00000000000..a0b1feedf31 > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-1.d > @@ -0,0 +1,16 @@ > +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on > +# ET_DYN. > +#source: property-seal-1.s > +#as: --generate-missing-build-notes=no > +#ld: -shared > +#readelf: -n > +#xfail: ![check_shared_lib_support] > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#failif > +#... > +Displaying notes found in: .note.gnu.property > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-1.s b/ld/testsuite/ld-elf/property-seal-1.s > new file mode 100644 > index 00000000000..aa28a3d0516 > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-1.s > @@ -0,0 +1,11 @@ > + .section ".note.gnu.property", "a" > + .p2align ALIGN > + .long 1f - 0f /* name length */ > + .long 3f - 2f /* data length */ > + .long 5 /* note type */ > +0: .asciz "GNU" /* vendor name */ > +1: > + .p2align ALIGN > +2: .long 3 /* pr_type. */ > + .long 0 /* pr_datasz. */ > +3: > diff --git a/ld/testsuite/ld-elf/property-seal-2.d b/ld/testsuite/ld-elf/property-seal-2.d > new file mode 100644 > index 00000000000..ebdaa623e0c > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-2.d > @@ -0,0 +1,17 @@ > +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on > +# ET_DYN. > +#source: empty.s > +#source: property-seal-1.s > +#as: --generate-missing-build-notes=no > +#ld: -shared > +#readelf: -n > +#xfail: ![check_shared_lib_support] > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#failif > +#... > +Displaying notes found in: .note.gnu.property > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-3.d b/ld/testsuite/ld-elf/property-seal-3.d > new file mode 100644 > index 00000000000..969729ee0f4 > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-3.d > @@ -0,0 +1,16 @@ > +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on > +# ET_EXEC. > +#source: property-seal-1.s > +#as: --generate-missing-build-notes=no > +#ld: -e _start > +#warning: .*: warning: cannot find entry symbol .* > +#readelf: -n > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#failif > +#... > +Displaying notes found in: .note.gnu.property > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-4.d b/ld/testsuite/ld-elf/property-seal-4.d > new file mode 100644 > index 00000000000..3dd990dd68a > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-4.d > @@ -0,0 +1,16 @@ > +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on > +# ET_EXEC. > +#source: empty.s > +#source: property-seal-1.s > +#as: --generate-missing-build-notes=no > +#ld: -e _start > +#readelf: -n > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#failif > +#... > +Displaying notes found in: .note.gnu.property > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-5.d b/ld/testsuite/ld-elf/property-seal-5.d > new file mode 100644 > index 00000000000..0b92a8eb6eb > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-5.d > @@ -0,0 +1,15 @@ > +#source: empty.s > +#ld: -shared -z memory-seal > +#readelf: -n > +#xfail: ![check_shared_lib_support] > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#... > +Displaying notes found in: .note.gnu.property > +[ ]+Owner[ ]+Data size[ ]+Description > + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 > + Properties: memory seal > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-6.d b/ld/testsuite/ld-elf/property-seal-6.d > new file mode 100644 > index 00000000000..725911acae7 > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-6.d > @@ -0,0 +1,16 @@ > +#source: empty.s > +#source: property-seal-1.s > +#ld: -shared -z memory-seal > +#readelf: -n > +#xfail: ![check_shared_lib_support] > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#... > +Displaying notes found in: .note.gnu.property > +[ ]+Owner[ ]+Data size[ ]+Description > + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 > + Properties: memory seal > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-7.d b/ld/testsuite/ld-elf/property-seal-7.d > new file mode 100644 > index 00000000000..12339e83ebd > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-7.d > @@ -0,0 +1,14 @@ > +#source: empty.s > +#ld: -z memory-seal > +#readelf: -n > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#... > +Displaying notes found in: .note.gnu.property > +[ ]+Owner[ ]+Data size[ ]+Description > + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 > + Properties: memory seal > +#pass > diff --git a/ld/testsuite/ld-elf/property-seal-8.d b/ld/testsuite/ld-elf/property-seal-8.d > new file mode 100644 > index 00000000000..0c4c4e4907e > --- /dev/null > +++ b/ld/testsuite/ld-elf/property-seal-8.d > @@ -0,0 +1,15 @@ > +#source: empty.s > +#source: property-seal-1.s > +#ld: -z memory-seal > +#readelf: -n > +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* > +# Assembly source file for the HPPA assembler is renamed and modifed by > +# sed. mn10300 has relocations in .note.gnu.property section which > +# elf_parse_notes doesn't support. > + > +#... > +Displaying notes found in: .note.gnu.property > +[ ]+Owner[ ]+Data size[ ]+Description > + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 > + Properties: memory seal > +#pass > -- > 2.43.0 > As the GNU property owner, it looks OK to me. Please apply if there are no objections from other binutils maintainers after a few days. Thanks.
diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c index 61f01bf5380..23634a9d9c9 100644 --- a/bfd/elf-properties.c +++ b/bfd/elf-properties.c @@ -177,6 +177,20 @@ _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note) prop->pr_kind = property_number; goto next; + case GNU_PROPERTY_MEMORY_SEAL: + if (datasz != 0) + { + _bfd_error_handler + (_("warning: %pB: corrupt memory sealing size: 0x%x"), + abfd, datasz); + /* Clear all properties. */ + elf_properties (abfd) = NULL; + return false; + } + prop = _bfd_elf_get_property (abfd, type, datasz); + prop->pr_kind = property_number; + goto next; + default: if ((type >= GNU_PROPERTY_UINT32_AND_LO && type <= GNU_PROPERTY_UINT32_AND_HI) @@ -254,6 +268,7 @@ elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd, /* FALLTHROUGH */ case GNU_PROPERTY_NO_COPY_ON_PROTECTED: + case GNU_PROPERTY_MEMORY_SEAL: /* Return TRUE if APROP is NULL to indicate that BPROP should be added to ABFD. */ return aprop == NULL; @@ -607,6 +622,33 @@ elf_write_gnu_properties (struct bfd_link_info *info, } } +static asection * +_bfd_elf_link_create_gnu_property_sec (struct bfd_link_info *info, bfd *elf_bfd, + unsigned int elfclass) +{ + asection *sec; + + sec = bfd_make_section_with_flags (elf_bfd, + NOTE_GNU_PROPERTY_SECTION_NAME, + (SEC_ALLOC + | SEC_LOAD + | SEC_IN_MEMORY + | SEC_READONLY + | SEC_HAS_CONTENTS + | SEC_DATA)); + if (sec == NULL) + info->callbacks->einfo (_("%F%P: failed to create GNU property section\n")); + + if (!bfd_set_section_alignment (sec, + elfclass == ELFCLASS64 ? 3 : 2)) + info->callbacks->einfo (_("%F%pA: failed to align section\n"), + sec); + + elf_section_type (sec) = SHT_NOTE; + return sec; +} + + /* Set up GNU properties. Return the first relocatable ELF input with GNU properties if found. Otherwise, return NULL. */ @@ -656,23 +698,7 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) /* Support -z indirect-extern-access. */ if (first_pbfd == NULL) { - sec = bfd_make_section_with_flags (elf_bfd, - NOTE_GNU_PROPERTY_SECTION_NAME, - (SEC_ALLOC - | SEC_LOAD - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_HAS_CONTENTS - | SEC_DATA)); - if (sec == NULL) - info->callbacks->einfo (_("%F%P: failed to create GNU property section\n")); - - if (!bfd_set_section_alignment (sec, - elfclass == ELFCLASS64 ? 3 : 2)) - info->callbacks->einfo (_("%F%pA: failed to align section\n"), - sec); - - elf_section_type (sec) = SHT_NOTE; + sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass); first_pbfd = elf_bfd; has_properties = true; } @@ -690,6 +716,31 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS; } + if (elf_bfd != NULL) + { + if (info->memory_seal) + { + /* Support -z no-memory-seal. */ + if (first_pbfd == NULL) + { + sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass); + first_pbfd = elf_bfd; + has_properties = true; + } + + p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_MEMORY_SEAL, 0); + if (p->pr_kind == property_unknown) + { + /* Create GNU_PROPERTY_NO_MEMORY_SEAL. */ + p->u.number = GNU_PROPERTY_MEMORY_SEAL; + p->pr_kind = property_number; + } + } + else + elf_find_and_remove_property (&elf_properties (elf_bfd), + GNU_PROPERTY_MEMORY_SEAL, true); + } + /* Do nothing if there is no .note.gnu.property section. */ if (!has_properties) return NULL; diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 60e81f518a7..7c164e9c131 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -4892,7 +4892,8 @@ _bfd_x86_elf_link_fixup_gnu_properties for (p = *listp; p; p = p->next) { unsigned int type = p->property.pr_type; - if (type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED + if (type == GNU_PROPERTY_MEMORY_SEAL + || type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED || type == GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED || (type >= GNU_PROPERTY_X86_UINT32_AND_LO && type <= GNU_PROPERTY_X86_UINT32_AND_HI) diff --git a/binutils/readelf.c b/binutils/readelf.c index 4f8f879cf91..0f29b65fe30 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -21476,6 +21476,12 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote) printf (_("<corrupt length: %#x> "), datasz); goto next; + case GNU_PROPERTY_MEMORY_SEAL: + printf ("memory seal "); + if (datasz) + printf (_("<corrupt length: %#x> "), datasz); + goto next; + default: if ((type >= GNU_PROPERTY_UINT32_AND_LO && type <= GNU_PROPERTY_UINT32_AND_HI) diff --git a/include/bfdlink.h b/include/bfdlink.h index 85e7da84406..ae451075996 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -429,6 +429,9 @@ struct bfd_link_info /* TRUE if only one read-only, non-code segment should be created. */ unsigned int one_rosegment: 1; + /* TRUE if GNU_PROPERTY_MEMORY_SEAL should be generated. */ + unsigned int memory_seal: 1; + /* Nonzero if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment should be created. 1 for DWARF2 tables, 2 for compact tables. */ unsigned int eh_frame_hdr_type: 2; diff --git a/include/elf/common.h b/include/elf/common.h index 6077db7a8b7..2e2c486bf8d 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -890,6 +890,7 @@ /* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */ #define GNU_PROPERTY_STACK_SIZE 1 #define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2 +#define GNU_PROPERTY_MEMORY_SEAL 3 /* A 4-byte unsigned integer property: A bit is set if it is set in all relocatable inputs. */ diff --git a/ld/NEWS b/ld/NEWS index 4a19f5a7d5d..5d5fec4aed3 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -33,6 +33,9 @@ Changes in 2.43: * Add -plugin-save-temps to store plugin intermediate files permanently. +* Add -z memory-seal/-z nomemory-seal options to ELF linker to mark the + object to memory sealed. + Changes in 2.42: * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em index 4d431995d2e..9a14eae749e 100644 --- a/ld/emultempl/elf.em +++ b/ld/emultempl/elf.em @@ -1083,6 +1083,10 @@ fragment <<EOF link_info.combreloc = false; else if (strcmp (optarg, "nocopyreloc") == 0) link_info.nocopyreloc = true; + else if (strcmp (optarg, "memory-seal") == 0) + link_info.memory_seal = true; + else if (strcmp (optarg, "nomemory-seal") == 0) + link_info.memory_seal = false; EOF if test -n "$COMMONPAGESIZE"; then fragment <<EOF diff --git a/ld/ld.texi b/ld/ld.texi index da714a20855..d3d9f32d8f3 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -1590,6 +1590,14 @@ Disable relocation overflow check. This can be used to disable relocation overflow check if there will be no dynamic relocation overflow at run-time. Supported for x86_64. +@item memory-seal +@item nomemory-seal +Instruct the executable or shared library that the all PT_LOAD segments +should be sealed to avoid further manipulation (such as changing the +protection flags, the segment size, or remove the mapping). +This is a security hardening that requires system support. This +generates GNU_PROPERTY_MEMORY_SEAL in .note.gnu.property section + @item now When generating an executable or shared library, mark it to tell the dynamic linker to resolve all symbols when the program is started, or diff --git a/ld/lexsup.c b/ld/lexsup.c index e63c4310c6e..9cf1a9a033b 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -2265,6 +2265,10 @@ elf_shlib_list_options (FILE *file) fprintf (file, _("\ -z textoff Don't treat DT_TEXTREL in output as error\n")); } + fprintf (file, _("\ + -z memory-seal Mark object be memory sealed\n")); + fprintf (file, _("\ + -z nomemory-seal Don't mark oject to be memory sealed (default)\n")); } static void diff --git a/ld/testsuite/ld-elf/property-seal-1.d b/ld/testsuite/ld-elf/property-seal-1.d new file mode 100644 index 00000000000..a0b1feedf31 --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-1.d @@ -0,0 +1,16 @@ +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on +# ET_DYN. +#source: property-seal-1.s +#as: --generate-missing-build-notes=no +#ld: -shared +#readelf: -n +#xfail: ![check_shared_lib_support] +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#failif +#... +Displaying notes found in: .note.gnu.property +#pass diff --git a/ld/testsuite/ld-elf/property-seal-1.s b/ld/testsuite/ld-elf/property-seal-1.s new file mode 100644 index 00000000000..aa28a3d0516 --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-1.s @@ -0,0 +1,11 @@ + .section ".note.gnu.property", "a" + .p2align ALIGN + .long 1f - 0f /* name length */ + .long 3f - 2f /* data length */ + .long 5 /* note type */ +0: .asciz "GNU" /* vendor name */ +1: + .p2align ALIGN +2: .long 3 /* pr_type. */ + .long 0 /* pr_datasz. */ +3: diff --git a/ld/testsuite/ld-elf/property-seal-2.d b/ld/testsuite/ld-elf/property-seal-2.d new file mode 100644 index 00000000000..ebdaa623e0c --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-2.d @@ -0,0 +1,17 @@ +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on +# ET_DYN. +#source: empty.s +#source: property-seal-1.s +#as: --generate-missing-build-notes=no +#ld: -shared +#readelf: -n +#xfail: ![check_shared_lib_support] +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#failif +#... +Displaying notes found in: .note.gnu.property +#pass diff --git a/ld/testsuite/ld-elf/property-seal-3.d b/ld/testsuite/ld-elf/property-seal-3.d new file mode 100644 index 00000000000..969729ee0f4 --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-3.d @@ -0,0 +1,16 @@ +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on +# ET_EXEC. +#source: property-seal-1.s +#as: --generate-missing-build-notes=no +#ld: -e _start +#warning: .*: warning: cannot find entry symbol .* +#readelf: -n +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#failif +#... +Displaying notes found in: .note.gnu.property +#pass diff --git a/ld/testsuite/ld-elf/property-seal-4.d b/ld/testsuite/ld-elf/property-seal-4.d new file mode 100644 index 00000000000..3dd990dd68a --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-4.d @@ -0,0 +1,16 @@ +# Check if a GNU_PROPERTY_MEMORY_SEAL on a ET_REL is not replicated on +# ET_EXEC. +#source: empty.s +#source: property-seal-1.s +#as: --generate-missing-build-notes=no +#ld: -e _start +#readelf: -n +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#failif +#... +Displaying notes found in: .note.gnu.property +#pass diff --git a/ld/testsuite/ld-elf/property-seal-5.d b/ld/testsuite/ld-elf/property-seal-5.d new file mode 100644 index 00000000000..0b92a8eb6eb --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-5.d @@ -0,0 +1,15 @@ +#source: empty.s +#ld: -shared -z memory-seal +#readelf: -n +#xfail: ![check_shared_lib_support] +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#... +Displaying notes found in: .note.gnu.property +[ ]+Owner[ ]+Data size[ ]+Description + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 + Properties: memory seal +#pass diff --git a/ld/testsuite/ld-elf/property-seal-6.d b/ld/testsuite/ld-elf/property-seal-6.d new file mode 100644 index 00000000000..725911acae7 --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-6.d @@ -0,0 +1,16 @@ +#source: empty.s +#source: property-seal-1.s +#ld: -shared -z memory-seal +#readelf: -n +#xfail: ![check_shared_lib_support] +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#... +Displaying notes found in: .note.gnu.property +[ ]+Owner[ ]+Data size[ ]+Description + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 + Properties: memory seal +#pass diff --git a/ld/testsuite/ld-elf/property-seal-7.d b/ld/testsuite/ld-elf/property-seal-7.d new file mode 100644 index 00000000000..12339e83ebd --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-7.d @@ -0,0 +1,14 @@ +#source: empty.s +#ld: -z memory-seal +#readelf: -n +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#... +Displaying notes found in: .note.gnu.property +[ ]+Owner[ ]+Data size[ ]+Description + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 + Properties: memory seal +#pass diff --git a/ld/testsuite/ld-elf/property-seal-8.d b/ld/testsuite/ld-elf/property-seal-8.d new file mode 100644 index 00000000000..0c4c4e4907e --- /dev/null +++ b/ld/testsuite/ld-elf/property-seal-8.d @@ -0,0 +1,15 @@ +#source: empty.s +#source: property-seal-1.s +#ld: -z memory-seal +#readelf: -n +#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-* +# Assembly source file for the HPPA assembler is renamed and modifed by +# sed. mn10300 has relocations in .note.gnu.property section which +# elf_parse_notes doesn't support. + +#... +Displaying notes found in: .note.gnu.property +[ ]+Owner[ ]+Data size[ ]+Description + GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0 + Properties: memory seal +#pass