Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -519,6 +519,29 @@ } } +// The InX::BssRelRo inserts a .bss.rel.ro sections into the parent +// Section. As .bss.rel.ro can easily match in a linker script with +// the pattern *(.bss.*) we have two cases to handle: +// 1.) There are no .bss.rel.ro sections, we are non relro. +// 2.) There is at least one .bss.rel.ro and at least one non +// .bss.rel.ro, give an error message. +static bool isBssRelRoContents(const OutputSection *Sec) { + bool HaveRelRo = false; + bool HaveNonRelRo = false; + for (BaseCommand *Base : Sec->SectionCommands) + if (auto *ISD = dyn_cast(Base)) { + for (InputSection *&IS : ISD->Sections) + if (isa(IS) && IS->Name == ".bss.rel.ro") + HaveRelRo = true; + else + HaveNonRelRo = true; + } + if (HaveRelRo && HaveNonRelRo) + error("section: " + Sec->Name + " has mix of relro and non relro" + + " sections"); + return HaveRelRo; +} + // Today's loaders have a feature to make segments read-only after // processing dynamic relocations to enhance security. PT_GNU_RELRO // is defined for that. @@ -576,20 +599,26 @@ if (Sec == InX::Dynamic->getParent()) return true; - // .bss.rel.ro is used for copy relocations for read-only symbols. - // Since the dynamic linker needs to process copy relocations, the - // section cannot be read-only, but once initialized, they shouldn't - // change. - if (Sec == InX::BssRelRo->getParent()) - return true; - // Sections with some special names are put into RELRO. This is a // bit unfortunate because section names shouldn't be significant in // ELF in spirit. But in reality many linker features depend on // magic section names. StringRef S = Sec->Name; - return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || - S == ".eh_frame" || S == ".openbsd.randomdata"; + if (S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || + S == ".eh_frame" || S == ".openbsd.randomdata") + return true; + + // .bss.rel.ro is used for copy relocations for read-only symbols. + // Since the dynamic linker needs to process copy relocations, the + // section cannot be read-only, but once initialized, they shouldn't + // change. + if (Sec == InX::BssRelRo->getParent()) { + if (!Script->HasSectionsCommand || Sec->Name == ".bss.rel.ro") + return true; + return isBssRelRoContents(Sec); + } + + return false; } // We compute a rank for each section. The rank indicates where the Index: test/ELF/relro-copyrel-bss-script-error.s =================================================================== --- /dev/null +++ test/ELF/relro-copyrel-bss-script-error.s @@ -0,0 +1,31 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/copy-in-shared.s -o %t2.o +// RUN: ld.lld -shared %t.o %t2.o -o %t.so + +// A linker script that will map .bss.rel.ro into .bss. Error if we mix relro +// and non relro .bss +// RUN: echo "SECTIONS { \ +// RUN: .bss : { *(.bss) *(.bss.*) } \ +// RUN: } " > %t.script + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t3.o +// RUN: not ld.lld %t3.o %t.so -z relro -o %t --script=%t.script 2>&1 | FileCheck %s + +// CHECK: error: section: .bss has mix of relro and non relro sections + .section .text, "ax", @progbits + .global bar + .global foo + .global _start +_start: + callq bar + .quad foo + + .data + .space 4 + + // Non relro bss + .bss + // make large enough to affect PT_GNU_RELRO MemSize if this was marked + // as relro. + .space 0x2000 Index: test/ELF/relro-copyrel-bss-script.s =================================================================== --- /dev/null +++ test/ELF/relro-copyrel-bss-script.s @@ -0,0 +1,37 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// A linker script that will map .bss.rel.ro into .bss. If we don't have any +// .bss.rel.ro then we don't want to mark .bss as being relro. +// RUN: echo "SECTIONS { \ +// RUN: .bss : { *(.bss) *(.bss.*) } \ +// RUN: } " > %t.script + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o +// RUN: ld.lld %t2.o %t.so -z relro -o %t --script=%t.script +// RUN: llvm-readobj --program-headers %t | FileCheck %s + .section .text, "ax", @progbits + .global _start +_start: + callq bar + + .data + .space 4 + + // Non relro bss + .bss + // make large enough to affect PT_GNU_RELRO MemSize if this was marked + // as relro. + .space 0x2000 + +// CHECK: Type: PT_GNU_RELRO (0x6474E552) +// CHECK-NEXT: Offset: +// CHECK-NEXT: VirtualAddress: +// CHECK-NEXT: PhysicalAddress: +// CHECK-NEXT: FileSize: +// CHECK-NEXT: MemSize: 4096 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 1 +// CHECK-NEXT: }