Theo de Raadt <[email protected]> wrote:

> Theo de Raadt <[email protected]> wrote:
> 
> > > Yet another version of the diff as I incrementally get it working better.
> > > Call it version 22..
> 
> This is around version 30.

New version.

uvm_unmap_remove() now avoids doing entry splits as it scans for immutables
in the region.

Lots of // debug code remains, because there is a hunt for a linker bug;
some libraries are created subtly incorrectly, and it would be better if
they were correct and we could rip out some workarounds.

Index: gnu/llvm/lld/ELF/ScriptParser.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/ScriptParser.cpp,v
retrieving revision 1.1.1.4
diff -u -p -u -r1.1.1.4 ScriptParser.cpp
--- gnu/llvm/lld/ELF/ScriptParser.cpp   17 Dec 2021 12:25:02 -0000      1.1.1.4
+++ gnu/llvm/lld/ELF/ScriptParser.cpp   17 Sep 2022 13:11:25 -0000
@@ -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: gnu/llvm/lld/ELF/Writer.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Writer.cpp,v
retrieving revision 1.3
diff -u -p -u -r1.3 Writer.cpp
--- gnu/llvm/lld/ELF/Writer.cpp 17 Dec 2021 14:46:47 -0000      1.3
+++ gnu/llvm/lld/ELF/Writer.cpp 17 Sep 2022 13:11:25 -0000
@@ -146,7 +146,7 @@ StringRef elf::getOutputSectionName(cons
        {".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();
 
@@ -2469,6 +2469,12 @@ std::vector<PhdrEntry *> Writer<ELFT>::c
       part.ehFrame->getParent() && part.ehFrameHdr->getParent())
     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.
Index: gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h
===================================================================
RCS file: /cvs/src/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h,v
retrieving revision 1.1.1.3
diff -u -p -u -r1.1.1.3 ELF.h
--- gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h       17 Dec 2021 12:23:22 
-0000      1.1.1.3
+++ gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h       17 Sep 2022 13:11:25 
-0000
@@ -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: gnu/usr.bin/binutils/bfd/elf.c
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils/bfd/elf.c,v
retrieving revision 1.23
diff -u -p -u -r1.23 elf.c
--- gnu/usr.bin/binutils/bfd/elf.c      13 Jan 2015 20:05:01 -0000      1.23
+++ gnu/usr.bin/binutils/bfd/elf.c      17 Sep 2022 13:11:25 -0000
@@ -969,6 +969,7 @@ _bfd_elf_print_private_bfd_data (bfd *ab
            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_In
       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;
 
@@ -4166,6 +4189,12 @@ get_program_header_size (bfd *abfd)
   if (bfd_get_section_by_name (abfd, ".openbsd.randomdata") != NULL)
     {
       /* We need a PT_OPENBSD_RANDOMIZE segment.  */
+      ++segs;
+    }
+
+  if (bfd_get_section_by_name (abfd, ".openbsd.mutable") != NULL)
+    {
+      /* We need a PT_OPENBSD_MUTABLE segment.  */
       ++segs;
     }
 
Index: gnu/usr.bin/binutils/binutils/readelf.c
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils/binutils/readelf.c,v
retrieving revision 1.13
diff -u -p -u -r1.13 readelf.c
--- gnu/usr.bin/binutils/binutils/readelf.c     11 Dec 2018 17:09:07 -0000      
1.13
+++ gnu/usr.bin/binutils/binutils/readelf.c     17 Sep 2022 13:11:25 -0000
@@ -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: gnu/usr.bin/binutils/include/elf/common.h
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils/include/elf/common.h,v
retrieving revision 1.12
diff -u -p -u -r1.12 common.h
--- gnu/usr.bin/binutils/include/elf/common.h   11 Dec 2018 17:09:07 -0000      
1.12
+++ gnu/usr.bin/binutils/include/elf/common.h   17 Sep 2022 13:11:25 -0000
@@ -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.  */
Index: gnu/usr.bin/binutils/ld/ldgram.y
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils/ld/ldgram.y,v
retrieving revision 1.8
diff -u -p -u -r1.8 ldgram.y
--- gnu/usr.bin/binutils/ld/ldgram.y    30 Dec 2013 10:30:00 -0000      1.8
+++ gnu/usr.bin/binutils/ld/ldgram.y    17 Sep 2022 13:11:25 -0000
@@ -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 (_("\
Index: gnu/usr.bin/binutils-2.17/bfd/elf.c
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/bfd/elf.c,v
retrieving revision 1.18
diff -u -p -u -r1.18 elf.c
--- gnu/usr.bin/binutils-2.17/bfd/elf.c 12 Nov 2021 22:23:40 -0000      1.18
+++ gnu/usr.bin/binutils-2.17/bfd/elf.c 17 Sep 2022 13:11:25 -0000
@@ -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_In
       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);
@@ -4744,6 +4766,12 @@ get_program_header_size (bfd *abfd)
   if (bfd_get_section_by_name (abfd, ".openbsd.randomdata") != NULL)
     {
       /* We need a PT_OPENBSD_RANDOMIZE segment.  */
+      ++segs;
+    }
+
+  if (bfd_get_section_by_name (abfd, ".openbsd.mutable") != NULL)
+    {
+      /* We need a PT_OPENBSD_MUTABLE segment.  */
       ++segs;
     }
 
Index: gnu/usr.bin/binutils-2.17/binutils/readelf.c
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/binutils/readelf.c,v
retrieving revision 1.25
diff -u -p -u -r1.25 readelf.c
--- gnu/usr.bin/binutils-2.17/binutils/readelf.c        25 Dec 2021 01:25:51 
-0000      1.25
+++ gnu/usr.bin/binutils-2.17/binutils/readelf.c        17 Sep 2022 13:11:25 
-0000
@@ -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: gnu/usr.bin/binutils-2.17/include/elf/common.h
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/include/elf/common.h,v
retrieving revision 1.14
diff -u -p -u -r1.14 common.h
--- gnu/usr.bin/binutils-2.17/include/elf/common.h      25 Dec 2021 01:25:51 
-0000      1.14
+++ gnu/usr.bin/binutils-2.17/include/elf/common.h      17 Sep 2022 13:11:25 
-0000
@@ -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.  */
 
Index: gnu/usr.bin/binutils-2.17/ld/ldgram.y
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/ldgram.y,v
retrieving revision 1.6
diff -u -p -u -r1.6 ldgram.y
--- gnu/usr.bin/binutils-2.17/ld/ldgram.y       10 Aug 2016 20:46:08 -0000      
1.6
+++ gnu/usr.bin/binutils-2.17/ld/ldgram.y       17 Sep 2022 13:11:25 -0000
@@ -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: lib/csu/boot.h
===================================================================
RCS file: /cvs/src/lib/csu/boot.h,v
retrieving revision 1.33
diff -u -p -u -r1.33 boot.h
--- lib/csu/boot.h      12 Jan 2022 21:41:06 -0000      1.33
+++ lib/csu/boot.h      17 Sep 2022 13:11:25 -0000
@@ -35,7 +35,6 @@
 #define        _DYN_LOADER
 
 #include <sys/exec_elf.h>
-#include <sys/mman.h>
 
 #include <machine/reloc.h>
 
@@ -50,6 +49,7 @@ void _dl_exit(int);
  */
 #define REDIRECT_SYSCALL(x)    typeof(x) x asm("_libc_"#x) __dso_hidden
 REDIRECT_SYSCALL(mprotect);
+REDIRECT_SYSCALL(mimmutable);
 
 #if RELOC_TAG == DT_RELA
 typedef        Elf_RelA        RELOC_TYPE;
@@ -63,8 +63,10 @@ static void *relro_addr;
 static size_t relro_size;
 #define RCRT0_RELRO()                                                  \
        do {                                                            \
-               if (relro_addr != NULL && relro_size != 0)              \
+               if (relro_addr != NULL && relro_size != 0) {            \
                        mprotect(relro_addr, relro_size, PROT_READ);    \
+                       mimmutable(relro_addr, relro_size);             \
+               }                                                       \
        } while (0)
 
 /*
Index: lib/csu/crt0.c
===================================================================
RCS file: /cvs/src/lib/csu/crt0.c,v
retrieving revision 1.17
diff -u -p -u -r1.17 crt0.c
--- lib/csu/crt0.c      12 Jan 2022 21:41:06 -0000      1.17
+++ lib/csu/crt0.c      17 Sep 2022 13:11:25 -0000
@@ -32,6 +32,7 @@
  */
 
 #include <sys/syscall.h>
+#include <sys/mman.h>
 #include <stdlib.h>
 #include <limits.h>
 
Index: lib/libc/Symbols.list
===================================================================
RCS file: /cvs/src/lib/libc/Symbols.list,v
retrieving revision 1.76
diff -u -p -u -r1.76 Symbols.list
--- lib/libc/Symbols.list       9 Sep 2022 13:52:59 -0000       1.76
+++ lib/libc/Symbols.list       17 Sep 2022 13:11:25 -0000
@@ -131,6 +131,7 @@ _thread_sys_lseek
 _thread_sys_lstat
 _thread_sys_madvise
 _thread_sys_minherit
+_thread_sys_mimmutable
 _thread_sys_mkdir
 _thread_sys_mkdirat
 _thread_sys_mkfifo
@@ -327,6 +328,7 @@ listen
 lseek
 lstat
 madvise
+mimmutable
 minherit
 mkdir
 mkdirat
Index: lib/libc/hidden/sys/mman.h
===================================================================
RCS file: /cvs/src/lib/libc/hidden/sys/mman.h,v
retrieving revision 1.4
diff -u -p -u -r1.4 mman.h
--- lib/libc/hidden/sys/mman.h  11 Jan 2019 18:46:30 -0000      1.4
+++ lib/libc/hidden/sys/mman.h  17 Sep 2022 13:11:25 -0000
@@ -26,6 +26,7 @@ PROTO_NORMAL(mlock);
 PROTO_NORMAL(mlockall);
 PROTO_NORMAL(mmap);
 PROTO_NORMAL(mprotect);
+PROTO_NORMAL(mimmutable);
 PROTO_NORMAL(mquery);
 PROTO_CANCEL(msync);
 PROTO_NORMAL(munlock);
Index: lib/libc/stdlib/malloc.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/malloc.c,v
retrieving revision 1.274
diff -u -p -u -r1.274 malloc.c
--- lib/libc/stdlib/malloc.c    30 Jun 2022 17:15:48 -0000      1.274
+++ lib/libc/stdlib/malloc.c    17 Sep 2022 13:11:25 -0000
@@ -228,7 +228,8 @@ struct malloc_readonly {
 static union {
        struct malloc_readonly mopts;
        u_char _pad[MALLOC_PAGESIZE];
-} malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE)));
+} malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE)))
+               __attribute__((section(".openbsd.mutable")));
 #define mopts  malloc_readonly.mopts
 
 char           *malloc_options;        /* compile-time options */
Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /cvs/src/lib/libc/sys/Makefile.inc,v
retrieving revision 1.164
diff -u -p -u -r1.164 Makefile.inc
--- lib/libc/sys/Makefile.inc   9 Sep 2022 13:52:59 -0000       1.164
+++ lib/libc/sys/Makefile.inc   17 Sep 2022 13:11:25 -0000
@@ -58,7 +58,7 @@ ASM=  __semctl.o __syscall.o __thrsigdive
        getsockopt.o ioctl.o \
        kevent.o kill.o kqueue.o ktrace.o lchown.o \
        link.o linkat.o listen.o lseek.o lstat.o \
-       madvise.o minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \
+       madvise.o mimmutable.o minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o 
\
        mknod.o mknodat.o mlock.o mlockall.o mmap.o mount.o mprotect.o \
        mquery.o msgctl.o msgget.o munlock.o munlockall.o munmap.o \
        nfssvc.o \
@@ -186,7 +186,7 @@ MAN+=       __get_tcb.2 __thrsigdivert.2 __thr
        getrtable.2 getrusage.2 getsid.2 getsockname.2 getsockopt.2 \
        getthrid.2 gettimeofday.2 getuid.2 intro.2 ioctl.2 issetugid.2 \
        kbind.2 kill.2 kqueue.2 ktrace.2 link.2 listen.2 lseek.2 madvise.2 \
-       minherit.2 mkdir.2 mkfifo.2 mknod.2 mlock.2 \
+       mimmutable.2 minherit.2 mkdir.2 mkfifo.2 mknod.2 mlock.2 \
        mlockall.2 mmap.2 mount.2 mprotect.2 mquery.2 msyscall.2 msgctl.2 \
        msgget.2 msgrcv.2 msgsnd.2 msync.2 munmap.2 nanosleep.2 \
        nfssvc.2 open.2 pathconf.2 pipe.2 pledge.2 poll.2 profil.2 \
Index: lib/libc/sys/mimmutable.2
===================================================================
RCS file: lib/libc/sys/mimmutable.2
diff -N lib/libc/sys/mimmutable.2
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/libc/sys/mimmutable.2   17 Sep 2022 13:11:25 -0000
@@ -0,0 +1,83 @@
+.\"    $OpenBSD: mimmutable.2,v 1.16 2019/01/11 18:46:30 deraadt Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    @(#)mimmutable.2        8.1 (Berkeley) 6/9/93
+.\"
+.Dd $Mdocdate: January 11 2019 $
+.Dt MIMMUTABLE 2
+.Os
+.Sh NAME
+.Nm mimmutable
+.Nd control the immutability of pages
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn mimmutable "void *addr" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn mimmutable
+system call
+changes currently mapped pages in the region to be marked immutable,
+which means their protection or mapping may not be changed in the future.
+.Xr mmap 2 ,
+.Xr mprotect 2 ,
+and
+.Xr munmap 2
+to pages marked immutable will return with error
+.Er EPERM .
+.Pp
+Unmapped pages in the region do not retain immutability, but this
+behaviour should not be relied upon.
+.Pp
+Not all implementations will guarantee that the immutable characteristic
+can be set on a page basis;
+the granularity of changes may be as large as an entire region.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn mimmutable
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The virtual address range specified by the
+.Fa addr
+and
+.Fa len
+arguments is not valid.
+.El
+.Sh SEE ALSO
+.Xr mmap 2 ,
+.Xr mprotect 2 ,
+.Xr munmap 2
+.Sh HISTORY
+The
+.Fn mimmutable
+function first appeared in
+.Ox 7.3 .
Index: lib/libc/sys/mmap.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/mmap.2,v
retrieving revision 1.68
diff -u -p -u -r1.68 mmap.2
--- lib/libc/sys/mmap.2 31 Mar 2022 17:27:16 -0000      1.68
+++ lib/libc/sys/mmap.2 17 Sep 2022 13:11:25 -0000
@@ -300,6 +300,13 @@ and the process is link-time tagged with
 in
 .Xr sysctl 2
 for a method to diagnose failure).
+.It Bq Er EPERM
+The
+.Fa addr
+and
+.Fa len
+parameters
+specify a region which contains at least one page marked immutable.
 .El
 .Sh SEE ALSO
 .Xr madvise 2 ,
Index: lib/libc/sys/mprotect.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/mprotect.2,v
retrieving revision 1.26
diff -u -p -u -r1.26 mprotect.2
--- lib/libc/sys/mprotect.2     30 Jun 2021 18:46:49 -0000      1.26
+++ lib/libc/sys/mprotect.2     17 Sep 2022 13:11:25 -0000
@@ -111,6 +111,13 @@ for more information).
 The
 .Fa prot
 argument is invalid or the specified address range would wrap around.
+.It Bq Er EPERM
+The
+.Fa addr
+and
+.Fa len
+parameters
+specify a region which contains at least one page marked immutable.
 .El
 .Sh SEE ALSO
 .Xr madvise 2 ,
Index: lib/libc/sys/munmap.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/munmap.2,v
retrieving revision 1.19
diff -u -p -u -r1.19 munmap.2
--- lib/libc/sys/munmap.2       21 Dec 2019 05:23:38 -0000      1.19
+++ lib/libc/sys/munmap.2       17 Sep 2022 13:11:25 -0000
@@ -62,6 +62,13 @@ parameters
 specify a region that would extend beyond the end of the address space,
 or some part of the region being unmapped is not part of the currently
 valid address space.
+.It Bq Er EPERM
+The
+.Fa addr
+and
+.Fa len
+parameters
+specify a region which contains at least one page marked immutable.
 .El
 .Sh SEE ALSO
 .Xr madvise 2 ,
Index: libexec/ld.so/Makefile
===================================================================
RCS file: /cvs/src/libexec/ld.so/Makefile,v
retrieving revision 1.82
diff -u -p -u -r1.82 Makefile
--- libexec/ld.so/Makefile      23 Dec 2021 18:50:32 -0000      1.82
+++ libexec/ld.so/Makefile      17 Sep 2022 13:11:25 -0000
@@ -28,8 +28,8 @@ SRCS+=        dl_uname.c dl_dirname.c strlcat.c
 SRCS+= malloc.c reallocarray.c tib.c ffs.c
 
 syscall=close exit fstat getdents getentropy getthrid issetugid kbind \
-       mmap mprotect munmap msyscall open pledge read __realpath sendsyslog \
-       __set_tcb sysctl thrkill utrace write
+       mimmutable mmap mprotect munmap msyscall open pledge read \
+       __realpath sendsyslog __set_tcb sysctl thrkill utrace write
 
 .if (${MACHINE_ARCH} == "i386")
 syscall+=mquery
Index: libexec/ld.so/library.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library.c,v
retrieving revision 1.87
diff -u -p -u -r1.87 library.c
--- libexec/ld.so/library.c     20 Aug 2022 14:11:31 -0000      1.87
+++ libexec/ld.so/library.c     17 Sep 2022 13:11:25 -0000
@@ -328,6 +328,40 @@ _dl_tryload_shlib(const char *libname, i
                                _dl_printf("msyscall %lx %lx error\n",
                                    exec_start, exec_size);
                }
+
+               /* Queue all LOAD sections to become immutable, but subtract
+                * the regions which cannot be immutable.  This includes the
+                * specifically marked PT_OPENBSD_MUTABLE, and PT_GNU_RELRO
+                * (which programs mark immutable when protecting later)
+                */
+               if (type == OBJTYPE_LIB &&
+                   ((object->obj_flags & (DF_1_INITFIRST | DF_1_NODELETE)))) {
+                       phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
+                       for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
+                               char *  start = (char *)TRUNC_PG(phdp->p_vaddr);
+                               Elf_Addr size = ROUND_PG(phdp->p_memsz);
+
+                               switch (phdp->p_type) {
+                               case PT_LOAD:
+                                       _dl_defer_immutable(object,
+                                           start, size, "LOAD");
+                                       break;
+                               case PT_OPENBSD_RANDOMIZE:
+                                       _dl_defer_immutable(object,
+                                           start, size, "RANDOM");
+                                       break;
+                               case PT_OPENBSD_MUTABLE:
+                                       _dl_defer_mutable(object,
+                                           start, size, "malloc");
+                                       break;
+                               case PT_GNU_RELRO:
+                                       _dl_defer_mutable(object,
+                                           start, size, "relro");
+                                       break;
+                               }
+                       }
+               }
+//             _dl_apply_immutable(object, loff);
        } else {
                _dl_munmap((void *)libaddr, maxva - minva);
                _dl_load_list_free(load_list);
Index: libexec/ld.so/library_mquery.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library_mquery.c,v
retrieving revision 1.67
diff -u -p -u -r1.67 library_mquery.c
--- libexec/ld.so/library_mquery.c      20 Aug 2022 14:11:31 -0000      1.67
+++ libexec/ld.so/library_mquery.c      17 Sep 2022 13:11:25 -0000
@@ -336,6 +336,41 @@ retry:
                                _dl_printf("msyscall %lx %lx error\n",
                                    exec_start, exec_size);
                }
+
+               /* Queue all LOAD sections to become immutable, but subtract
+                * the regions which cannot be immutable.  This includes the
+                * specifically marked PT_OPENBSD_MUTABLE, and PT_GNU_RELRO
+                * (which programs mark immutable when protecting later)
+                */
+               if (type == OBJTYPE_LIB &&
+                   ((object->obj_flags & (DF_1_INITFIRST | DF_1_NODELETE)))) {
+                       phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
+                       for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
+                               char *  start = (char *)TRUNC_PG(phdp->p_vaddr);
+                               Elf_Addr size = ROUND_PG(phdp->p_memsz);
+
+                               switch (phdp->p_type) {
+                               case PT_LOAD:
+                                       _dl_defer_immutable(object,
+                                           start, size, "LOAD");
+                                       break;
+                               case PT_OPENBSD_RANDOMIZE:
+                                       _dl_defer_immutable(object,
+                                           start, size, "RANDOM");
+                                       break;
+                               case PT_OPENBSD_MUTABLE:
+                                       _dl_defer_mutable(object,
+                                           start, size, "malloc");
+                                       break;
+                               case PT_GNU_RELRO:
+                                       _dl_defer_mutable(object,
+                                           start, size, "relro");
+                                       break;
+                               }
+                       }
+               }
+//             _dl_apply_immutable(object, loff);
+
        } else {
                _dl_load_list_free(lowld);
        }
Index: libexec/ld.so/loader.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/loader.c,v
retrieving revision 1.195
diff -u -p -u -r1.195 loader.c
--- libexec/ld.so/loader.c      8 Jan 2022 06:49:41 -0000       1.195
+++ libexec/ld.so/loader.c      17 Sep 2022 13:11:25 -0000
@@ -375,7 +375,7 @@ _dl_load_dep_libs(elf_object_t *object, 
                                DL_DEB(("loading: %s required by %s\n", libname,
                                    dynobj->load_name));
                                depobj = _dl_load_shlib(libname, dynobj,
-                                   OBJTYPE_LIB, depflags);
+                                   OBJTYPE_LIB, depflags | DF_1_NODELETE);
                                if (depobj == 0) {
                                        if (booting) {
                                                _dl_die(
@@ -432,12 +432,13 @@ _dl_self_relro(long loff)
                case PT_GNU_RELRO:
                        _dl_mprotect((void *)(phdp->p_vaddr + loff),
                            phdp->p_memsz, PROT_READ);
+                       _dl_mimmutable((void *)(phdp->p_vaddr + loff),
+                           phdp->p_memsz);
                        break;
                }
        }
 }
 
-
 #define PFLAGS(X) ((((X) & PF_R) ? PROT_READ : 0) | \
                   (((X) & PF_W) ? PROT_WRITE : 0) | \
                   (((X) & PF_X) ? PROT_EXEC : 0))
@@ -785,9 +786,16 @@ _dl_relro(elf_object_t *object)
        if (object->relro_addr != 0 && object->relro_size != 0) {
                Elf_Addr addr = object->relro_addr;
 
-               DL_DEB(("protect RELRO [0x%lx,0x%lx) in %s\n",
-                   addr, addr + object->relro_size, object->load_name));
+//             _dl_printf("protect RELRO [0x%lx,0x%lx) in %s\n",
+//                 addr, addr + object->relro_size, object->load_name);
                _dl_mprotect((void *)addr, object->relro_size, PROT_READ);
+
+               /* if library will never be unloaded, immutable is OK */
+               if ((object->obj_flags & DF_1_NODELETE)) {
+//                     _dl_printf("immutable RELRO %s %p-%p %x\n", 
object->load_name,
+//                         addr, addr + object->relro_size, 
object->relro_size);
+                       _dl_mimmutable((void *)addr, object->relro_size);
+               }
        }
 }
 
@@ -812,8 +820,10 @@ _dl_call_init_recurse(elf_object_t *obje
        if (initfirst && (object->obj_flags & DF_1_INITFIRST) == 0)
                return;
 
-       if (!initfirst)
+       if (!initfirst) {
                _dl_relro(object);
+               _dl_apply_immutable(object, object->obj_base);
+       }
 
        if (object->dyn.init) {
                DL_DEB(("doing ctors obj %p @%p: [%s]\n",
@@ -832,8 +842,10 @@ _dl_call_init_recurse(elf_object_t *obje
                            environ, &_dl_cb_cb);
        }
 
-       if (initfirst)
+       if (initfirst) {
                _dl_relro(object);
+               _dl_apply_immutable(object, object->obj_base);
+       }
 
        object->status |= STAT_INIT_DONE;
 }
@@ -980,3 +992,109 @@ _dl_rreloc(elf_object_t *object)
        }
 }
 
+void
+_dl_defer_immutable(elf_object_t *object, void *start, size_t len, char *name)
+{
+       struct mutate *m;
+       int i;
+
+       for (i = 0; i < MAXMUT; i++) {
+               m = &object->imut[i];
+               if (m->valid == 0) {
+//                     _dl_printf("imut\t%x-%x %s\n", start, start + len, 
name);
+                       m->start = (vaddr_t)start;
+                       m->end = (vaddr_t)start + len;
+                       m->name = name;
+                       m->valid = 1;
+                       break;
+               }
+       }
+}
+
+void
+_dl_defer_mutable(elf_object_t *object, void *start, size_t len, char *name)
+{
+       struct mutate *m;
+       int i;
+
+       for (i = 0; i < MAXMUT; i++) {
+               m = &object->mut[i];
+               if (m->valid == 0) {
+//                     _dl_printf(" mut\t%x-%x %s\n", start, start + len, 
name);
+                       m->start = (vaddr_t)start;
+                       m->end = (vaddr_t)start + len;
+                       m->name = name;
+                       m->valid = 1;
+                       break;
+               }
+       }
+}
+
+void
+_dl_apply_immutable(elf_object_t *object, Elf_Addr loff)
+{
+       struct mutate *m, *im, *imtail;
+       int mut, imut;
+       
+       imtail = &object->imut[MAXMUT - 1];
+
+       for (imut = 0; imut < MAXMUT; imut++) {
+               im = &object->imut[imut];
+               if (im->valid == 0)
+                       continue;
+
+               for (mut = 0; mut < MAXMUT; mut++) {
+                       m = &object->mut[mut];
+                       if (m->valid == 0)
+                               continue;
+//                     _dl_printf("try %d-%s %x-%x from %d-%s %x-%x: ",
+//                         mut, m->name, m->start, m->end,
+//                         imut, im->name, im->start, im->end);
+                       if (m->start <= im->start) {
+                               if (m->end < im->start) {
+//                                     _dl_printf(" before ignored");
+                                       ;
+                               } else if (m->end >= im->end) {
+                                       im->start = im->end = im->valid = 0;
+//                                     _dl_printf(" whole: %x-%x", im->start, 
im->end);
+                               } else {
+//                                     _dl_printf(" early: %x-%x", im->start, 
im->end);
+                                       im->start = m->end;
+                               }
+                       } else if (m->start > im->start) {
+                               if (m->end >= im->end) {
+//                                     _dl_printf(" after ignored");
+                                       ;
+                               } else if (m->end < im->end) {
+                                       imtail->start = im->start;
+                                       imtail->end = m->start;
+                                       imtail->valid = 1;
+                                       imtail->name = "split1";
+                                       imtail--;
+                                       imtail->start = m->end;
+                                       imtail->end = im->end;
+                                       imtail->valid = 1;
+                                       imtail->name = "split2";
+                                       imtail--;
+                                       im->start = im->end = im->valid = 0;
+//                                     _dl_printf(" split %x-%x %x-%x",
+//                                         imtail[1].start, imtail[1].end,
+//                                         imtail[2].start, imtail[2].end);
+                               }
+                       }
+//                     _dl_printf("\n");
+               }
+       }
+
+       /* and now, install immutability for objects */
+       for (imut = 0; imut < MAXMUT; imut++) {
+               im = &object->imut[imut];
+               if (im->valid == 0)
+                       continue;
+//             _dl_printf("IMUT %lx-%lx %s (%lx,%lx) [%lx,%lx]\n",
+//                 im->start, im->end, object->load_name,
+//                 (void *)im->start + loff, (void *)im->end + loff,
+//                 (void *)im->start + loff, im->end - im->start);
+               _dl_mimmutable((void *)im->start + loff, im->end - im->start);
+       }
+}
Index: libexec/ld.so/resolve.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.h,v
retrieving revision 1.101
diff -u -p -u -r1.101 resolve.h
--- libexec/ld.so/resolve.h     20 Aug 2022 14:11:31 -0000      1.101
+++ libexec/ld.so/resolve.h     17 Sep 2022 13:11:25 -0000
@@ -77,6 +77,13 @@ struct object_vector {
 };
 void   object_vec_grow(struct object_vector *_vec, int _more);
 
+struct mutate {
+       vaddr_t start;
+       vaddr_t end;
+       char *name;
+       int valid;
+};
+
 /*
  *  Structure describing a loaded object.
  *  The head of this struct must be compatible
@@ -231,6 +238,10 @@ struct elf_object {
 
        /* nonzero if trace enabled for this object */
        int traced;
+
+#define MAXMUT 20
+       struct mutate imut[MAXMUT];
+       struct mutate mut[MAXMUT];
 };
 
 struct dep_node {
@@ -315,6 +326,10 @@ void _dl_run_all_dtors(void);
 int    _dl_match_file(struct sod *sodp, const char *name, int namelen);
 char   *_dl_find_shlib(struct sod *sodp, char **searchpath, int nohints);
 void   _dl_load_list_free(struct load_list *load_list);
+
+void _dl_defer_mutable(elf_object_t *object, void *start, size_t len, char 
*name);
+void _dl_defer_immutable(elf_object_t *object, void *start, size_t len, char 
*name);
+void _dl_apply_immutable(elf_object_t *object, Elf_Addr loff);
 
 typedef void lock_cb(int);
 void   _dl_thread_kern_go(lock_cb *);
Index: libexec/ld.so/sod.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/sod.c,v
retrieving revision 1.36
diff -u -p -u -r1.36 sod.c
--- libexec/ld.so/sod.c 8 Jan 2022 06:49:41 -0000       1.36
+++ libexec/ld.so/sod.c 17 Sep 2022 13:11:25 -0000
@@ -186,6 +186,8 @@ _dl_maphints(void)
        if (hheader->hh_version >= LD_HINTS_VERSION_2)
                _dl_hint_search_path = _dl_split_path(hstrtab + 
hheader->hh_dirlist);
 
+       _dl_mimmutable(addr, hsize);
+
        /* close the file descriptor, leaving the hints mapped */
        _dl_close(hfd);
 
Index: libexec/ld.so/syscall.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/syscall.h,v
retrieving revision 1.2
diff -u -p -u -r1.2 syscall.h
--- libexec/ld.so/syscall.h     8 Jan 2022 06:49:41 -0000       1.2
+++ libexec/ld.so/syscall.h     17 Sep 2022 13:11:25 -0000
@@ -52,6 +52,7 @@ int   _dl_mprotect(const void *, size_t, i
 void   *_dl_mquery(void *, size_t, int, int, int, off_t);
 int    _dl_msyscall(void *addr, size_t len);
 int    _dl_munmap(const void *, size_t);
+int    _dl_mimmutable(const void *, size_t);
 int    _dl_open(const char *, int);
 int    _dl_pledge(const char *, const char **);
 ssize_t        _dl_read(int, const char *, size_t);
Index: libexec/ld.so/aarch64/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/aarch64/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/aarch64/ld.script     10 May 2019 13:29:21 -0000      1.1
+++ libexec/ld.so/aarch64/ld.script     17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -28,7 +29,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text
+    } :btext
 
     /* RELRO DATA */
     . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
@@ -62,6 +63,7 @@ SECTIONS
     /* DATA */
     . = ALIGN(0x1000);
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x1000);
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
 
Index: libexec/ld.so/amd64/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/amd64/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/amd64/ld.script       10 May 2019 13:29:21 -0000      1.1
+++ libexec/ld.so/amd64/ld.script       17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -26,7 +27,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text =0xcccccccc
+    } :btext =0xcccccccc
     . = ALIGN(0x1000);
     .text      : { *(.text .text.*) } :text =0xcccccccc
 
@@ -62,6 +63,7 @@ SECTIONS
     /* DATA */
     . = ALIGN(0x1000);
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x1000);
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
 
Index: libexec/ld.so/arm/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/arm/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/arm/ld.script 10 May 2019 13:29:21 -0000      1.1
+++ libexec/ld.so/arm/ld.script 17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -29,7 +30,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text
+    } :btext
 
     /* RELRO DATA */
     . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
@@ -63,6 +64,7 @@ SECTIONS
     /* DATA */
     . = ALIGN(0x1000);
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x1000);
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
 
Index: libexec/ld.so/powerpc/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/powerpc/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/powerpc/ld.script     10 May 2019 13:29:21 -0000      1.1
+++ libexec/ld.so/powerpc/ld.script     17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -26,7 +27,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text
+    } :btext
     . = ALIGN(0x1000);
     .text      : { *(.text .text.*) } :text
 
@@ -62,6 +63,7 @@ SECTIONS
     . = ALIGN(0x1000);
     .sdata     : { *(.sdata .sdata.*) } :data
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x1000);
     .sbss      : { *(.sbss .sbss.*) } :data
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
Index: libexec/ld.so/powerpc64/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/powerpc64/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/powerpc64/ld.script   25 Jun 2020 04:00:58 -0000      1.1
+++ libexec/ld.so/powerpc64/ld.script   17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -26,7 +27,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text
+    } :btext
     . = ALIGN(0x1000);
     .text      : { *(.text .text.*) } :text
 
@@ -62,6 +63,7 @@ SECTIONS
     . = ALIGN(0x1000);
     .sdata     : { *(.sdata .sdata.*) } :data
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x1000);
     .sbss      : { *(.sbss .sbss.*) } :data
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
Index: libexec/ld.so/riscv64/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/riscv64/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/riscv64/ld.script     28 Apr 2021 15:16:26 -0000      1.1
+++ libexec/ld.so/riscv64/ld.script     17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -28,7 +29,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text
+    } :btext
 
     /* RELRO DATA */
     . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
@@ -62,6 +63,7 @@ SECTIONS
     /* DATA */
     . = ALIGN(0x1000);
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x1000);
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
 
Index: libexec/ld.so/sparc64/ld.script
===================================================================
RCS file: /cvs/src/libexec/ld.so/sparc64/ld.script,v
retrieving revision 1.1
diff -u -p -u -r1.1 ld.script
--- libexec/ld.so/sparc64/ld.script     10 May 2019 13:29:21 -0000      1.1
+++ libexec/ld.so/sparc64/ld.script     17 Sep 2022 13:11:25 -0000
@@ -2,6 +2,7 @@ PHDRS
 {
        rodata  PT_LOAD FILEHDR PHDRS FLAGS (4);
        text    PT_LOAD;
+       btext   PT_LOAD FLAGS (0x08000005);
        data    PT_LOAD;
        random  PT_OPENBSD_RANDOMIZE;
        relro   PT_GNU_RELRO;
@@ -26,7 +27,7 @@ SECTIONS
        boot_text_start = .;
        *(.boot.text)
        boot_text_end = .;
-    } :text =0xcccccccc
+    } :btext =0xcccccccc
     . = ALIGN(0x100000);
     .text      : { *(.text .text.*) } :text =0xcccccccc
 
@@ -62,6 +63,7 @@ SECTIONS
     /* DATA */
     . = ALIGN(0x100000);
     .data      : { *(.data .data.*) } :data
+    . = ALIGN(0x2000);
     .bss       : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data
     . = DATA_SEGMENT_END (.);
 
Index: sys/arch/mips64/mips64/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/trap.c,v
retrieving revision 1.159
diff -u -p -u -r1.159 trap.c
--- sys/arch/mips64/mips64/trap.c       28 Feb 2022 15:49:57 -0000      1.159
+++ sys/arch/mips64/mips64/trap.c       21 Sep 2022 13:05:28 -0000
@@ -616,7 +616,7 @@ fault_common_no_miss:
                                KERNEL_UNLOCK();
                                (void)uvm_map_protect(map, p->p_md.md_fppgva,
                                    p->p_md.md_fppgva + PAGE_SIZE,
-                                   PROT_NONE, FALSE);
+                                   PROT_NONE, FALSE, FALSE);
                                return;
                        }
                        /* FALLTHROUGH */
@@ -1587,7 +1587,8 @@ fpe_branch_emulate(struct proc *p, struc
         */
 
        rc = uvm_map_protect(map, p->p_md.md_fppgva,
-           p->p_md.md_fppgva + PAGE_SIZE, PROT_READ | PROT_WRITE, FALSE);
+           p->p_md.md_fppgva + PAGE_SIZE, PROT_READ | PROT_WRITE, FALSE,
+           FALSE);
        if (rc != 0) {
 #ifdef DEBUG
                printf("%s: uvm_map_protect on %p failed: %d\n",
@@ -1626,7 +1627,7 @@ fpe_branch_emulate(struct proc *p, struc
        }
 
        (void)uvm_map_protect(map, p->p_md.md_fppgva,
-           p->p_md.md_fppgva + PAGE_SIZE, PROT_READ | PROT_EXEC, FALSE);
+           p->p_md.md_fppgva + PAGE_SIZE, PROT_READ | PROT_EXEC, FALSE, FALSE);
        p->p_md.md_fpbranchva = dest;
        p->p_md.md_fpslotva = (vaddr_t)tf->pc + 4;
        p->p_md.md_flags |= MDP_FPUSED;
@@ -1640,7 +1641,7 @@ err:
        KERNEL_UNLOCK();
 err2:
        (void)uvm_map_protect(map, p->p_md.md_fppgva,
-           p->p_md.md_fppgva + PAGE_SIZE, PROT_NONE, FALSE);
+           p->p_md.md_fppgva + PAGE_SIZE, PROT_NONE, FALSE, FALSE);
        return rc;
 }
 #endif
Index: sys/kern/exec_elf.c
===================================================================
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.168
diff -u -p -u -r1.168 exec_elf.c
--- sys/kern/exec_elf.c 29 Aug 2022 16:53:46 -0000      1.168
+++ sys/kern/exec_elf.c 29 Sep 2022 04:12:12 -0000
@@ -189,11 +189,17 @@ elf_load_psection(struct exec_vmcmd_set 
         * initially.  The dynamic linker will make these read-only
         * and add back X permission after relocation processing.
         * Static executables with W|X segments will probably crash.
+        * Apply immutability as much as possible, but not for RELRO
+        * or PT_OPENBSD_MUTABLE sections, or LOADS marked entirely
+        * PF_MUTABLE. Userland (meaning crt0 or ld.so) will take care
+        * of those regions if it is possible.
         */
        *prot |= (ph->p_flags & PF_R) ? PROT_READ : 0;
        *prot |= (ph->p_flags & PF_W) ? PROT_WRITE : 0;
        if ((ph->p_flags & PF_W) == 0)
                *prot |= (ph->p_flags & PF_X) ? PROT_EXEC : 0;
+       if ((ph->p_flags & PF_MUTABLE) == 0)
+               flags |= VMCMD_IMMUTABLE;
 
        msize = ph->p_memsz + diff;
        offset = ph->p_offset - bdiff;
@@ -432,6 +438,12 @@ elf_load_file(struct proc *p, char *path
                            ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0);
                        break;
 
+               case PT_GNU_RELRO:
+               case PT_OPENBSD_MUTABLE:
+                       NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,
+                           ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0);
+                       break;
+
                default:
                        break;
                }
@@ -652,6 +664,12 @@ exec_elf_makecmds(struct proc *p, struct
                        }
                        randomizequota -= ph[i].p_memsz;
                        NEW_VMCMD(&epp->ep_vmcmds, vmcmd_randomize,
+                           ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 
0);
+                       break;
+
+               case PT_GNU_RELRO:
+               case PT_OPENBSD_MUTABLE:
+                       NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,
                            ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 
0);
                        break;
 
Index: sys/kern/exec_subr.c
===================================================================
RCS file: /cvs/src/sys/kern/exec_subr.c,v
retrieving revision 1.57
diff -u -p -u -r1.57 exec_subr.c
--- sys/kern/exec_subr.c        29 Nov 2019 06:34:45 -0000      1.57
+++ sys/kern/exec_subr.c        17 Sep 2022 13:11:25 -0000
@@ -211,6 +211,10 @@ vmcmd_map_pagedvn(struct proc *p, struct
                 * error: detach from object
                 */
                uobj->pgops->pgo_detach(uobj);
+       } else {
+               if (cmd->ev_flags & VMCMD_IMMUTABLE)
+                       uvm_map_immutable(&p->p_vmspace->vm_map, cmd->ev_addr,
+                           cmd->ev_addr + cmd->ev_len, 1, "pagedvm");
        }
 
        return (error);
@@ -259,7 +263,7 @@ vmcmd_map_readvn(struct proc *p, struct 
                return (uvm_map_protect(&p->p_vmspace->vm_map,
                    trunc_page(cmd->ev_addr),
                    round_page(cmd->ev_addr + cmd->ev_len),
-                   prot, FALSE));
+                   prot, FALSE, TRUE));
        }
        return (0);
 }
@@ -281,6 +285,23 @@ vmcmd_map_zero(struct proc *p, struct ex
            UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY,
            MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW |
            (cmd->ev_flags & VMCMD_STACK ? UVM_FLAG_STACK : 0))));
+}
+
+/*
+ * vmcmd_mutable():
+ *     handle vmcmd which changes an address space region.back to mutable
+ */
+
+int
+vmcmd_mutable(struct proc *p, struct exec_vmcmd *cmd)
+{
+       if (cmd->ev_len == 0)
+               return (0);
+       
+       cmd->ev_addr = trunc_page(cmd->ev_addr);
+       uvm_map_immutable(&p->p_vmspace->vm_map, cmd->ev_addr,
+           cmd->ev_addr + round_page(cmd->ev_len), 0, "mutable");
+       return 0;
 }
 
 /*
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /cvs/src/sys/kern/init_sysent.c,v
retrieving revision 1.249
diff -u -p -u -r1.249 init_sysent.c
--- sys/kern/init_sysent.c      3 Sep 2022 21:16:51 -0000       1.249
+++ sys/kern/init_sysent.c      17 Sep 2022 13:11:25 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: init_sysent.c,v 1.249 2022/09/03 21:16:51 mbuhl Exp $ */
+/*     $OpenBSD$       */
 
 /*
  * System call switch table.
@@ -355,8 +355,8 @@ const struct sysent sysent[] = {
            sys_nosys },                        /* 157 = obsolete statfs25 */
        { 0, 0, 0,
            sys_nosys },                        /* 158 = obsolete fstatfs25 */
-       { 0, 0, 0,
-           sys_nosys },                        /* 159 = unimplemented */
+       { 2, s(struct sys_mimmutable_args), 0,
+           sys_mimmutable },                   /* 159 = mimmutable */
        { 0, 0, 0,
            sys_nosys },                        /* 160 = unimplemented */
        { 2, s(struct sys_getfh_args), 0,
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.231
diff -u -p -u -r1.231 kern_exec.c
--- sys/kern/kern_exec.c        14 Aug 2022 01:58:27 -0000      1.231
+++ sys/kern/kern_exec.c        17 Sep 2022 13:11:25 -0000
@@ -466,16 +466,19 @@ sys_execve(struct proc *p, void *v, regi
 #ifdef MACHINE_STACK_GROWS_UP
        pr->ps_strings = (vaddr_t)vm->vm_maxsaddr + sgap;
         if (uvm_map_protect(&vm->vm_map, (vaddr_t)vm->vm_maxsaddr,
-            trunc_page(pr->ps_strings), PROT_NONE, TRUE))
+            trunc_page(pr->ps_strings), PROT_NONE, TRUE, TRUE))
                 goto exec_abort;
 #else
        pr->ps_strings = (vaddr_t)vm->vm_minsaddr - sizeof(arginfo) - sgap;
         if (uvm_map_protect(&vm->vm_map,
             round_page(pr->ps_strings + sizeof(arginfo)),
-            (vaddr_t)vm->vm_minsaddr, PROT_NONE, TRUE))
+            (vaddr_t)vm->vm_minsaddr, PROT_NONE, TRUE, TRUE))
                 goto exec_abort;
 #endif
 
+       uvm_map_immutable(&p->p_vmspace->vm_map, (vaddr_t)vm->vm_maxsaddr,
+           (vaddr_t)vm->vm_minsaddr, 1, "stack");
+
        memset(&arginfo, 0, sizeof(arginfo));
 
        /* remember information about the process */
@@ -863,6 +866,8 @@ exec_sigcode_map(struct process *pr)
                uao_detach(sigobject);
                return (ENOMEM);
        }
+       uvm_map_immutable(&pr->ps_vmspace->vm_map, pr->ps_sigcode,
+           pr->ps_sigcode + round_page(sz), 1, "sig");
 
        /* Calculate PC at point of sigreturn entry */
        pr->ps_sigcoderet = pr->ps_sigcode + (sigcoderet - sigcode);
@@ -911,6 +916,8 @@ exec_timekeep_map(struct process *pr)
                uao_detach(timekeep_object);
                return (ENOMEM);
        }
+       uvm_map_immutable(&pr->ps_vmspace->vm_map, pr->ps_timekeep,
+           pr->ps_timekeep + timekeep_sz, 1, "time");
 
        return (0);
 }
Index: sys/kern/kern_pledge.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_pledge.c,v
retrieving revision 1.295
diff -u -p -u -r1.295 kern_pledge.c
--- sys/kern/kern_pledge.c      5 Sep 2022 16:37:47 -0000       1.295
+++ sys/kern/kern_pledge.c      17 Sep 2022 13:11:25 -0000
@@ -150,6 +150,7 @@ const uint64_t pledge_syscalls[SYS_MAXSY
        [SYS_minherit] = PLEDGE_STDIO,
        [SYS_mmap] = PLEDGE_STDIO,
        [SYS_mprotect] = PLEDGE_STDIO,
+       [SYS_mimmutable] = PLEDGE_STDIO,
        [SYS_mquery] = PLEDGE_STDIO,
        [SYS_munmap] = PLEDGE_STDIO,
        [SYS_msync] = PLEDGE_STDIO,
Index: sys/kern/kern_resource.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.74
diff -u -p -u -r1.74 kern_resource.c
--- sys/kern/kern_resource.c    28 May 2022 03:47:43 -0000      1.74
+++ sys/kern/kern_resource.c    17 Sep 2022 13:11:25 -0000
@@ -328,8 +328,8 @@ dosetrlimit(struct proc *p, u_int which,
                        addr = trunc_page(addr);
                        size = round_page(size);
                        KERNEL_LOCK();
-                       (void) uvm_map_protect(&vm->vm_map,
-                                             addr, addr+size, prot, FALSE);
+                       (void) uvm_map_protect(&vm->vm_map, addr,
+                           addr+size, prot, FALSE, FALSE);
                        KERNEL_UNLOCK();
                }
        }
Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.c,v
retrieving revision 1.247
diff -u -p -u -r1.247 syscalls.c
--- sys/kern/syscalls.c 3 Sep 2022 21:16:51 -0000       1.247
+++ sys/kern/syscalls.c 17 Sep 2022 13:11:25 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscalls.c,v 1.247 2022/09/03 21:16:51 mbuhl Exp $    */
+/*     $OpenBSD$       */
 
 /*
  * System call names.
@@ -183,7 +183,7 @@ const char *const syscallnames[] = {
        "#156 (obsolete ogetdirentries)",               /* 156 = obsolete 
ogetdirentries */
        "#157 (obsolete statfs25)",             /* 157 = obsolete statfs25 */
        "#158 (obsolete fstatfs25)",            /* 158 = obsolete fstatfs25 */
-       "#159 (unimplemented)",         /* 159 = unimplemented */
+       "mimmutable",                   /* 159 = mimmutable */
        "#160 (unimplemented)",         /* 160 = unimplemented */
        "getfh",                        /* 161 = getfh */
        "#162 (obsolete ogetdomainname)",               /* 162 = obsolete 
ogetdomainname */
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.master,v
retrieving revision 1.232
diff -u -p -u -r1.232 syscalls.master
--- sys/kern/syscalls.master    3 Sep 2022 21:13:48 -0000       1.232
+++ sys/kern/syscalls.master    17 Sep 2022 13:11:25 -0000
@@ -307,7 +307,7 @@
 156    OBSOL           ogetdirentries
 157    OBSOL           statfs25
 158    OBSOL           fstatfs25
-159    UNIMPL
+159    STD             { int sys_mimmutable(void *addr, size_t len); }
 160    UNIMPL
 161    STD             { int sys_getfh(const char *fname, fhandle_t *fhp); }
 162    OBSOL           ogetdomainname
Index: sys/sys/exec.h
===================================================================
RCS file: /cvs/src/sys/sys/exec.h,v
retrieving revision 1.48
diff -u -p -u -r1.48 exec.h
--- sys/sys/exec.h      1 Sep 2022 07:26:56 -0000       1.48
+++ sys/sys/exec.h      17 Sep 2022 13:11:25 -0000
@@ -93,9 +93,10 @@ struct exec_vmcmd {
 #define VMCMD_BASE      0x0002  /* marks a base entry */
 #define VMCMD_STACK     0x0004  /* create with UVM_FLAG_STACK */
 #define VMCMD_SYSCALL   0x0008  /* create with UVM_FLAG_SYSCALL */
+#define VMCMD_IMMUTABLE        0x0010  /* make immutable */
 };
 
-#define        EXEC_DEFAULT_VMCMD_SETSIZE      8       /* # of cmds in set to 
start */
+#define        EXEC_DEFAULT_VMCMD_SETSIZE      12      /* # of cmds in set to 
start */
 
 /* exec vmspace-creation command set; see below */
 struct exec_vmcmd_set {
@@ -148,6 +149,7 @@ int vmcmd_map_pagedvn(struct proc *, str
 int    vmcmd_map_readvn(struct proc *, struct exec_vmcmd *);
 int    vmcmd_map_zero(struct proc *, struct exec_vmcmd *);
 int    vmcmd_randomize(struct proc *, struct exec_vmcmd *);
+int    vmcmd_mutable(struct proc *, struct exec_vmcmd *);
 int    copyargs(struct exec_package *, struct ps_strings *, void *, void *);
 void   setregs(struct proc *, struct exec_package *, u_long, register_t *);
 int    check_exec(struct proc *, struct exec_package *);
Index: sys/sys/exec_elf.h
===================================================================
RCS file: /cvs/src/sys/sys/exec_elf.h,v
retrieving revision 1.94
diff -u -p -u -r1.94 exec_elf.h
--- sys/sys/exec_elf.h  25 Dec 2021 01:25:51 -0000      1.94
+++ sys/sys/exec_elf.h  17 Sep 2022 13:11:25 -0000
@@ -305,6 +305,7 @@ typedef struct {
 #define ELF_SYMTAB      ".symtab"      /* symbol table */
 #define ELF_TEXT        ".text"                /* code */
 #define ELF_OPENBSDRANDOMDATA ".openbsd.randomdata" /* constant randomdata */
+#define ELF_OPENBSDMUTABLE ".openbsd.mutable" /* mutable bss */
 
 
 /* Section Attribute Flags - sh_flags */
@@ -476,6 +477,7 @@ typedef struct {
 #define PT_GNU_EH_FRAME                0x6474e550      /* Exception handling 
info */
 #define PT_GNU_RELRO           0x6474e552      /* Read-only after relocation */
 
+#define PT_OPENBSD_MUTABLE     0x65a3dbe5      /* like bss, but not immutable 
*/
 #define PT_OPENBSD_RANDOMIZE   0x65a3dbe6      /* fill with random data */
 #define PT_OPENBSD_WXNEEDED    0x65a3dbe7      /* program performs W^X 
violations */
 #define PT_OPENBSD_BOOTDATA    0x65a41be6      /* section for boot arguments */
@@ -484,6 +486,7 @@ typedef struct {
 #define PF_X           0x1             /* Executable */
 #define PF_W           0x2             /* Writable */
 #define PF_R           0x4             /* Readable */
+#define PF_MUTABLE     0x08000000      /* Mutable */
 #define PF_MASKPROC    0xf0000000      /* reserved bits for processor */
                                        /*  specific segment flags */
 
Index: sys/sys/mman.h
===================================================================
RCS file: /cvs/src/sys/sys/mman.h,v
retrieving revision 1.34
diff -u -p -u -r1.34 mman.h
--- sys/sys/mman.h      1 Mar 2019 01:46:18 -0000       1.34
+++ sys/sys/mman.h      17 Sep 2022 13:11:25 -0000
@@ -154,6 +154,7 @@ int munlockall(void);
 #if __BSD_VISIBLE
 int    madvise(void *, size_t, int);
 int    minherit(void *, size_t, int);
+int    mimmutable(void *, size_t);
 void * mquery(void *, size_t, int, int, int, off_t);
 #endif
 int    posix_madvise(void *, size_t, int);
Index: sys/sys/syscall.h
===================================================================
RCS file: /cvs/src/sys/sys/syscall.h,v
retrieving revision 1.246
diff -u -p -u -r1.246 syscall.h
--- sys/sys/syscall.h   3 Sep 2022 21:16:51 -0000       1.246
+++ sys/sys/syscall.h   17 Sep 2022 13:11:25 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscall.h,v 1.246 2022/09/03 21:16:51 mbuhl Exp $     */
+/*     $OpenBSD$       */
 
 /*
  * System call numbers.
@@ -441,6 +441,9 @@
                                /* 156 is obsolete ogetdirentries */
                                /* 157 is obsolete statfs25 */
                                /* 158 is obsolete fstatfs25 */
+/* syscall: "mimmutable" ret: "int" args: "void *" "size_t" */
+#define        SYS_mimmutable  159
+
 /* syscall: "getfh" ret: "int" args: "const char *" "fhandle_t *" */
 #define        SYS_getfh       161
 
Index: sys/sys/syscallargs.h
===================================================================
RCS file: /cvs/src/sys/sys/syscallargs.h,v
retrieving revision 1.249
diff -u -p -u -r1.249 syscallargs.h
--- sys/sys/syscallargs.h       3 Sep 2022 21:16:51 -0000       1.249
+++ sys/sys/syscallargs.h       17 Sep 2022 13:11:25 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscallargs.h,v 1.249 2022/09/03 21:16:51 mbuhl Exp $ */
+/*     $OpenBSD$       */
 
 /*
  * System call argument lists.
@@ -733,6 +733,11 @@ struct sys_nfssvc_args {
        syscallarg(void *) argp;
 };
 
+struct sys_mimmutable_args {
+       syscallarg(void *) addr;
+       syscallarg(size_t) len;
+};
+
 struct sys_getfh_args {
        syscallarg(const char *) fname;
        syscallarg(fhandle_t *) fhp;
@@ -1345,6 +1350,7 @@ int       sys_ypconnect(struct proc *, void *,
 int    sys_nfssvc(struct proc *, void *, register_t *);
 #else
 #endif
+int    sys_mimmutable(struct proc *, void *, register_t *);
 int    sys_getfh(struct proc *, void *, register_t *);
 int    sys___tmpfd(struct proc *, void *, register_t *);
 int    sys_sysarch(struct proc *, void *, register_t *);
Index: sys/uvm/uvm.h
===================================================================
RCS file: /cvs/src/sys/uvm/uvm.h,v
retrieving revision 1.70
diff -u -p -u -r1.70 uvm.h
--- sys/uvm/uvm.h       29 Sep 2022 04:10:27 -0000      1.70
+++ sys/uvm/uvm.h       29 Sep 2022 04:13:32 -0000
@@ -92,6 +92,7 @@ struct uvm {
 #define UVM_ET_WC              0x0080  /* write combining */
 #define UVM_ET_CONCEAL         0x0100  /* omit from dumps */
 #define UVM_ET_SYSCALL         0x0200  /* syscall text segment */
+#define UVM_ET_IMMUTABLE       0x0400  /* entry may not be changed */
 #define UVM_ET_FREEMAPPED      0x8000  /* map entry is on free list (DEBUG) */
 
 #define UVM_ET_ISOBJ(E)                (((E)->etype & UVM_ET_OBJ) != 0)
Index: sys/uvm/uvm_extern.h
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.163
diff -u -p -u -r1.163 uvm_extern.h
--- sys/uvm/uvm_extern.h        15 Aug 2022 03:21:04 -0000      1.163
+++ sys/uvm/uvm_extern.h        17 Sep 2022 13:11:25 -0000
@@ -399,7 +399,7 @@ int                 uvm_map_pageable_all(vm_map_t, int
 boolean_t              uvm_map_checkprot(vm_map_t, vaddr_t,
                            vaddr_t, vm_prot_t);
 int                    uvm_map_protect(vm_map_t, vaddr_t, 
-                           vaddr_t, vm_prot_t, boolean_t);
+                           vaddr_t, vm_prot_t, boolean_t, boolean_t);
 struct vmspace         *uvmspace_alloc(vaddr_t, vaddr_t,
                            boolean_t, boolean_t);
 void                   uvmspace_init(struct vmspace *, struct pmap *,
Index: sys/uvm/uvm_io.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_io.c,v
retrieving revision 1.29
diff -u -p -u -r1.29 uvm_io.c
--- sys/uvm/uvm_io.c    12 Mar 2022 08:11:07 -0000      1.29
+++ sys/uvm/uvm_io.c    17 Sep 2022 13:11:25 -0000
@@ -127,7 +127,7 @@ uvm_io(vm_map_t map, struct uio *uio, in
                vm_map_lock(kernel_map);
                TAILQ_INIT(&dead_entries);
                uvm_unmap_remove(kernel_map, kva, kva+chunksz,
-                   &dead_entries, FALSE, TRUE);
+                   &dead_entries, FALSE, TRUE, FALSE);
                vm_map_unlock(kernel_map);
                uvm_unmap_detach(&dead_entries, AMAP_REFALL);
 
Index: sys/uvm/uvm_map.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.c,v
retrieving revision 1.294
diff -u -p -u -r1.294 uvm_map.c
--- sys/uvm/uvm_map.c   15 Aug 2022 15:53:45 -0000      1.294
+++ sys/uvm/uvm_map.c   23 Sep 2022 02:13:55 -0000
@@ -797,7 +797,13 @@ uvm_mapanon(struct vm_map *map, vaddr_t 
                                error = EINVAL;
                                goto unlock;
                        }
-                       uvm_unmap_remove(map, *addr, *addr + sz, &dead, FALSE, 
TRUE);
+                       if (uvm_unmap_remove(map, *addr, *addr + sz, &dead,
+                           FALSE, TRUE, TRUE) != 0) {
+                               printf("uvm_mapanon: %s\n", 
curproc->p_p->ps_comm);
+                               // XXX immutable must fail
+                               error = ENOMEM;
+                               goto unlock;
+                       }
                }
                if (!uvm_map_isavail(map, NULL, &first, &last, *addr, sz)) {
                        error = ENOMEM;
@@ -1038,8 +1044,15 @@ uvm_map(struct vm_map *map, vaddr_t *add
                }
 
                /* Check that the space is available. */
-               if (flags & UVM_FLAG_UNMAP)
-                       uvm_unmap_remove(map, *addr, *addr + sz, &dead, FALSE, 
TRUE);
+               if (flags & UVM_FLAG_UNMAP) {
+                       if (uvm_unmap_remove(map, *addr, *addr + sz, &dead,
+                           FALSE, TRUE, TRUE) != 0) {
+                               printf("uvm_map: %s\n", curproc->p_p->ps_comm);
+                               // XXX immutable must fail
+                               error = ENOMEM;
+                               goto unlock;
+                       }
+               }
                if (!uvm_map_isavail(map, NULL, &first, &last, *addr, sz)) {
                        error = ENOMEM;
                        goto unlock;
@@ -1817,7 +1830,7 @@ uvm_unmap(struct vm_map *map, vaddr_t st
            (end & (vaddr_t)PAGE_MASK) == 0);
        TAILQ_INIT(&dead);
        vm_map_lock(map);
-       uvm_unmap_remove(map, start, end, &dead, FALSE, TRUE);
+       uvm_unmap_remove(map, start, end, &dead, FALSE, TRUE, FALSE);
        vm_map_unlock(map);
 
        if (map->flags & VM_MAP_INTRSAFE)
@@ -1959,17 +1972,17 @@ uvm_unmap_kill_entry(struct vm_map *map,
  * If markfree, entry will be properly marked free, otherwise, no replacement
  * entry will be put in the tree (corrupting the tree).
  */
-void
+int
 uvm_unmap_remove(struct vm_map *map, vaddr_t start, vaddr_t end,
     struct uvm_map_deadq *dead, boolean_t remove_holes,
-    boolean_t markfree)
+    boolean_t markfree, boolean_t checkimmutable)
 {
        struct vm_map_entry *prev_hint, *next, *entry;
 
        start = MAX(start, map->min_offset);
        end = MIN(end, map->max_offset);
        if (start >= end)
-               return;
+               return 0;
 
        if ((map->flags & VM_MAP_INTRSAFE) == 0)
                splassert(IPL_NONE);
@@ -1979,6 +1992,24 @@ uvm_unmap_remove(struct vm_map *map, vad
        /* Find first affected entry. */
        entry = uvm_map_entrybyaddr(&map->addr, start);
        KDASSERT(entry != NULL && entry->start <= start);
+
+       if (checkimmutable) {
+               struct vm_map_entry *entry1 = entry;
+
+               /* Refuse to unmap if any entries are immutable */
+               for (; entry1 != NULL && entry1->start < end; entry1 = next) {
+                       KDASSERT(entry1->start >= start);
+//                     if (entry1->end > end || !markfree)
+//                             UVM_MAP_CLIP_END(map, entry1, end);
+//                     KDASSERT(entry1->start >= start && entry1->end <= end);
+                       next = RBT_NEXT(uvm_map_addr, entry1);
+                       if (entry1->etype & UVM_ET_IMMUTABLE) {
+                               printf("uvm_unmap: %s\n", 
curproc->p_p->ps_comm);
+                               return EPERM;
+                       }
+               }
+       }
+
        if (entry->end <= start && markfree)
                entry = RBT_NEXT(uvm_map_addr, entry);
        else
@@ -2043,6 +2074,7 @@ uvm_unmap_remove(struct vm_map *map, vad
                        KDASSERT(uvm_map_entrybyaddr(&map->addr, a) == NULL);
        }
 #endif
+       return 0;
 }
 
 /*
@@ -3063,7 +3095,7 @@ uvm_page_printit(struct vm_page *pg, boo
  */
 int
 uvm_map_protect(struct vm_map *map, vaddr_t start, vaddr_t end,
-    vm_prot_t new_prot, boolean_t set_max)
+    vm_prot_t new_prot, boolean_t set_max, boolean_t checkimmutable)
 {
        struct vm_map_entry *first, *iter;
        vm_prot_t old_prot;
@@ -3098,6 +3130,14 @@ uvm_map_protect(struct vm_map *map, vadd
                if (iter->start == iter->end || UVM_ET_ISHOLE(iter))
                        continue;
 
+               if (checkimmutable &&
+                   (iter->etype & UVM_ET_IMMUTABLE)) {
+                       printf("%s failing mprotect %lx-%lx inside %lx-%lx\n",
+                           curproc->p_p->ps_comm,
+                           iter->start, iter->end, start, end);
+                       error = EPERM;
+                       goto out;
+               }
                old_prot = iter->protection;
                if (old_prot == PROT_NONE && new_prot != old_prot) {
                        dused += uvmspace_dused(
@@ -3356,7 +3396,7 @@ uvmspace_exec(struct proc *p, vaddr_t st
                 * (as in, not replace them with free-memory entries).
                 */
                uvm_unmap_remove(map, map->min_offset, map->max_offset,
-                   &dead_entries, TRUE, FALSE);
+                   &dead_entries, TRUE, FALSE, FALSE);
 
                KDASSERT(RBT_EMPTY(uvm_map_addr, &map->addr));
 
@@ -3529,7 +3569,7 @@ uvm_share(struct vm_map *dstmap, vaddr_t
        }
 
        ret = EINVAL;
-       uvm_unmap_remove(dstmap, dstaddr, unmap_end, &dead, FALSE, TRUE);
+       uvm_unmap_remove(dstmap, dstaddr, unmap_end, &dead, FALSE, TRUE, FALSE);
 
 exit_unlock:
        vm_map_unlock_read(srcmap);
@@ -4088,7 +4128,7 @@ uvm_map_deallocate(vm_map_t map)
        TAILQ_INIT(&dead);
        uvm_tree_sanity(map, __FILE__, __LINE__);
        uvm_unmap_remove(map, map->min_offset, map->max_offset, &dead,
-           TRUE, FALSE);
+           TRUE, FALSE, FALSE);
        pmap_destroy(map->pmap);
        KASSERT(RBT_EMPTY(uvm_map_addr, &map->addr));
        free(map, M_VMMAP, sizeof *map);
@@ -4183,6 +4223,52 @@ uvm_map_syscall(struct vm_map *map, vadd
        return (0);
 }
 
+/* 
+ * uvm_map_immutable: block mapping/mprotect for range of addrs in map.
+ *
+ * => map must be unlocked
+ */
+int
+uvm_map_immutable(struct vm_map *map, vaddr_t start, vaddr_t end, int imut, 
char *name)
+{
+       struct vm_map_entry *entry;
+
+       if (start > end)
+               return EINVAL;
+       start = MAX(start, map->min_offset);
+       end = MIN(end, map->max_offset);
+       if (start >= end)
+               return 0;
+
+       vm_map_lock(map);
+
+       entry = uvm_map_entrybyaddr(&map->addr, start);
+       if (entry->end > start)
+               UVM_MAP_CLIP_START(map, entry, start);
+       else
+               entry = RBT_NEXT(uvm_map_addr, entry);
+
+       while (entry != NULL && entry->start < end) {
+               UVM_MAP_CLIP_END(map, entry, end);
+               if (imut) {     
+//                     printf("%s %lx imut\n", name, entry->start);
+//                     if ((entry->etype & UVM_ET_IMMUTABLE))
+//                             printf("%s already immutable %lx-%lx inside 
%lx-%lx\n",
+//                                 curproc->p_p->ps_comm,
+//                                 entry->start, entry->end, start, end);
+                       entry->etype |= UVM_ET_IMMUTABLE;
+               } else {
+//                     printf("%s %lx-%lx mut\n", name, entry->start, 
entry->end);
+                       entry->etype &= ~UVM_ET_IMMUTABLE;
+               }
+               entry = RBT_NEXT(uvm_map_addr, entry);
+       }
+
+       map->wserial++;
+       vm_map_unlock(map);
+       return (0);
+}
+
 /*
  * uvm_map_advice: set advice code for range of addrs in map.
  *
@@ -4367,7 +4453,7 @@ uvm_map_extract(struct vm_map *srcmap, v
 fail2_unmap:
        if (error) {
                uvm_unmap_remove(kernel_map, dstaddr, dstaddr + len, &dead,
-                   FALSE, TRUE);
+                   FALSE, TRUE, FALSE);
        }
 
        /* Release maps, release dead entries. */
Index: sys/uvm/uvm_map.h
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.h,v
retrieving revision 1.75
diff -u -p -u -r1.75 uvm_map.h
--- sys/uvm/uvm_map.h   12 Mar 2022 08:11:07 -0000      1.75
+++ sys/uvm/uvm_map.h   17 Sep 2022 13:11:25 -0000
@@ -350,6 +350,7 @@ struct vm_map *     uvm_map_create(pmap_t, v
 vaddr_t                uvm_map_pie(vaddr_t);
 vaddr_t                uvm_map_hint(struct vmspace *, vm_prot_t, vaddr_t, 
vaddr_t);
 int            uvm_map_syscall(struct vm_map *, vaddr_t, vaddr_t);
+int            uvm_map_immutable(struct vm_map *, vaddr_t, vaddr_t, int, char 
*);
 int            uvm_map_inherit(struct vm_map *, vaddr_t, vaddr_t, 
vm_inherit_t);
 int            uvm_map_advice(struct vm_map *, vaddr_t, vaddr_t, int);
 void           uvm_map_init(void);
@@ -365,8 +366,8 @@ int         uvm_map_submap(struct vm_map *, vad
                    struct vm_map *);
 void           uvm_unmap(struct vm_map *, vaddr_t, vaddr_t);
 void           uvm_unmap_detach(struct uvm_map_deadq *, int);
-void           uvm_unmap_remove(struct vm_map*, vaddr_t, vaddr_t,
-                   struct uvm_map_deadq *, boolean_t, boolean_t);
+int            uvm_unmap_remove(struct vm_map*, vaddr_t, vaddr_t,
+                   struct uvm_map_deadq *, boolean_t, boolean_t, boolean_t);
 void           uvm_map_set_uaddr(struct vm_map*, struct uvm_addr_state**,
                    struct uvm_addr_state*);
 int            uvm_map_mquery(struct vm_map*, vaddr_t*, vsize_t, voff_t, int);
Index: sys/uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.172
diff -u -p -u -r1.172 uvm_mmap.c
--- sys/uvm/uvm_mmap.c  1 Aug 2022 14:56:59 -0000       1.172
+++ sys/uvm/uvm_mmap.c  17 Sep 2022 13:11:25 -0000
@@ -569,7 +569,11 @@ sys_munmap(struct proc *p, void *v, regi
        }
 
        TAILQ_INIT(&dead_entries);
-       uvm_unmap_remove(map, addr, addr + size, &dead_entries, FALSE, TRUE);
+       if (uvm_unmap_remove(map, addr, addr + size, &dead_entries,
+           FALSE, TRUE, TRUE) != 0) {
+               vm_map_unlock(map);
+               return EPERM;
+       }
        vm_map_unlock(map);     /* and unlock */
 
        uvm_unmap_detach(&dead_entries, 0);
@@ -619,7 +623,7 @@ sys_mprotect(struct proc *p, void *v, re
                return EINVAL;          /* disallow wrap-around. */
 
        return (uvm_map_protect(&p->p_vmspace->vm_map, addr, addr+size,
-           prot, FALSE));
+           prot, FALSE, TRUE));
 }
 
 /*
@@ -649,6 +653,32 @@ sys_msyscall(struct proc *p, void *v, re
 }
 
 /*
+ * sys_mimmutable: the mimmutable system call
+ */
+int
+sys_mimmutable(struct proc *p, void *v, register_t *retval)
+{
+       struct sys_mimmutable_args /* {
+               immutablearg(void *) addr;
+               immutablearg(size_t) len;
+       } */ *uap = v;
+       vaddr_t addr;
+       vsize_t size, pageoff;
+
+       addr = (vaddr_t)SCARG(uap, addr);
+       size = (vsize_t)SCARG(uap, len);
+
+       /*
+        * align the address to a page boundary, and adjust the size accordingly
+        */
+       ALIGN_ADDR(addr, size, pageoff);
+       if (addr > SIZE_MAX - size)
+               return EINVAL;          /* disallow wrap-around. */
+
+       return uvm_map_immutable(&p->p_vmspace->vm_map, addr, addr+size, 1, 
"sys");
+}
+
+/*
  * sys_minherit: the minherit system call
  */
 int
@@ -1228,7 +1258,8 @@ redo:
                        if (kva != 0) {
                                vm_map_lock(kernel_map);
                                uvm_unmap_remove(kernel_map, kva,
-                                   kva+PAGE_SIZE, &dead_entries, FALSE, TRUE);
+                                   kva+PAGE_SIZE, &dead_entries,
+                                   FALSE, TRUE, FALSE);        /* XXX */
                                vm_map_unlock(kernel_map);
                                kva = 0;
                        }
@@ -1255,7 +1286,7 @@ redo:
        if (kva != 0) {
                vm_map_lock(kernel_map);
                uvm_unmap_remove(kernel_map, kva, kva+PAGE_SIZE,
-                   &dead_entries, FALSE, TRUE);
+                   &dead_entries, FALSE, TRUE, FALSE);         /* XXX */
                vm_map_unlock(kernel_map);
        }
        uvm_unmap_detach(&dead_entries, AMAP_REFALL);
Index: usr.sbin/procmap/procmap.1
===================================================================
RCS file: /cvs/src/usr.sbin/procmap/procmap.1,v
retrieving revision 1.23
diff -u -p -u -r1.23 procmap.1
--- usr.sbin/procmap/procmap.1  31 Mar 2018 17:26:13 -0000      1.23
+++ usr.sbin/procmap/procmap.1  17 Sep 2022 13:11:25 -0000
@@ -223,7 +223,7 @@ MAP 0xcf7cac84: [0x0-\*(Gt0xbfbfe000]
         #ent=8, sz=34041856, ref=1, version=20, flags=0x21
         pmap=0xcf44cee0(resident=\*(Ltunknown\*(Gt)
  - 0xcfa3a358: 0x8048000-\*(Gt0x80b1000: obj=0xcf45a8e8/0x0, amap=0x0/0
-        submap=F, cow=T, nc=T, prot(max)=5/7, inh=1, wc=0, adv=0
+        submap=F, cow=T, nc=T, stack=F, syscall=F, immutable=F, prot(max)=5/7, 
inh=1, wc=0, adv=0
 \&...
 .Ed
 .Pp
@@ -274,17 +274,17 @@ file system
 appear as follows:
 .Bd -literal -offset indent
 $ procmap -m
-0x8048000 0x80b1000 r-x rwx COW NC 1 0 0
-0x80b1000 0x80b3000 rw- rwx COW NC 1 0 0
-0x80b3000 0x80ba000 rw- rwx COW NNC 1 0 0
-0x80ba000 0x80be000 rwx rwx COW NNC 1 0 0
+0x8048000 0x80b1000 r-x--I rwx COW NC 1 0 0
+0xdecf000 0xd018000 r-x--I rwx COW NC 1 0 0
+0x80b1000 0x80b3000 rw---I rwx COW NC 1 0 0
+0x80b3000 0x80ba000 rw---I rwx COW NNC 1 0 0
+0x80ba000 0x80be000 rwx--I rwx COW NNC 1 0 0
 \&...
 
 $ procmap -l
-08048000-080b1000 r-xp 00000000 00:00 70173     /bin/sh
-080b1000-080b3000 rw-p 00068000 00:00 70173     /bin/sh
-080b3000-080ba000 rw-p 00000000 00:00 0
-080ba000-080be000 rwxp 00000000 00:00 0
+0x08048000     0x080b1000      r-x--Ip 00000000 00:00 70173     /bin/sh
+0x080b1000     0x080b3000      rw---Ip 00068000 00:00 70173     /bin/sh
+0x080b3000     0x080ba000      rw---Ip 00000000 00:00 0
 \&...
 .Ed
 .Pp
Index: usr.sbin/procmap/procmap.c
===================================================================
RCS file: /cvs/src/usr.sbin/procmap/procmap.c,v
retrieving revision 1.69
diff -u -p -u -r1.69 procmap.c
--- usr.sbin/procmap/procmap.c  22 Feb 2022 17:35:01 -0000      1.69
+++ usr.sbin/procmap/procmap.c  17 Sep 2022 13:11:25 -0000
@@ -497,7 +497,7 @@ process_map(kvm_t *kd, pid_t pid, struct
                    (int)sizeof(int) * 2 - 1,  "Size ");
 #endif
        if (print_all)
-               printf("%-*s %-*s %*s %-*s rwxSepc  RWX  I/W/A Dev  %*s - 
File\n",
+               printf("%-*s %-*s %*s %-*s rwxSeIpc  RWX  I/W/A Dev  %*s - 
File\n",
                    (int)sizeof(long) * 2, "Start",
                    (int)sizeof(long) * 2, "End",
                    (int)sizeof(int)  * 2, "Size ",
@@ -719,7 +719,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
        name = findname(kd, vmspace, vme, vp, vfs, uvm_obj);
 
        if (print_map) {
-               printf("0x%-*lx 0x%-*lx %c%c%c%c%c %c%c%c %s %s %d %d %d",
+               printf("0x%-*lx 0x%-*lx %c%c%c%c%c%c %c%c%c %s %s %d %d %d",
                    (int)sizeof(long) * 2 + 0, vme->start,
                    (int)sizeof(long) * 2 + 0, vme->end,
                    (vme->protection & PROT_READ) ? 'r' : '-',
@@ -727,6 +727,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                    (vme->protection & PROT_EXEC) ? 'x' : '-',
                    (vme->etype & UVM_ET_STACK) ? 'S' : '-',
                    (vme->etype & UVM_ET_SYSCALL) ? 'e' : '-',
+                   (vme->etype & UVM_ET_IMMUTABLE) ? 'I' : '-',
                    (vme->max_protection & PROT_READ) ? 'r' : '-',
                    (vme->max_protection & PROT_WRITE) ? 'w' : '-',
                    (vme->max_protection & PROT_EXEC) ? 'x' : '-',
@@ -746,7 +747,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
        }
 
        if (print_maps)
-               printf("0x%-*lx 0x%-*lx %c%c%c%c%c%c %0*lx %02x:%02x %llu     
%s\n",
+               printf("0x%-*lx 0x%-*lx %c%c%c%c%c%c%c %0*lx %02x:%02x %llu     
%s\n",
                    (int)sizeof(void *) * 2, vme->start,
                    (int)sizeof(void *) * 2, vme->end,
                    (vme->protection & PROT_READ) ? 'r' : '-',
@@ -754,6 +755,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                    (vme->protection & PROT_EXEC) ? 'x' : '-',
                    (vme->etype & UVM_ET_STACK) ? 'S' : '-',
                    (vme->etype & UVM_ET_SYSCALL) ? 'e' : '-',
+                   (vme->etype & UVM_ET_IMMUTABLE) ? 'I' : '-',
                    (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's',
                    (int)sizeof(void *) * 2,
                    (unsigned long)vme->offset,
@@ -767,13 +769,14 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                    vme->object.uvm_obj, (unsigned long)vme->offset,
                    vme->aref.ar_amap, vme->aref.ar_pageoff);
                printf("\tsubmap=%c, cow=%c, nc=%c, stack=%c, "
-                   "syscall=%c, prot(max)=%d/%d, inh=%d, "
+                   "syscall=%c, immutable=%c, prot(max)=%d/%d, inh=%d, "
                    "wc=%d, adv=%d\n",
                    (vme->etype & UVM_ET_SUBMAP) ? 'T' : 'F',
                    (vme->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F',
                    (vme->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F',
                    (vme->etype & UVM_ET_STACK) ? 'T' : 'F',
                    (vme->etype & UVM_ET_SYSCALL) ? 'T' : 'F',
+                   (vme->etype & UVM_ET_IMMUTABLE) ? 'T' : 'F',
                    vme->protection, vme->max_protection,
                    vme->inheritance, vme->wired_count, vme->advice);
                if (inode && verbose)
@@ -813,7 +816,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                }
 
                sz = (size_t)((vme->end - vme->start) / 1024);
-               printf("%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c%c%c (%c%c%c) 
%d/%d/%d %02u:%02u %7llu - %s",
+               printf("%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c%c%c%c (%c%c%c) 
%d/%d/%d %02u:%02u %7llu - %s",
                    (int)sizeof(void *) * 2, vme->start, (int)sizeof(void *) * 
2,
                    vme->end - (vme->start != vme->end ? 1 : 0), (unsigned 
long)sz,
                    (int)sizeof(void *) * 2, (unsigned long)vme->offset,
@@ -822,6 +825,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                    (vme->protection & PROT_EXEC) ? 'x' : '-',
                    (vme->etype & UVM_ET_STACK) ? 'S' : '-',
                    (vme->etype & UVM_ET_SYSCALL) ? 'e' : '-',
+                   (vme->etype & UVM_ET_IMMUTABLE) ? 'I' : '-',
                    (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's',
                    (vme->etype & UVM_ET_NEEDSCOPY) ? '+' : '-',
                    (vme->max_protection & PROT_READ) ? 'r' : '-',

Reply via email to