Theo de Raadt <dera...@openbsd.org> wrote:

> Theo de Raadt <dera...@openbsd.org> wrote:
> 
> > Theo de Raadt <dera...@openbsd.org> wrote:
> > 
> > > In this version of the diff, the kernel manages to mark immutable most of
> > > the main binary, and in the shared-binary case, also most of ld.so.  But 
> > > it
> > > cannot mark all of the ELF mapping -- because of two remaining problems 
> > > (RELRO
> > > in .data, and the malloc.c self-protected bookkeeping page in .bss).  I am
> > > looking into various solutions for both of those.
> 
> Yet another version of the diff as I incrementally get it working better.
> Call it version 22..
> 
> Some things of note:
> 
> 1. Some linkers appear to be creating non-aligned relro sections, which
>    has security implications as they cannot be mprotected correctly.  I
>    am happy this work has exposed the problem as severe.  I have a
>    workaround in ld.so for now that allows these cases to work, and
>    later on we can perhaps add a warning to ld.so to identify these
>    linkers and get them fixed.
> 
> 2. But the relro is still not handled perfectly, and I hope someone else's
>    eyes can compare addresses and spot what's wrong.
> 
> 3. ld.so has to cut the list of mutable mappings from the immutable mappings,
>    before applying them (late, to satisfy 1).    This is in 
> _dl_apply_mutable().
>    After redoing this a couple of times, I am still not proud of it.
> 
> 4. uvm_unmap_remove() must walk the entries in the region twice.  It cannot
>    do unmapping work until it knows the region is completely muteable.  This
>    might turn into a performance issue.
> 
> 5. binutils ld support completely untested, I mainly went in there to fix
>    objdump and readelf.
> 
> 6. It would be nice to hear of a pkg that actually has a problem with this
>    change.  I haven't found any yet but don't run many myself.
> 
> If anyone wants to debug issues, uncomment the // _dl_printf's in ld.so,
> and expect a lot of noise.  Then do something like "ktrace -di program
> >& log", and generate a kdump seperately.  It also helps if you test
> with programs that don't exit, so you can procmap -a -p $pid.  In the
> kdump output, it is important to look for "mprotect -1", because that
> provides evidence of the worst (silent) problems...

Oops, 1 line error in the diff, try this instead.

And to point 1 above, notice that a rare page of shared library mapping
is not immutable, right on the edge of the relro...

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   2 Sep 2022 15:23:20 -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 2 Sep 2022 21:53:22 -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/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      10 Sep 2022 07:06:59 -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_MUTABLEIZE
+     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_MUTABLEIZE;
+      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     10 Sep 2022 07:06:03 -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   10 Sep 2022 07:42:26 -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    10 Sep 2022 07:05:28 -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 10 Sep 2022 06:53:29 -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        10 Sep 2022 06:50:24 
-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      10 Sep 2022 07:41:49 
-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       10 Sep 2022 07:05:26 -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      10 Sep 2022 10:56:42 -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      3 Sep 2022 14:03:43 -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.75
diff -u -p -u -r1.75 Symbols.list
--- lib/libc/Symbols.list       2 Aug 2022 16:45:00 -0000       1.75
+++ lib/libc/Symbols.list       24 Aug 2022 00:39:15 -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
@@ -325,6 +326,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  30 Aug 2022 23:54:47 -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    3 Sep 2022 14:01:22 -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.163
diff -u -p -u -r1.163 Makefile.inc
--- lib/libc/sys/Makefile.inc   17 Jul 2022 03:04:27 -0000      1.163
+++ lib/libc/sys/Makefile.inc   24 Aug 2022 00:33:59 -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 \
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      31 Aug 2022 13:49:31 -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     10 Sep 2022 18:55:55 -0000
@@ -95,6 +95,113 @@ unload:
        }
 }
 
+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_mutable(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 || (im->start == 0 && im->end == 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);
+       }
+}
+
 elf_object_t *
 _dl_tryload_shlib(const char *libname, int type, int flags)
 {
@@ -212,6 +319,7 @@ _dl_tryload_shlib(const char *libname, i
        phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
 
        for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
+
                switch (phdp->p_type) {
                case PT_LOAD: {
                        char *start = (char *)(TRUNC_PG(phdp->p_vaddr)) + loff;
@@ -328,6 +436,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_mutable(object, loff);
        } else {
                _dl_munmap((void *)libaddr, maxva - minva);
                _dl_load_list_free(load_list);
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      10 Sep 2022 16:28:48 -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_mutable(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_mutable(object, object->obj_base);
+       }
 
        object->status |= STAT_INIT_DONE;
 }
@@ -979,4 +991,3 @@ _dl_rreloc(elf_object_t *object)
                }
        }
 }
-
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     10 Sep 2022 16:25:23 -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,8 @@ 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_apply_mutable(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 31 Aug 2022 06:56:02 -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     30 Aug 2022 08:10:24 -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     10 Sep 2022 16:34:00 -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       10 Sep 2022 11:33:46 -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: 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 10 Sep 2022 06:41:33 -0000
@@ -189,11 +189,16 @@ 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 will take care of those if 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 +437,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 +663,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        3 Sep 2022 13:51:09 -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);
@@ -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      10 Sep 2022 05:37:44 -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        3 Sep 2022 06:45:22 -0000
@@ -863,6 +863,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 +913,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      9 Sep 2022 12:56:14 -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/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 10 Sep 2022 05:37:44 -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    10 Sep 2022 05:37:42 -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      2 Sep 2022 20:06:23 -0000
@@ -93,6 +93,7 @@ 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 */
@@ -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  2 Sep 2022 09:13:17 -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      31 Aug 2022 05:11:09 -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   10 Sep 2022 05:37:44 -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       10 Sep 2022 05:37:44 -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.69
diff -u -p -u -r1.69 uvm.h
--- sys/uvm/uvm.h       4 May 2022 14:58:26 -0000       1.69
+++ sys/uvm/uvm.h       24 Aug 2022 00:58:32 -0000
@@ -81,8 +81,6 @@ struct uvm {
 
 /*
  * vm_map_entry etype bits:
- *
- * keep in sync with KVM_ET_*
  */
 #define UVM_ET_OBJ             0x0001  /* it is a uvm_object */
 #define UVM_ET_SUBMAP          0x0002  /* it is a vm_map submap */
@@ -94,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_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    24 Aug 2022 00:32:40 -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   10 Sep 2022 18:52:16 -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);
@@ -1984,6 +1997,23 @@ uvm_unmap_remove(struct vm_map *map, vad
        else
                UVM_MAP_CLIP_START(map, entry, 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;
+                       }
+               }
+       }
+
        /*
         * Iterate entries until we reach end address.
         * prev_hint hints where the freed space can be appended to.
@@ -2043,6 +2073,7 @@ uvm_unmap_remove(struct vm_map *map, vad
                        KDASSERT(uvm_map_entrybyaddr(&map->addr, a) == NULL);
        }
 #endif
+       return 0;
 }
 
 /*
@@ -3098,6 +3129,13 @@ uvm_map_protect(struct vm_map *map, vadd
                if (iter->start == iter->end || UVM_ET_ISHOLE(iter))
                        continue;
 
+               if ((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 +3394,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 +3567,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 +4126,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 +4221,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 +4451,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   3 Sep 2022 06:46:38 -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  3 Sep 2022 06:49:27 -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);
@@ -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.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  24 Aug 2022 02:09:17 -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