From: Adhemerval Zanella Date: Tue, 4 Mar 2025 14:39:30 +0000 (-0300) Subject: elf: Add PT_GNU_MUTABLE X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fazanella%2Fpt_gnu_mutable;p=thirdparty%2Fbinutils-gdb.git elf: Add PT_GNU_MUTABLE The section mark a memory region that should not be sealed if GNU_PROPERTY_MEMORY_SEAL attribute is present. PT_GNU_MUTABLE section names start with ".gnu.mutable" and are maximum page aligned and have a size of maximum page size. For instance the code: unsigned char mutable_array1[64] __attribute__ ((section (GNU_MUTABLE_SECTION_NAME))) = { 0 }; unsigned char mutable_array2[32] __attribute__ ((section (GNU_MUTABLE_SECTION_NAME))) = { 0 }; places both 'mutable_array1' and 'mutable_array2' on a page aligned memory region in a size of a page (the alignment and size can be change with -Wl,-z,max-page-size= linker option). The linker sets the alignment and size to make it easier to loader to avoid sealing the area (since mseal only work on multiple of page size areas), and to simplify the userland process to change protection of either seal the area after initialization. Change-Id: I1304af9ec6b5b2682a1416b2b3d8d5b2c65b9f1c TODO: add tests. --- diff --git a/bfd/elf.c b/bfd/elf.c index 3f8bc838bfb..d3ef9ddd17f 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1434,6 +1434,7 @@ get_segment_type (unsigned int p_type) case PT_GNU_STACK: pt = "STACK"; break; case PT_GNU_RELRO: pt = "RELRO"; break; case PT_GNU_SFRAME: pt = "SFRAME"; break; + case PT_GNU_MUTABLE: pt = "MUTABLE"; break; default: pt = NULL; break; } return pt; @@ -3416,6 +3417,9 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index) return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "sframe"); + case PT_GNU_MUTABLE: + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "mutable"); + default: /* Check for any processor-specific program segment types. */ bed = get_elf_backend_data (abfd); @@ -4766,6 +4770,13 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info) ++segs; } + s = bfd_get_section_by_name (abfd, GNU_MUTABLE_SECTION_NAME); + if (s != NULL) + { + /* We need a PT_GNU_MUTABLE segment. */ + ++segs; + } + s = bfd_get_section_by_name (abfd, NOTE_GNU_PROPERTY_SECTION_NAME); if (s != NULL && s->size != 0) @@ -5032,6 +5043,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, asection *first_mbind = NULL; asection *dynsec, *eh_frame_hdr; asection *sframe; + asection *mutabledata; size_t amt; bfd_vma addr_mask, wrap_to = 0; /* Bytes. */ bfd_size_type phdr_size; /* Octets/bytes. */ @@ -5571,6 +5583,23 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, pm = &m->next; } + mutabledata = bfd_get_section_by_name (abfd, + GNU_MUTABLE_SECTION_NAME); + if (mutabledata != NULL && (mutabledata->flags & SEC_LOAD) != 0) + { + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_MUTABLE; + m->count = 1; + m->sections[0] = mutabledata->output_section; + + *pm = m; + pm = &m->next; + } + if (info != NULL && info->relro) { for (m = mfirst; m != NULL; m = m->next) diff --git a/binutils/readelf.c b/binutils/readelf.c index dd1871d8c75..b1f4d5c1b46 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -5483,6 +5483,7 @@ get_os_specific_segment_type (Filedata * filedata, unsigned long p_type) case PT_GNU_RELRO: return "GNU_RELRO"; case PT_GNU_PROPERTY: return "GNU_PROPERTY"; case PT_GNU_SFRAME: return "GNU_SFRAME"; + case PT_GNU_MUTABLE: return "GNU_MUTABLE"; case PT_OPENBSD_MUTABLE: return "OPENBSD_MUTABLE"; case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE"; diff --git a/include/elf/common.h b/include/elf/common.h index fd032d1e03e..4e68f2ca961 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -511,6 +511,9 @@ #define PT_GNU_MBIND_LO (PT_LOOS + 0x474e555) #define PT_GNU_MBIND_HI (PT_GNU_MBIND_LO + PT_GNU_MBIND_NUM - 1) +/* Memory sealing mutable section */ +#define PT_GNU_MUTABLE (PT_GNU_MBIND_HI + 1) /* Mutable section. */ + #define PT_LOPROC 0x70000000 /* Processor-specific */ #define PT_HIPROC 0x7FFFFFFF /* Processor-specific */ @@ -887,6 +890,7 @@ #define NOTE_GNU_PROPERTY_SECTION_NAME ".note.gnu.property" #define GNU_BUILD_ATTRS_SECTION_NAME ".gnu.build.attributes" +#define GNU_MUTABLE_SECTION_NAME ".gnu.mutable" /* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */ #define GNU_PROPERTY_STACK_SIZE 1 diff --git a/ld/ldgram.y b/ld/ldgram.y index 6635e598562..cbeff7fb0db 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -1312,6 +1312,8 @@ phdr_type: $$ = exp_intop (0x6474e552); else if (strcmp (s, "PT_GNU_PROPERTY") == 0) $$ = exp_intop (0x6474e553); + else if (strcmp (s, "PT_GNU_MUTABLE") == 0) + $$ = exp_intop (0x6474f555); else { einfo (_("\ diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc index be8d19fcf11..5eadc18aa98 100644 --- a/ld/scripttempl/elf.sc +++ b/ld/scripttempl/elf.sc @@ -244,7 +244,7 @@ RELA_IPLT=".rela.iplt ${RELOCATING-0} : DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }" RODATA=".${RODATA_NAME} ${RELOCATING-0} : { *(.${RODATA_NAME}${RELOCATING+ .${RODATA_NAME}.* .gnu.linkonce.r.*}) }" DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }" -DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }" +DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) *(.gnu.mutable) }" if test -z "${NO_SMALL_DATA}"; then SBSS=".${SBSS_NAME} ${RELOCATING-0} : { @@ -855,6 +855,12 @@ cat <