teach the BFD tools how to handle NOBTCFI, quite similar to WXNEEDED
authorderaadt <deraadt@openbsd.org>
Thu, 6 Jul 2023 09:52:37 +0000 (09:52 +0000)
committerderaadt <deraadt@openbsd.org>
Thu, 6 Jul 2023 09:52:37 +0000 (09:52 +0000)
ok kettenis

gnu/usr.bin/binutils-2.17/bfd/elf-bfd.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/bfdlink.h
gnu/usr.bin/binutils-2.17/include/elf/common.h
gnu/usr.bin/binutils-2.17/ld/emultempl/elf32.em
gnu/usr.bin/binutils-2.17/ld/ld.texinfo
gnu/usr.bin/binutils-2.17/ld/ldgram.y

index 2abac0e..e4a2f5f 100644 (file)
@@ -1318,6 +1318,9 @@ struct elf_obj_tdata
   /* TRUE if output program should be marked to request W^X permission */
   bfd_boolean wxneeded;
 
+  /* TRUE if output program should be marked to stop branch target CFI enforcement */
+  bfd_boolean nobtcfi;
+
   /* Symbol version definitions in external objects.  */
   Elf_Internal_Verdef *verdef;
 
index a2804f5..6c1454c 100644 (file)
@@ -1102,6 +1102,7 @@ get_segment_type (unsigned int p_type)
     case PT_GNU_RELRO: pt = "RELRO"; break;
     case PT_OPENBSD_RANDOMIZE: pt = "OPENBSD_RANDOMIZE"; break;
     case PT_OPENBSD_WXNEEDED: pt = "OPENBSD_WXNEEDED"; break;
+    case PT_OPENBSD_NOBTCFI: pt = "PT_OPENBSD_NOBTCFI"; break;
     case PT_OPENBSD_BOOTDATA: pt = "OPENBSD_BOOTDATA"; break;
     case PT_OPENBSD_MUTABLE: pt = "OPENBSD_MUTABLE"; break;
     default: pt = NULL; break;
@@ -2646,6 +2647,10 @@ 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_NOBTCFI:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index,
+                                             "openbsd_nobtcfi");
+
     case PT_OPENBSD_MUTABLE:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index,
                                              "openbsd_mutable");
@@ -3988,6 +3993,21 @@ map_sections_to_segments (bfd *abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->nobtcfi)
+    {
+      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_NOBTCFI;
+      m->p_flags = 1;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   /* If there is a .openbsd.randomdata section, throw in a PT_OPENBSD_RANDOMIZE
      segment.  */
   randomdata = bfd_get_section_by_name (abfd, ".openbsd.randomdata");
@@ -4800,6 +4820,12 @@ get_program_header_size (bfd *abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->nobtcfi)
+    {
+      /* We need a PT_OPENBSD_NOBTCFI segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
index a45527f..262a0b3 100644 (file)
@@ -2711,6 +2711,8 @@ get_segment_type (unsigned long p_type)
                        return "OPENBSD_BOOTDATA";
     case PT_OPENBSD_MUTABLE:
                        return "OPENBSD_MUTABLE";
+    case PT_OPENBSD_NOBTCFI:
+                       return "OPENBSD_NOBTCFI";
 
     default:
       if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
index 8c17bf8..15b97b6 100644 (file)
@@ -270,6 +270,9 @@ struct bfd_link_info
   /* TRUE if output program should be marked to request W^X permission */
   unsigned int wxneeded: 1;
 
+  /* TRUE if output program should be marked to stop branch target CFI enforcement */
+  unsigned int nobtcfi: 1;
+
   /* TRUE if ok to have version with no definition.  */
   unsigned int allow_undefined_version: 1;
 
index 9d1c84a..a494372 100644 (file)
 
 #define PT_OPENBSD_RANDOMIZE   0x65a3dbe6 /* Fill with random data. */
 #define PT_OPENBSD_WXNEEDED    0x65a3dbe7 /* Program does W^X violations */
+#define PT_OPENBSD_NOBTCFI     0x65a3dbe8 /* no branch target CFI */
 #define PT_OPENBSD_BOOTDATA    0x65a41be6 /* Section for boot arguments */
 #define PT_OPENBSD_MUTABLE     0x65a3dbe5 /* Like bss, but not immutable */
 
index 6786e60..6d17020 100644 (file)
@@ -2206,6 +2206,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
        link_info.relro = FALSE;
       else if (strcmp (optarg, "wxneeded") == 0)
        link_info.wxneeded = TRUE;
+      else if (strcmp (optarg, "nobtcfi") == 0)
+       link_info.nobtcfi = TRUE;
       else if (strcmp (optarg, "notext") == 0)
        link_info.allow_textrel = TRUE;
       else if (strcmp (optarg, "text") == 0)
index b771b01..d53c4ef 100644 (file)
@@ -1019,6 +1019,11 @@ Marks the executable with a @code{PT_OPENBSD_WXNEEDED} segment header,
 indicating it is expected to perform W^X violating operations later
 (such as calling mprotect(2) or mmap(2) with both PROT_WRITE and PROT_EXEC).
 
+@item nobtcfi
+Marks the executable with a @code{PT_OPENBSD_NOBTCFI} segment header,
+indicating it is expected the binary is missing BTI/IBT instructions and
+thus the system should not enforce them as required.
+
 @end table
 
 Other keywords are ignored for Solaris compatibility.  
index 8692424..5ed2a5f 100644 (file)
@@ -1095,6 +1095,8 @@ phdr_type:
                            $$ = exp_intop (0x65a3dbe6);
                          else if (strcmp (s, "PT_OPENBSD_WXNEEDED") == 0)
                            $$ = exp_intop (0x65a3dbe7);
+                         else if (strcmp (s, "PT_OPENBSD_NOBTCFI") == 0)
+                           $$ = exp_intop (0x65a3dbe8);
                          else if (strcmp (s, "PT_OPENBSD_BOOTDATA") == 0)
                            $$ = exp_intop (0x65a41be6);
                          else if (strcmp (s, "PT_OPENBSD_MUTABLE") == 0)