Re: immutable userland mappings
Theo de Raadt wrote: > Theo de Raadt wrote: > > > > Yet another version of the diff as I incrementally get it working better. > > > Call it version 22.. > > This is around version 30. New version. uvm_unmap_remove() now avoids doing entry splits as it scans for immutables in the region. Lots of // debug code remains, because there is a hunt for a linker bug; some libraries are created subtly incorrectly, and it would be better if they were correct and we could rip out some workarounds. Index: gnu/llvm/lld/ELF/ScriptParser.cpp === RCS file: /cvs/src/gnu/llvm/lld/ELF/ScriptParser.cpp,v retrieving revision 1.1.1.4 diff -u -p -u -r1.1.1.4 ScriptParser.cpp --- gnu/llvm/lld/ELF/ScriptParser.cpp 17 Dec 2021 12:25:02 - 1.1.1.4 +++ gnu/llvm/lld/ELF/ScriptParser.cpp 17 Sep 2022 13:11:25 - @@ -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 - 1.3 +++ gnu/llvm/lld/ELF/Writer.cpp 17 Sep 2022 13:11:25 - @@ -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 Writer::c part.ehFrame->getParent() && part.ehFrameHdr->getParent()) addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) ->add(part.ehFrameHdr->getParent()); + + // PT_OPENBSD_MUTABLE is an OpenBSD-specific feature. That makes + // the dynamic linker fill the segment with zero data, like bss, but + // it can be treated differently. + if (OutputSection *cmd = findSection(".openbsd.mutable", partNo)) +addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. Index: gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h === RCS file: /cvs/src/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h,v retrieving revision 1.1.1.3 diff -u -p -u -r1.1.1.3 ELF.h --- gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h 17 Dec 2021 12:23:22 - 1.1.1.3 +++ gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h 17 Sep 2022 13:11:25 - @@ -1303,6 +1303,7 @@ enum { PT_GNU_RELRO = 0x6474e552,// Read-only after relocation. PT_GNU_PROPERTY = 0x6474e553, // .note.gnu.property notes sections. + PT_OPENBSD_MUTABLE = 0x65a3dbe5, // Like bss, but not immutable. PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data. PT_OPENBSD_WXNEEDED = 0x65a3dbe7, // Program does W^X violations. PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments. Index: gnu/usr.bin/binutils/bfd/elf.c === RCS file: /cvs/src/gnu/usr.bin/binutils/bfd/elf.c,v retrieving revision 1.23 diff -u -p -u -r1.23 elf.c --- gnu/usr.bin/binutils/bfd/elf.c 13 Jan 2015 20:05:01 - 1.23 +++ gnu/usr.bin/binutils/bfd/elf.c 17 Sep 2022 13:11:25 - @@ -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 off0x", 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
Re: immutable userland mappings
On Thu, Sep 15, 2022 at 08:31:06AM -0600, Theo de Raadt wrote: > RCS file: lib/libc/sys/mimmutable.2 ... > +Unmapped pages in the region do not retain immutability, but this > +behaviour should not be relied up. s/relied up/relied on/ or s/relied up/relied upon/
Re: immutable userland mappings
Theo de Raadt wrote: > > Yet another version of the diff as I incrementally get it working better. > > Call it version 22.. This is around version 30. There is still a subtle problem with RELRO, but it is masked with a hack. arm64 also works correctly, and I'm onto the next architecture. Systems using bfd.ld need to be checked also. There's a weird piece of logic related to "libraries that never unload", I am not sure I did it right. man page changes included. Transition steps are: make new kernel, install, reboot [you will see uvm_unmap errors for various programs in dmesg] make includes cd gnu/usr.bin/clang; make && make install make backup copies of /usr/libexec/ld.so and the most recent libc.so build and install ld.so [you will now see uvm_map_protect errors in dmesg] build and install libc.so [the messages should go away] build everything 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 - 1.1.1.4 +++ gnu/llvm/lld/ELF/ScriptParser.cpp 2 Sep 2022 15:23:20 - @@ -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 - 1.3 +++ gnu/llvm/lld/ELF/Writer.cpp 2 Sep 2022 21:53:22 - @@ -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 Writer::c part.ehFrame->getParent() && part.ehFrameHdr->getParent()) addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) ->add(part.ehFrameHdr->getParent()); + + // PT_OPENBSD_MUTABLE is an OpenBSD-specific feature. That makes + // the dynamic linker fill the segment with zero data, like bss, but + // it can be treated differently. + if (OutputSection *cmd = findSection(".openbsd.mutable", partNo)) +addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. Index: gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h === RCS file: /cvs/src/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h,v retrieving revision 1.1.1.3 diff -u -p -u -r1.1.1.3 ELF.h --- gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h 17 Dec 2021 12:23:22 - 1.1.1.3 +++ gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h 14 Sep 2022 13:01:42 - @@ -1303,6 +1303,7 @@ enum { PT_GNU_RELRO = 0x6474e552,// Read-only after relocation. PT_GNU_PROPERTY = 0x6474e553, // .note.gnu.property notes sections. + PT_OPENBSD_MUTABLE = 0x65a3dbe5, // Like bss, but not immutable. PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data. PT_OPENBSD_WXNEEDED = 0x65a3dbe7, // Program does W^X violations. PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments. Index: gnu/usr.bin/binutils/bfd/elf.c === RCS file: /cvs/src/gnu/usr.bin/binutils/bfd/elf.c,v retrieving revision 1.23 diff -u -p -u -r1.23 elf.c --- gnu/usr.bin/binutils/bfd/elf.c 13 Jan 2015 20:05:01 - 1.23 +++ gnu/usr.bin/binutils/bfd/elf.c 14 Sep 2022 13:00:27 - @@ -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 off0x", p
Re: immutable userland mappings
Theo de Raadt wrote: > Theo de Raadt wrote: > > > Theo de Raadt 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 - 1.1.1.4 +++ gnu/llvm/lld/ELF/ScriptParser.cpp 2 Sep 2022 15:23:20 - @@ -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 - 1.3 +++ gnu/llvm/lld/ELF/Writer.cpp 2 Sep 2022 21:53:22 - @@ -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 Writer::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.
Re: immutable userland mappings
Theo de Raadt wrote: > Theo de Raadt 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... 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 - 1.1.1.4 +++ gnu/llvm/lld/ELF/ScriptParser.cpp 2 Sep 2022 15:23:20 - @@ -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 - 1.3 +++ gnu/llvm/lld/ELF/Writer.cpp 2 Sep 2022 21:53:22 - @@ -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 Writer::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 - 1.23 +++ gnu/usr.bin/binutils/bfd/elf.c 10 Sep 2022 07:06:59 - @@ -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 =
Re: immutable userland mappings
Theo de Raadt 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. I have mostly succeeded at changing this to a better model. The previous version had a real difficult time finding the specific objects which cannot become immutable, so I found a way to describe them to the kernel. The ELF program headers now contain a new PHDR for section ".openbsd.mutable", aka OPENBSD_MUTABLE. This is placed on the malloc self-protected bookkeeping page. When the main binary & ld.so are loaded the kernel can make all LOAD regions immutable, and then in a later pass the kernel is permitted to undo the immutable on the OPENBSD_MUTABLE and GNU_RELRO regions. Only the kernel can undo immutability, in these specific cases. When crt0 finishes RELRO adjustment and mprotects PROT_READ, it also marks the region immutable. ld.so does the same for it's RELRO. The libc malloc self-protection scheme can mprotect RW and R back and forth when it wants, and it will never make this region immutable. When ld.so loads a library, it creates a queue of immutable and mutable work actions to do after the library is done. ld.so cannot reverse an immutable, so it must clip the mutable regions out of the immutables. This clip piece of the diff is embarrassingly poor. It is very forgiving, which is why I can run multiuser. I do know that the system libraries are clean, and anyways the big problems were with the malloc, relro, main programs, and ld.so, not the other libraries This version is harder to cross compile through, but I wanted to show in case someone is interested. There are numberous gaps (binutils lacks support, other architectures, but the worst part is the immutuble clipping code. 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 -r1.1.1.4 ScriptParser.cpp --- gnu/llvm/lld/ELF/ScriptParser.cpp 17 Dec 2021 12:25:02 - 1.1.1.4 +++ gnu/llvm/lld/ELF/ScriptParser.cpp 2 Sep 2022 15:23:20 - @@ -1478,6 +1478,7 @@ .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 -r1.3 Writer.cpp --- gnu/llvm/lld/ELF/Writer.cpp 17 Dec 2021 14:46:47 - 1.3 +++ gnu/llvm/lld/ELF/Writer.cpp 2 Sep 2022 21:53:22 - @@ -146,7 +146,7 @@ {".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 @@ part.ehFrame->getParent() && part.ehFrameHdr->getParent()) addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) ->add(part.ehFrameHdr->getParent()); + + // PT_OPENBSD_MUTABLE is an OpenBSD-specific feature. That makes + // the dynamic linker fill the segment with zero data, like bss, but + // it can be treated differently. + if (OutputSection *cmd = findSection(".openbsd.mutable", partNo)) +addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. Index: gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h === RCS file: /cvs/src/gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h,v retrieving revision 1.1.1.3 diff -u -r1.1.1.3 ELF.h --- gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h 17 Dec 2021 12:23:22 - 1.1.1.3 +++ gnu/llvm/llvm/include/llvm/BinaryFormat/ELF.h 2 Sep 2022 12:12:47 - @@ -1303,6 +1303,7 @@ PT_GNU_RELRO = 0x6474e552,// Read-only after relocation. PT_GNU_PROPERTY = 0x6474e553, // .note.gnu.property notes sections. + PT_OPENBSD_MUTABLE = 0x65a3dbe5, // Like bss, but not immutable PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data. PT_OPENBSD
immutable userland mappings
In the last few years, I have been improving the strictness of userland memory layout. An example is the recent addition of MAP_STACK and msyscall(). The first one marks pages that are stack, so that upon entry to the kernel we can check if the stack-pointer is pointing in the stack range. If it isn't, the most obvious conclusion is that a ROP pivot has occured, and we kills the process. The second one marks the region which contains syscall traps, if upon entry to the kernel the PC is not in that region, we know somone is trying to do system calls via an unapproved method. My next attempt is to lock memory mappings. The current working name is mimmutable(void *addr, size_t len). This identifies all current mapped memory in a region, and tags the mappings. Such mappings can never be unmapped. No new mmap can be done on top of the mappings. And the permissions cannot be changed. Other than that, the underlying storage memory works fine, it is just the mapping that is locked. I'm aware of an method used at least once (not on openbsd) which managed to mprotect a region of libc, and then place things there, for later execution. That makes msyscall() less useful, so I want to restore the strenth. 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. So for now, crt0 self-immutables the remaining parts, and ld.so does the same for itself. ld.so is also responsible for immutable marking on libraries it loads. To my surprise, the diff is working quite well. With kern.allowkmem=1, "procmap -a" can see what process mappings look like, and they are quite locked down. This is a view of a "sed", with 'grep -v anon'. The "I" marker indicates mapping immutability. A few small chunks must still be fixed. StartEnd Size Offset rwxSeIpc RWX I/W/A Dev Inode - File 03128621a000-03128621cfff 12k rIp+ (rwx) 1/0/0 04:05 77840 - /usr/bin/sed [0xfd83e38b3640] 03128621d000-031286222fff 24k 2000 r-x--Ip+ (rwx) 1/0/0 04:05 77840 - /usr/bin/sed [0xfd83e38b3640] 03148bbc3000-03148bbc3fff 4k rIs- (r--) 1/0/1 00:00 0 - [ uvm_aobj ] 0314ea4e7000-0314ea51dfff 220k rIp+ (rwx) 1/0/0 04:05 103688 - /usr/lib/libc.so.96.1 [0xfd83e0c62608] 0314ea51e000-0314ea5c2fff 660k 00036000 r-x-eIp+ (rwx) 1/0/0 04:05 103688 - /usr/lib/libc.so.96.1 [0xfd83e0c62608] 0314ea5c3000-0314ea5c8fff 24k 000da000 rIp- (rwx) 1/0/0 04:05 103688 - /usr/lib/libc.so.96.1 [0xfd83e0c62608] 0314ea5c9000-0314ea5cbfff 12k 000df000 rw---Ip- (rwx) 1/0/0 04:05 103688 - /usr/lib/libc.so.96.1 [0xfd83e0c62608] 031526544000-031526544fff 4k r-x-eIp+ (rwx) 1/0/1 00:00 0 - [ uvm_aobj ] 031535da7000-031535da9fff 12k rIp+ (rwx) 1/0/0 04:05 336963 - /usr/libexec/ld.so [0xfd83e27f90e8] 031535eac000-031535eb6fff 44k 5000 r-x-eIp+ (rwx) 1/0/0 04:05 336963 - /usr/libexec/ld.so [0xfd83e27f90e8] 031535fa7000-031535fa7fff 4k 0001 r-p- (rwx) 1/0/0 04:05 336963 - /usr/libexec/ld.so [0xfd83e27f90e8] 031535fa8000-031535fa8fff 4k 00011000 rwp- (rwx) 1/0/0 04:05 336963 - /usr/libexec/ld.so [0xfd83e27f90e8] 03154a19e000-03154a1b1fff 80k rIp+ (rwx) 1/0/0 04:04 3654731 - /var/run/ld.so.hints [0xfd83e1098960] 7f7ffdebd000-7f7fffbbcfff 29696k --p+ (rwx) 1/0/0 00:00 0 - [ stack ] total 5724k I wanted to show it a bit early. To try the diff: - apply patch - cd /usr/src/sys/kern; make syscalls - build and boot new kernel - cd /usr/src; make includes - cd lib/libc; make && make install - cd /usr/src/*/ld.so; make && make install - cd /usr/src/lib/csu; make && make install - then other binaries can be built, including procmap 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 - 1.33 +++ lib/csu/boot.h 31 Aug 2022 05:14:09 - @@ -35,7 +35,6 @@ #define_DYN_LOADER #include -#include #include @@ -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 typedefE