- Merge '.openbsd.randomdata.*' sections into a single '.openbsd.randomdata' section when linking, as we do when using ld from binutils. - Generate __data_start symbol that marks the start of .data when __data_start is referenced from code being linked. - Put .got.plt in RELRO. - On i386, produce binaries that are compatible with our W^X implementation. - In the linkers, collect objects in section "openbsd.mutable" and place them into a page-aligned region in the bss, with the right markers for kernel/ld.so to identify the region and skip making it immutable. - Implement support for PT_OPENBSD_NOBTCFI in lld(1). This can be set using the -z nobtcfi option. Index: tools/lld/ELF/Writer.cpp --- tools/lld/ELF/Writer.cpp.orig +++ tools/lld/ELF/Writer.cpp @@ -145,7 +145,8 @@ StringRef elf::getOutputSectionName(const InputSection for (StringRef v : {".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."}) + ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab.", + ".openbsd.randomdata.", ".openbsd.mutable." }) if (isSectionPrefix(v, s->name)) return v.drop_back(); @@ -324,6 +325,7 @@ void elf::addReservedSymbols() { }; ElfSym::bss = add("__bss_start", 0); + ElfSym::data = add("__data_start", 0); ElfSym::end1 = add("end", -1); ElfSym::end2 = add("_end", -1); ElfSym::etext1 = add("etext", -1); @@ -883,7 +885,11 @@ static bool isRelroSection(const OutputSection *sec) { // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. if (sec == in.gotPlt->getParent()) +#ifndef __OpenBSD__ return config->zNow; +#else + return true; /* kbind(2) means we can always put these in RELRO */ +#endif // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put @@ -1193,6 +1199,9 @@ template void Writer::setReservedSy if (ElfSym::bss) ElfSym::bss->section = findSection(".bss"); + if (ElfSym::data) + ElfSym::data->section = findSection(".data"); + // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (ElfSym::mipsGp) { @@ -2461,6 +2470,12 @@ std::vector Writer::createPhdrs(Par 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. if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo)) @@ -2484,6 +2499,11 @@ std::vector Writer::createPhdrs(Par if (config->zWxneeded) addHdr(PT_OPENBSD_WXNEEDED, PF_X); + // PT_OPENBSD_NOBTCFI is an OpenBSD-specific header to mark that the + // executable is expected to violate branch-target CFI checks. + if (config->zNoBtCfi) + addHdr(PT_OPENBSD_NOBTCFI, PF_X); + if (OutputSection *cmd = findSection(".note.gnu.property", partNo)) addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd); @@ -2576,6 +2596,31 @@ template void Writer::fixSectionAli }; } }; + +#ifdef __OpenBSD__ + // On i386, produce binaries that are compatible with our W^X implementation + if (config->emachine == EM_386) { + auto NXAlign = [](OutputSection *Cmd) { + if (Cmd && !Cmd->addrExpr) + Cmd->addrExpr = [=] { + return alignTo(script->getDot(), 0x20000000); + }; + }; + + for (Partition &part : partitions) { + PhdrEntry *firstRW = nullptr; + for (PhdrEntry *P : part.phdrs) { + if (P->p_type == PT_LOAD && (P->p_flags & PF_W)) { + firstRW = P; + break; + } + } + + if (firstRW) + NXAlign(firstRW->firstSec); + } + } +#endif for (Partition &part : partitions) { prev = nullptr;