Theo de Raadt <[email protected]> wrote:
> Theo de Raadt <[email protected]> wrote:
>
> > Theo de Raadt <[email protected]> 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' : '-',