[PATCH v2 1/3] elf: Add GNU_PROPERTY_MEMORY_SEAL gnu property
H.J. Lu
hjl.tools@gmail.com
Mon Sep 30 20:52:56 GMT 2024
On Tue, Oct 1, 2024 at 4:09 AM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> Along with -Wl,memory-seal/-Wl,nomemory-seal options to ld.bfd.
>
> The new attribute indicates that an ET_EXEC or ET_DYN ELF object should
> be memory-sealed if the loader supports it. Memory sealing is useful as
> a hardening mechanism to avoid either remapping the memory segments or
> changing the memory protection segments layout by the dynamic loader
> (for instance, the RELRO hardening). The Linux 6.10
> (8be7258aad44b5e25977a98db136f677fa6f4370) added the mseal syscall
> accomplishes it.
>
> A GNU property is used instead of a new dynamic section tag (like the
> one proposed for DT_GNU_FLAGS_1) because the memory sealing should be
> selectable for ET_EXEC and not only for ET_DYN. It also fits new opt-in
> security features like x86 CET or AArch64 BTI.
> ---
> bfd/elf-properties.c | 72 ++++++++++++++++++++-------
> 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 | 15 ++++++
> ld/testsuite/ld-elf/property-seal-2.d | 14 ++++++
> 11 files changed, 115 insertions(+), 18 deletions(-)
> create mode 100644 ld/testsuite/ld-elf/property-seal-1.d
> create mode 100644 ld/testsuite/ld-elf/property-seal-2.d
>
> diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c
> index ee8bd37f2bd..17c89d9e876 100644
> --- a/bfd/elf-properties.c
> +++ b/bfd/elf-properties.c
> @@ -177,6 +177,9 @@ _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
> prop->pr_kind = property_number;
> goto next;
>
> + case GNU_PROPERTY_MEMORY_SEAL:
> + goto next;
> +
> default:
> if ((type >= GNU_PROPERTY_UINT32_AND_LO
> && type <= GNU_PROPERTY_UINT32_AND_HI)
> @@ -258,6 +261,9 @@ elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd,
> be added to ABFD. */
> return aprop == NULL;
>
> + case GNU_PROPERTY_MEMORY_SEAL:
> + return aprop == NULL;
> +
> default:
> updated = false;
> if (pr_type >= GNU_PROPERTY_UINT32_OR_LO
> @@ -607,6 +613,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 +689,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 +707,27 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
> |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
> }
>
> + if (info->memory_seal && elf_bfd != NULL)
> + {
> + /* 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
> + p->u.number |= GNU_PROPERTY_MEMORY_SEAL;
> + }
> +
> /* 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 dd951b91f50..8a4405c8a79 100644
> --- a/bfd/elfxx-x86.c
> +++ b/bfd/elfxx-x86.c
> @@ -4815,7 +4815,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 0f8dc1b9716..bf25425bb8d 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -21464,6 +21464,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 f802ec627ef..8b9e391e6ff 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 c9920e7731a..8938e2f4754 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 1f14dd6bc77..4a28592fa32 100644
> --- a/ld/NEWS
> +++ b/ld/NEWS
> @@ -23,6 +23,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 2e865728587..ccd43531237 100644
> --- a/ld/emultempl/elf.em
> +++ b/ld/emultempl/elf.em
> @@ -1075,6 +1075,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 90182c436ec..b8957d3027e 100644
> --- a/ld/ld.texi
> +++ b/ld/ld.texi
> @@ -1591,6 +1591,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 8982073bc91..d82d3631a09 100644
> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -2271,6 +2271,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..0b92a8eb6eb
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/property-seal-1.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-2.d b/ld/testsuite/ld-elf/property-seal-2.d
> new file mode 100644
> index 00000000000..12339e83ebd
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/property-seal-2.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
> --
> 2.34.1
>
Is GNU_PROPERTY_MEMORY_SEAL only generated by linker?
What happens when an input relocatable object file contains
GNU_PROPERTY_MEMORY_SEAL?
--
H.J.
More information about the Binutils
mailing list