In the linkers, collect objects in section "openbsd.mutable" and place
authorderaadt <deraadt@openbsd.org>
Fri, 7 Oct 2022 15:04:51 +0000 (15:04 +0000)
committerderaadt <deraadt@openbsd.org>
Fri, 7 Oct 2022 15:04:51 +0000 (15:04 +0000)
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
gnu/llvm/lld/ELF/Writer.cpp
gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h
gnu/usr.bin/binutils-2.17/bfd/elf.c
gnu/usr.bin/binutils-2.17/binutils/readelf.c
gnu/usr.bin/binutils-2.17/include/elf/common.h
gnu/usr.bin/binutils-2.17/ld/ldgram.y
gnu/usr.bin/binutils/bfd/elf.c
gnu/usr.bin/binutils/binutils/readelf.c
gnu/usr.bin/binutils/include/elf/common.h
gnu/usr.bin/binutils/ld/ldgram.y

index 1c743fd..a9b96e3 100644 (file)
@@ -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)
index 9e6692b..8b5e4e2 100644 (file)
@@ -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<PhdrEntry *> Writer<ELFT>::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))
index 6148f96..fa4139b 100644 (file)
@@ -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.
index f8658be..2d2ed03 100644 (file)
@@ -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.  */
index 716b276..d0f16f3 100644 (file)
@@ -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))
index 1e535ef..8ceb3d2 100644 (file)
 #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.  */
 
index 33ccd4d..8692424 100644 (file)
@@ -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 (_("\
index efef5f9..3eb2ac8 100644 (file)
@@ -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.  */
index 12771b2..fe80b8a 100644 (file)
@@ -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))
index 5decb81..5b7610f 100644 (file)
 #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.  */
index e83e0e1..fabbd78 100644 (file)
@@ -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 (_("\