From bd249b5664da50f0178adea78250a7a0d8ea6566 Mon Sep 17 00:00:00 2001 From: deraadt Date: Fri, 7 Oct 2022 15:04:51 +0000 Subject: [PATCH] In the linkers, collect objects in section "openbsd.mutable" and place them into a page-aligned region in the bss, with the right markers for kernel/ld.so to identify the region and skip making it immutable. While here, fix readelf/objdump versions to show all of this. ok miod kettenis --- gnu/llvm/lld/ELF/ScriptParser.cpp | 1 + gnu/llvm/lld/ELF/Writer.cpp | 8 ++++- gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h | 1 + gnu/usr.bin/binutils-2.17/bfd/elf.c | 30 +++++++++++++++++- gnu/usr.bin/binutils-2.17/binutils/readelf.c | 2 ++ .../binutils-2.17/include/elf/common.h | 1 + gnu/usr.bin/binutils-2.17/ld/ldgram.y | 2 ++ gnu/usr.bin/binutils/bfd/elf.c | 31 ++++++++++++++++++- gnu/usr.bin/binutils/binutils/readelf.c | 1 + gnu/usr.bin/binutils/include/elf/common.h | 1 + gnu/usr.bin/binutils/ld/ldgram.y | 2 ++ 11 files changed, 77 insertions(+), 3 deletions(-) diff --git a/gnu/llvm/lld/ELF/ScriptParser.cpp b/gnu/llvm/lld/ELF/ScriptParser.cpp index 1c743fd4774..a9b96e3c361 100644 --- a/gnu/llvm/lld/ELF/ScriptParser.cpp +++ b/gnu/llvm/lld/ELF/ScriptParser.cpp @@ -1478,6 +1478,7 @@ unsigned ScriptParser::readPhdrType() { .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME) .Case("PT_GNU_STACK", PT_GNU_STACK) .Case("PT_GNU_RELRO", PT_GNU_RELRO) + .Case("PT_OPENBSD_MUTABLE", PT_OPENBSD_MUTABLE) .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE) .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED) .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA) diff --git a/gnu/llvm/lld/ELF/Writer.cpp b/gnu/llvm/lld/ELF/Writer.cpp index 9e6692b3709..8b5e4e294e8 100644 --- a/gnu/llvm/lld/ELF/Writer.cpp +++ b/gnu/llvm/lld/ELF/Writer.cpp @@ -146,7 +146,7 @@ StringRef elf::getOutputSectionName(const InputSectionBase *s) { {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab.", - ".openbsd.randomdata."}) + ".openbsd.randomdata.", ".openbsd.mutable." }) if (isSectionPrefix(v, s->name)) return v.drop_back(); @@ -2470,6 +2470,12 @@ std::vector Writer::createPhdrs(Partition &part) { addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) ->add(part.ehFrameHdr->getParent()); + // PT_OPENBSD_MUTABLE is an OpenBSD-specific feature. That makes + // the dynamic linker fill the segment with zero data, like bss, but + // it can be treated differently. + if (OutputSection *cmd = findSection(".openbsd.mutable", partNo)) + addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd); + // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo)) diff --git a/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h b/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h index 6148f968cdb..fa4139b88c2 100644 --- a/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h +++ b/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h @@ -1303,6 +1303,7 @@ enum { PT_GNU_RELRO = 0x6474e552, // Read-only after relocation. PT_GNU_PROPERTY = 0x6474e553, // .note.gnu.property notes sections. + PT_OPENBSD_MUTABLE = 0x65a3dbe5, // Like bss, but not immutable. PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data. PT_OPENBSD_WXNEEDED = 0x65a3dbe7, // Program does W^X violations. PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments. diff --git a/gnu/usr.bin/binutils-2.17/bfd/elf.c b/gnu/usr.bin/binutils-2.17/bfd/elf.c index f8658be09fe..2d2ed030eca 100644 --- a/gnu/usr.bin/binutils-2.17/bfd/elf.c +++ b/gnu/usr.bin/binutils-2.17/bfd/elf.c @@ -1103,6 +1103,7 @@ get_segment_type (unsigned int p_type) case PT_OPENBSD_RANDOMIZE: pt = "OPENBSD_RANDOMIZE"; break; case PT_OPENBSD_WXNEEDED: pt = "OPENBSD_WXNEEDED"; break; case PT_OPENBSD_BOOTDATA: pt = "OPENBSD_BOOTDATA"; break; + case PT_OPENBSD_MUTABLE: pt = "OPENBSD_MUTABLE"; break; default: pt = NULL; break; } return pt; @@ -2645,6 +2646,9 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index) return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "openbsd_wxneeded"); + case PT_OPENBSD_MUTABLE: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, + "openbsd_mutable"); default: /* Check for any processor-specific program segment types. */ bed = get_elf_backend_data (abfd); @@ -3649,7 +3653,7 @@ map_sections_to_segments (bfd *abfd) bfd_boolean writable; int tls_count = 0; asection *first_tls = NULL; - asection *dynsec, *eh_frame_hdr, *randomdata; + asection *dynsec, *eh_frame_hdr, *randomdata, *mutabledata; bfd_size_type amt; if (elf_tdata (abfd)->segment_map != NULL) @@ -4002,6 +4006,24 @@ map_sections_to_segments (bfd *abfd) pm = &m->next; } + /* If there is a .openbsd.mutable section, throw in a PT_OPENBSD_MUTABLE + segment. */ + mutabledata = bfd_get_section_by_name (abfd, ".openbsd.mutable"); + 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_OPENBSD_MUTABLE; + m->count = 1; + m->sections[0] = mutabledata->output_section; + + *pm = m; + pm = &m->next; + } + if (elf_tdata (abfd)->relro) { amt = sizeof (struct elf_segment_map); @@ -4747,6 +4769,12 @@ get_program_header_size (bfd *abfd) ++segs; } + if (bfd_get_section_by_name (abfd, ".openbsd.mutable") != NULL) + { + /* We need a PT_OPENBSD_MUTABLE segment. */ + ++segs; + } + if (elf_tdata (abfd)->eh_frame_hdr) { /* We need a PT_GNU_EH_FRAME segment. */ diff --git a/gnu/usr.bin/binutils-2.17/binutils/readelf.c b/gnu/usr.bin/binutils-2.17/binutils/readelf.c index 716b2768e2e..d0f16f3b6dd 100644 --- a/gnu/usr.bin/binutils-2.17/binutils/readelf.c +++ b/gnu/usr.bin/binutils-2.17/binutils/readelf.c @@ -2708,6 +2708,8 @@ get_segment_type (unsigned long p_type) return "OPENBSD_WXNEEDED"; case PT_OPENBSD_BOOTDATA: return "OPENBSD_BOOTDATA"; + case PT_OPENBSD_MUTABLE: + return "OPENBSD_MUTABLE"; default: if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) diff --git a/gnu/usr.bin/binutils-2.17/include/elf/common.h b/gnu/usr.bin/binutils-2.17/include/elf/common.h index 1e535ef0b2d..8ceb3d21d45 100644 --- a/gnu/usr.bin/binutils-2.17/include/elf/common.h +++ b/gnu/usr.bin/binutils-2.17/include/elf/common.h @@ -313,6 +313,7 @@ #define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* Fill with random data. */ #define PT_OPENBSD_WXNEEDED 0x65a3dbe7 /* Program does W^X violations */ #define PT_OPENBSD_BOOTDATA 0x65a41be6 /* Section for boot arguments */ +#define PT_OPENBSD_MUTABLE 0x65a3dbe5 /* Section for boot arguments */ /* Program segment permissions, in program header p_flags field. */ diff --git a/gnu/usr.bin/binutils-2.17/ld/ldgram.y b/gnu/usr.bin/binutils-2.17/ld/ldgram.y index 33ccd4d60f5..86924249835 100644 --- a/gnu/usr.bin/binutils-2.17/ld/ldgram.y +++ b/gnu/usr.bin/binutils-2.17/ld/ldgram.y @@ -1097,6 +1097,8 @@ phdr_type: $$ = exp_intop (0x65a3dbe7); else if (strcmp (s, "PT_OPENBSD_BOOTDATA") == 0) $$ = exp_intop (0x65a41be6); + else if (strcmp (s, "PT_OPENBSD_MUTABLE") == 0) + $$ = exp_intop (0x65a3dbe5); else { einfo (_("\ diff --git a/gnu/usr.bin/binutils/bfd/elf.c b/gnu/usr.bin/binutils/bfd/elf.c index efef5f9ac74..3eb2ac80833 100644 --- a/gnu/usr.bin/binutils/bfd/elf.c +++ b/gnu/usr.bin/binutils/bfd/elf.c @@ -969,6 +969,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break; case PT_GNU_STACK: pt = "STACK"; break; case PT_OPENBSD_RANDOMIZE: pt = "OPENBSD_RANDOMIZE"; break; + case PT_OPENBSD_MUTABLE: pt = "OPENBSD_MUTABLE"; break; default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break; } fprintf (f, "%8s off 0x", pt); @@ -2296,6 +2297,10 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index) return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "openbsd_randomize"); + case PT_OPENBSD_MUTABLE: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, + "openbsd_mutable"); + default: /* Check for any processor-specific program segment types. If no handler for them, default to making "segment" sections. */ @@ -3199,7 +3204,7 @@ map_sections_to_segments (bfd *abfd) bfd_boolean writable; int tls_count = 0; asection *first_tls = NULL; - asection *dynsec, *eh_frame_hdr, *randomdata; + asection *dynsec, *eh_frame_hdr, *randomdata, *mutabledata; bfd_size_type amt; if (elf_tdata (abfd)->segment_map != NULL) @@ -3544,6 +3549,24 @@ map_sections_to_segments (bfd *abfd) pm = &m->next; } + /* If there is a .openbsd.mutable section, throw in a PT_OPENBSD_MUTABLE + segment. */ + mutabledata = bfd_get_section_by_name (abfd, ".openbsd.mutable"); + 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_OPENBSD_MUTABLE; + m->count = 1; + m->sections[0] = mutabledata->output_section; + + *pm = m; + pm = &m->next; + } + free (sections); sections = NULL; @@ -4169,6 +4192,12 @@ get_program_header_size (bfd *abfd) ++segs; } + if (bfd_get_section_by_name (abfd, ".openbsd.mutable") != NULL) + { + /* We need a PT_OPENBSD_MUTABLE segment. */ + ++segs; + } + if (elf_tdata (abfd)->eh_frame_hdr) { /* We need a PT_GNU_EH_FRAME segment. */ diff --git a/gnu/usr.bin/binutils/binutils/readelf.c b/gnu/usr.bin/binutils/binutils/readelf.c index 12771b2c6aa..fe80b8a4a8b 100644 --- a/gnu/usr.bin/binutils/binutils/readelf.c +++ b/gnu/usr.bin/binutils/binutils/readelf.c @@ -2158,6 +2158,7 @@ get_segment_type (unsigned long p_type) return "GNU_EH_FRAME"; case PT_GNU_STACK: return "STACK"; case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE"; + case PT_OPENBSD_MUTABLE: return "OPENBSD_MUTABLE"; default: if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) diff --git a/gnu/usr.bin/binutils/include/elf/common.h b/gnu/usr.bin/binutils/include/elf/common.h index 5decb810d1e..5b7610fbd04 100644 --- a/gnu/usr.bin/binutils/include/elf/common.h +++ b/gnu/usr.bin/binutils/include/elf/common.h @@ -294,6 +294,7 @@ #define PT_GNU_STACK (PT_LOOS + 0x474e551) #define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 +#define PT_OPENBSD_MUTABLE 0x65a3dbe5 /* Program segment permissions, in program header p_flags field. */ diff --git a/gnu/usr.bin/binutils/ld/ldgram.y b/gnu/usr.bin/binutils/ld/ldgram.y index e83e0e1464a..fabbd7821b3 100644 --- a/gnu/usr.bin/binutils/ld/ldgram.y +++ b/gnu/usr.bin/binutils/ld/ldgram.y @@ -1021,6 +1021,8 @@ phdr_type: $$ = exp_intop (0x6474e551); else if (strcmp (s, "PT_OPENBSD_RANDOMIZE") == 0) $$ = exp_intop (0x65a3dbe6); + else if (strcmp (s, "PT_OPENBSD_MUTABLE") == 0) + $$ = exp_intop (0x65a3dbe5); else { einfo (_("\ -- 2.20.1