[ELF] Align the end of PT_GNU_RELRO associated PT_LOAD to a common-page-size boundary (#66042)
Close #57618: currently we align the end of PT_GNU_RELRO to a common-page-size boundary, but do not align the end of the associated PT_LOAD. This is benign when runtime_page_size >= common-page-size. However, when runtime_page_size < common-page-size, it is possible that `alignUp(end(PT_LOAD), page_size) < alignDown(end(PT_GNU_RELRO), page_size)`. In this case, rtld's mprotect call for PT_GNU_RELRO will apply to unmapped regions and lead to an error, e.g. ``` error while loading shared libraries: cannot apply additional memory protection after relocation: Cannot allocate memory ``` To fix the issue, add a padding section .relro_padding like mold, which is contained in the PT_GNU_RELRO segment and the associated PT_LOAD segment. The section also prevents strip from corrupting PT_LOAD program headers. .relro_padding has the largest `sortRank` among RELRO sections. Therefore, it is naturally placed at the end of `PT_GNU_RELRO` segment in the absence of `PHDRS`/`SECTIONS` commands. In the presence of `SECTIONS` commands, we place .relro_padding immediately before a symbol assignment using DATA_SEGMENT_RELRO_END (see also https://reviews.llvm.org/D124656), if present. DATA_SEGMENT_RELRO_END is changed to align to max-page-size instead of common-page-size. Some edge cases worth mentioning: * ppc64-toc-addis-nop.s: when PHDRS is present, do not append .relro_padding * avoid-empty-program-headers.s: when the only RELRO section is .tbss, it is not part of PT_LOAD segment, therefore we do not append .relro_padding. --- Close #65002: GNU ld from 2.39 onwards aligns the end of PT_GNU_RELRO to a max-page-size boundary (https://sourceware.org/PR28824) so that the last page is protected even if runtime_page_size > common-page-size. In my opinion, losing protection for the last page when the runtime page size is larger than common-page-size is not really an issue. Double mapping a page of up to max-common-page for the protection could cause undesired VM waste. Internally we had users complaining about 2MiB max-page-size applying to shared objects. Therefore, the end of .relro_padding is padded to a common-page-size boundary. Users who are really anxious can set common-page-size to match their runtime page size. --- 17 tests need updating as there are lots of change detectors.
This commit is contained in:
@@ -1586,8 +1586,8 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
|
||||
// Page alignment can be disabled by the -n (--nmagic) and -N (--omagic).
|
||||
// As PT_GNU_RELRO relies on Paging, do not create it when we have disabled
|
||||
// it.
|
||||
if (config->nmagic || config->omagic)
|
||||
// it. Also disable RELRO for -r.
|
||||
if (config->nmagic || config->omagic || config->relocatable)
|
||||
config->zRelro = false;
|
||||
|
||||
std::tie(config->buildId, config->buildIdVector) = getBuildId(args);
|
||||
|
||||
@@ -887,6 +887,10 @@ void LinkerScript::diagnoseOrphanHandling() const {
|
||||
if (config->orphanHandling == OrphanHandlingPolicy::Place)
|
||||
return;
|
||||
for (const InputSectionBase *sec : orphanSections) {
|
||||
// .relro_padding is inserted before DATA_SEGMENT_RELRO_END, if present,
|
||||
// automatically. The section is not supposed to be specified by scripts.
|
||||
if (sec == in.relroPadding.get())
|
||||
continue;
|
||||
// Input SHT_REL[A] retained by --emit-relocs are ignored by
|
||||
// computeInputSections(). Don't warn/error.
|
||||
if (isa<InputSection>(sec) &&
|
||||
@@ -1079,6 +1083,11 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
}
|
||||
}
|
||||
|
||||
// If .relro_padding is present, round up the end to a common-page-size
|
||||
// boundary to protect the last page.
|
||||
if (in.relroPadding && sec == in.relroPadding->getParent())
|
||||
expandOutputSection(alignToPowerOf2(dot, config->commonPageSize) - dot);
|
||||
|
||||
// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
|
||||
// as they are not part of the process image.
|
||||
if (!(sec->flags & SHF_ALLOC)) {
|
||||
@@ -1160,6 +1169,7 @@ void LinkerScript::adjustOutputSections() {
|
||||
uint64_t flags = SHF_ALLOC;
|
||||
|
||||
SmallVector<StringRef, 0> defPhdrs;
|
||||
bool seenRelro = false;
|
||||
for (SectionCommand *&cmd : sectionCommands) {
|
||||
if (!isa<OutputDesc>(cmd))
|
||||
continue;
|
||||
@@ -1196,9 +1206,17 @@ void LinkerScript::adjustOutputSections() {
|
||||
if (sec->sectionIndex != UINT32_MAX)
|
||||
maybePropagatePhdrs(*sec, defPhdrs);
|
||||
|
||||
// Discard .relro_padding if we have not seen one RELRO section. Note: when
|
||||
// .tbss is the only RELRO section, there is no associated PT_LOAD segment
|
||||
// (needsPtLoad), so we don't append .relro_padding in the case.
|
||||
if (in.relroPadding && in.relroPadding->getParent() == sec && !seenRelro)
|
||||
discardable = true;
|
||||
if (discardable) {
|
||||
sec->markDead();
|
||||
cmd = nullptr;
|
||||
} else {
|
||||
seenRelro |=
|
||||
sec->relro && !(sec->type == SHT_NOBITS && (sec->flags & SHF_TLS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,9 @@ struct SymbolAssignment : SectionCommand {
|
||||
bool provide = false;
|
||||
bool hidden = false;
|
||||
|
||||
// This assignment references DATA_SEGMENT_RELRO_END.
|
||||
bool dataSegmentRelroEnd = false;
|
||||
|
||||
unsigned symOrder;
|
||||
|
||||
// Holds file name and line number for error reporting.
|
||||
@@ -352,6 +355,8 @@ public:
|
||||
SmallVector<PhdrsCommand, 0> phdrsCommands;
|
||||
|
||||
bool hasSectionsCommand = false;
|
||||
bool seenDataAlign = false;
|
||||
bool seenRelroEnd = false;
|
||||
bool errorOnMissingSection = false;
|
||||
|
||||
// List of section patterns specified with KEEP commands. They will
|
||||
|
||||
@@ -136,9 +136,6 @@ private:
|
||||
// True if a script being read is in the --sysroot directory.
|
||||
bool isUnderSysroot = false;
|
||||
|
||||
bool seenDataAlign = false;
|
||||
bool seenRelroEnd = false;
|
||||
|
||||
// A set to detect an INCLUDE() cycle.
|
||||
StringSet<> seen;
|
||||
};
|
||||
@@ -600,7 +597,7 @@ void ScriptParser::readSections() {
|
||||
|
||||
// If DATA_SEGMENT_RELRO_END is absent, for sections after DATA_SEGMENT_ALIGN,
|
||||
// the relro fields should be cleared.
|
||||
if (!seenRelroEnd)
|
||||
if (!script->seenRelroEnd)
|
||||
for (SectionCommand *cmd : v)
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
osd->osec.relro = false;
|
||||
@@ -916,7 +913,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
||||
script->createOutputSection(unquote(outSec), getCurrentLocation());
|
||||
OutputSection *osec = &cmd->osec;
|
||||
// Maybe relro. Will reset to false if DATA_SEGMENT_RELRO_END is absent.
|
||||
osec->relro = seenDataAlign && !seenRelroEnd;
|
||||
osec->relro = script->seenDataAlign && !script->seenRelroEnd;
|
||||
|
||||
size_t symbolsReferenced = script->referencedSymbols.size();
|
||||
|
||||
@@ -1051,6 +1048,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
|
||||
|
||||
size_t oldPos = pos;
|
||||
SymbolAssignment *cmd = nullptr;
|
||||
bool savedSeenRelroEnd = script->seenRelroEnd;
|
||||
const StringRef op = peek();
|
||||
if (op.starts_with("=")) {
|
||||
// Support = followed by an expression without whitespace.
|
||||
@@ -1071,6 +1069,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
|
||||
}
|
||||
|
||||
if (cmd) {
|
||||
cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && script->seenRelroEnd;
|
||||
cmd->commandString =
|
||||
tok.str() + " " +
|
||||
llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " ");
|
||||
@@ -1439,7 +1438,7 @@ Expr ScriptParser::readPrimary() {
|
||||
expect(",");
|
||||
readExpr();
|
||||
expect(")");
|
||||
seenDataAlign = true;
|
||||
script->seenDataAlign = true;
|
||||
return [=] {
|
||||
uint64_t align = std::max(uint64_t(1), e().getValue());
|
||||
return (script->getDot() + align - 1) & -align;
|
||||
@@ -1460,9 +1459,8 @@ Expr ScriptParser::readPrimary() {
|
||||
expect(",");
|
||||
readExpr();
|
||||
expect(")");
|
||||
seenRelroEnd = true;
|
||||
Expr e = getPageSize();
|
||||
return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); };
|
||||
script->seenRelroEnd = true;
|
||||
return [=] { return alignToPowerOf2(script->getDot(), config->maxPageSize); };
|
||||
}
|
||||
if (tok == "DEFINED") {
|
||||
StringRef name = unquote(readParenLiteral());
|
||||
|
||||
@@ -2688,6 +2688,10 @@ size_t IBTPltSection::getSize() const {
|
||||
|
||||
bool IBTPltSection::isNeeded() const { return in.plt->getNumEntries() > 0; }
|
||||
|
||||
RelroPaddingSection::RelroPaddingSection()
|
||||
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1, ".relro_padding") {
|
||||
}
|
||||
|
||||
// The string hash function for .gdb_index.
|
||||
static uint32_t computeGdbHash(StringRef s) {
|
||||
uint32_t h = 0;
|
||||
@@ -3839,6 +3843,7 @@ void InStruct::reset() {
|
||||
got.reset();
|
||||
gotPlt.reset();
|
||||
igotPlt.reset();
|
||||
relroPadding.reset();
|
||||
armCmseSGSection.reset();
|
||||
ppc64LongBranchTarget.reset();
|
||||
mipsAbiFlags.reset();
|
||||
|
||||
@@ -778,6 +778,16 @@ public:
|
||||
size_t getSize() const override;
|
||||
};
|
||||
|
||||
// Used to align the end of the PT_GNU_RELRO segment and the associated PT_LOAD
|
||||
// segment to a common-page-size boundary. This padding section ensures that all
|
||||
// pages in the PT_LOAD segment is covered by at least one section.
|
||||
class RelroPaddingSection final : public SyntheticSection {
|
||||
public:
|
||||
RelroPaddingSection();
|
||||
size_t getSize() const override { return 0; }
|
||||
void writeTo(uint8_t *buf) override {}
|
||||
};
|
||||
|
||||
class GdbIndexSection final : public SyntheticSection {
|
||||
public:
|
||||
struct AddressEntry {
|
||||
@@ -1333,6 +1343,7 @@ struct InStruct {
|
||||
std::unique_ptr<GotSection> got;
|
||||
std::unique_ptr<GotPltSection> gotPlt;
|
||||
std::unique_ptr<IgotPltSection> igotPlt;
|
||||
std::unique_ptr<RelroPaddingSection> relroPadding;
|
||||
std::unique_ptr<SyntheticSection> armCmseSGSection;
|
||||
std::unique_ptr<PPC64LongBranchTargetSection> ppc64LongBranchTarget;
|
||||
std::unique_ptr<SyntheticSection> mipsAbiFlags;
|
||||
|
||||
@@ -458,6 +458,13 @@ template <class ELFT> void elf::createSyntheticSections() {
|
||||
add(*in.gotPlt);
|
||||
in.igotPlt = std::make_unique<IgotPltSection>();
|
||||
add(*in.igotPlt);
|
||||
// Add .relro_padding if DATA_SEGMENT_RELRO_END is used; otherwise, add the
|
||||
// section in the absence of PHDRS/SECTIONS commands.
|
||||
if (config->zRelro && ((script->phdrsCommands.empty() &&
|
||||
!script->hasSectionsCommand) || script->seenRelroEnd)) {
|
||||
in.relroPadding = std::make_unique<RelroPaddingSection>();
|
||||
add(*in.relroPadding);
|
||||
}
|
||||
|
||||
if (config->emachine == EM_ARM) {
|
||||
in.armCmseSGSection = std::make_unique<ArmCmseSGSection>();
|
||||
@@ -818,6 +825,9 @@ static bool isRelroSection(const OutputSection *sec) {
|
||||
if (sec == in.gotPlt->getParent())
|
||||
return config->zNow;
|
||||
|
||||
if (in.relroPadding && sec == in.relroPadding->getParent())
|
||||
return true;
|
||||
|
||||
// .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
|
||||
// it into RELRO.
|
||||
@@ -857,7 +867,7 @@ enum RankFlags {
|
||||
RF_BSS = 1 << 7,
|
||||
};
|
||||
|
||||
static unsigned getSectionRank(const OutputSection &osec) {
|
||||
static unsigned getSectionRank(OutputSection &osec) {
|
||||
unsigned rank = osec.partition * RF_PARTITION;
|
||||
|
||||
// We want to put section specified by -T option first, so we
|
||||
@@ -920,7 +930,9 @@ static unsigned getSectionRank(const OutputSection &osec) {
|
||||
// TLS sections directly before the other RELRO sections.
|
||||
if (!(osec.flags & SHF_TLS))
|
||||
rank |= RF_NOT_TLS;
|
||||
if (!isRelroSection(&osec))
|
||||
if (isRelroSection(&osec))
|
||||
osec.relro = true;
|
||||
else
|
||||
rank |= RF_NOT_RELRO;
|
||||
// Place .ldata and .lbss after .bss. Making .bss closer to .text alleviates
|
||||
// relocation overflow pressure.
|
||||
@@ -1140,6 +1152,18 @@ findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
|
||||
SmallVectorImpl<SectionCommand *>::iterator e) {
|
||||
OutputSection *sec = &cast<OutputDesc>(*e)->osec;
|
||||
|
||||
// As a special case, place .relro_padding before the SymbolAssignment using
|
||||
// DATA_SEGMENT_RELRO_END, if present.
|
||||
if (in.relroPadding && sec == in.relroPadding->getParent()) {
|
||||
auto i = std::find_if(b, e, [=](SectionCommand *a) {
|
||||
if (auto *assign = dyn_cast<SymbolAssignment>(a))
|
||||
return assign->dataSegmentRelroEnd;
|
||||
return false;
|
||||
});
|
||||
if (i != e)
|
||||
return i;
|
||||
}
|
||||
|
||||
// Find the first element that has as close a rank as possible.
|
||||
auto i = std::max_element(b, e, [=](SectionCommand *a, SectionCommand *b) {
|
||||
return getRankProximity(sec, a) < getRankProximity(sec, b);
|
||||
@@ -2334,6 +2358,7 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
relroEnd = sec;
|
||||
}
|
||||
}
|
||||
relRo->p_align = 1;
|
||||
|
||||
for (OutputSection *sec : outputSections) {
|
||||
if (!needsPtLoad(sec))
|
||||
@@ -2677,16 +2702,6 @@ template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
|
||||
if (!p->hasLMA)
|
||||
p->p_paddr = first->getLMA();
|
||||
}
|
||||
|
||||
if (p->p_type == PT_GNU_RELRO) {
|
||||
p->p_align = 1;
|
||||
// musl/glibc ld.so rounds the size down, so we need to round up
|
||||
// to protect the last page. This is a no-op on FreeBSD which always
|
||||
// rounds up.
|
||||
p->p_memsz =
|
||||
alignToPowerOf2(p->p_offset + p->p_memsz, config->commonPageSize) -
|
||||
p->p_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,3 +172,18 @@ description in the ``OVERWRITE_SECTIONS`` command while the insert command
|
||||
still applies (possibly after orphan section placement). It is recommended to
|
||||
leave the brace empty (i.e. ``section : {}``) for the insert command, because
|
||||
its description will be ignored anyway.
|
||||
|
||||
Built-in functions
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``DATA_SEGMENT_RELRO_END(offset, exp)`` defines the end of the ``PT_GNU_RELRO``
|
||||
segment when ``-z relro`` (default) is in effect. Sections between
|
||||
``DATA_SEGMENT_ALIGN`` and ``DATA_SEGMENT_RELRO_END`` are considered RELRO.
|
||||
|
||||
The typical use case is ``. = DATA_SEGMENT_RELRO_END(0, .);`` followed by
|
||||
writable but non-RELRO sections. LLD ignores ``offset`` and ``exp`` and aligns
|
||||
the current location to a max-page-size boundary, ensuring that the next
|
||||
``PT_LOAD`` segment will not overlap with the ``PT_GNU_RELRO`` segment.
|
||||
|
||||
LLD will insert ``.relro_padding`` immediately before the symbol assignment
|
||||
using ``DATA_SEGMENT_RELRO_END``.
|
||||
|
||||
@@ -29,7 +29,8 @@ ELF Improvements
|
||||
* ``--fat-lto-objects`` option is added to support LLVM FatLTO.
|
||||
Without ``--fat-lto-objects``, LLD will link LLVM FatLTO objects using the
|
||||
relocatable object file. (`D146778 <https://reviews.llvm.org/D146778>`_)
|
||||
|
||||
* common-page-size can now be larger than the system page-size.
|
||||
(`#57618 <https://github.com/llvm/llvm-project/issues/57618>`_)
|
||||
|
||||
Breaking changes
|
||||
----------------
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x0016d 0x0016d R 0x10000
|
||||
// CHECK: LOAD 0x000170 0x00010170 0x00010170 0x{{.*}} 0x{{.*}} R E 0x10000
|
||||
// CHECK: LOAD 0x000174 0x00020174 0x00020174 0x{{.*}} 0x{{.*}} E 0x10000
|
||||
// CHECK: LOAD 0x000178 0x00030178 0x00030178 0x00038 0x00038 RW 0x10000
|
||||
// CHECK: LOAD 0x000178 0x00030178 0x00030178 0x00038 0x00e88 RW 0x10000
|
||||
|
||||
// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
|
||||
// CHECK: 02 .text
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
// DIFF: LOAD 0x000000 0x00000000 0x00000000 0x0014d 0x0014d R 0x10000
|
||||
// DIFF: LOAD 0x000150 0x00010150 0x00010150 0x0000c 0x0000c R E 0x10000
|
||||
// DIFF: LOAD 0x00015c 0x0002015c 0x0002015c 0x00038 0x00038 RW 0x10000
|
||||
// DIFF: LOAD 0x00015c 0x0002015c 0x0002015c 0x00038 0x00ea4 RW 0x10000
|
||||
|
||||
// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
|
||||
// DIFF: 02 .text .foo
|
||||
|
||||
@@ -21,16 +21,16 @@
|
||||
# CHECK-NEXT: AddressAlignment:
|
||||
# CHECK-NEXT: EntrySize:
|
||||
# CHECK-NEXT: SectionData (
|
||||
# CHECK-NEXT: 0000: 08232000 00000000 08232000 00000000
|
||||
# CHECK-NEXT: 0000: 00302000 00000000 00302000 00000000
|
||||
# CHECK-NEXT: )
|
||||
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: _end
|
||||
# CHECK-NEXT: Value: 0x202308
|
||||
# CHECK-NEXT: Value: 0x203000
|
||||
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: end
|
||||
# CHECK-NEXT: Value: 0x202308
|
||||
# CHECK-NEXT: Value: 0x203000
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
|
||||
79
lld/test/ELF/linkerscript/data-segment-relro-ppc64.test
Normal file
79
lld/test/ELF/linkerscript/data-segment-relro-ppc64.test
Normal file
@@ -0,0 +1,79 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/a.s -o %t/a.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc64le %p/Inputs/shared.s -o %t/b.o
|
||||
# RUN: ld.lld -shared -soname=b %t/b.o -o %t/b.so
|
||||
|
||||
# RUN: ld.lld -z max-page-size=65536 -z norelro %t/a.o %t/b.so -T %t/1.t -o %t/a1
|
||||
# RN: llvm-readelf -S -l %t/a1 | FileCheck %s --check-prefixes=CHECK1
|
||||
|
||||
# RUN: ld.lld -z max-page-size=65536 -z relro %t/a.o %t/b.so -T %t/1.t -o %t/a2
|
||||
# RUN: llvm-readelf -S -l %t/a2 | FileCheck %s --check-prefixes=CHECK2
|
||||
|
||||
## -z norelro suppresses the .relro_padding section.
|
||||
# CHECK1: Name Type Address Off Size ES Flg
|
||||
# CHECK1: .foo PROGBITS
|
||||
# CHECK1-NEXT: .orphan.rw PROGBITS
|
||||
# CHECK1-NEXT: .branch_lt PROGBITS
|
||||
# CHECK1-NEXT: .got PROGBITS
|
||||
# CHECK1-NEXT: .data PROGBITS
|
||||
# CHECK1-NEXT: .bss NOBITS
|
||||
|
||||
# CHECK2: Name Type Address Off Size ES Flg
|
||||
# CHECK2-NEXT: NULL {{.*}}
|
||||
# CHECK2: .orphan.ro PROGBITS {{.*}} A
|
||||
# CHECK2: .dynamic DYNAMIC {{.*}} WA
|
||||
# CHECK2-NEXT: .branch_lt PROGBITS {{.*}} WA
|
||||
# CHECK2-NEXT: .got PROGBITS {{.*}} WA
|
||||
# CHECK2-NEXT: .relro_padding NOBITS 00000000000100f0 0100f0 000f10 00 WA
|
||||
# CHECK2-NEXT: .data PROGBITS {{.*}} WA
|
||||
# CHECK2-NEXT: .foo PROGBITS {{.*}} WA
|
||||
# CHECK2-NEXT: .orphan.rw PROGBITS {{.*}} WA
|
||||
# CHECK2-NEXT: .bss NOBITS {{.*}} WA
|
||||
|
||||
#--- a.s
|
||||
.global _start
|
||||
_start:
|
||||
addis 3, 2, bar2@toc@ha
|
||||
ld 12, bar2@toc@l(3)
|
||||
mtctr 12
|
||||
bctrl
|
||||
b bar
|
||||
nop
|
||||
|
||||
.section .data,"aw"
|
||||
.quad 0
|
||||
|
||||
.zero 4
|
||||
.section .foo,"aw"
|
||||
.section .bss,"",@nobits
|
||||
|
||||
.section .orphan.ro,"a",@progbits
|
||||
.dc.a 0
|
||||
|
||||
.section .orphan.rw,"aw",@progbits
|
||||
.dc.a .orphan.rw
|
||||
|
||||
#--- 1.t
|
||||
SECTIONS {
|
||||
. = SIZEOF_HEADERS;
|
||||
|
||||
.plt : { *(.plt) }
|
||||
.text : { *(.text) }
|
||||
|
||||
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||
|
||||
.dynamic : { *(.dynamic) }
|
||||
.branch_lt : { *(.branch_lt) }
|
||||
.got : { *(.got) }
|
||||
|
||||
. = DATA_SEGMENT_RELRO_END (0, .);
|
||||
|
||||
.plt : { *(.plt) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss) }
|
||||
|
||||
. = DATA_SEGMENT_END (.);
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
||||
@@ -7,18 +7,23 @@
|
||||
## With relro or without DATA_SEGMENT_RELRO_END just aligns to
|
||||
## page boundary.
|
||||
|
||||
# RUN: ld.lld --hash-style=sysv -z norelro %t/a.o %t/b.so -T %t/1.t -o %t/a1
|
||||
# RUN: ld.lld --hash-style=sysv -z max-page-size=65536 -z norelro %t/a.o %t/b.so -T %t/1.t -o %t/a1
|
||||
# RUN: llvm-readelf -S -l %t/a1 | FileCheck %s --check-prefixes=CHECK,CHECK1
|
||||
|
||||
# RUN: ld.lld --hash-style=sysv -z relro %t/a.o %t/b.so -T %t/1.t -o %t/a2
|
||||
# RUN: ld.lld --hash-style=sysv -z max-page-size=65536 -z relro --orphan-handling=warn \
|
||||
# RUN: %t/a.o %t/b.so -T %t/1.t -o %t/a2 2>&1 | FileCheck %s --check-prefix=WARN
|
||||
# RUN: llvm-readelf -S -l %t/a2 | FileCheck %s --check-prefixes=CHECK,CHECK2
|
||||
|
||||
# WARN: warning: <internal>:(.dynsym) is being placed in '.dynsym'
|
||||
# WARN-NOT: (.relro_padding)
|
||||
|
||||
# CHECK: Name Type Address Off Size ES Flg
|
||||
# CHECK-NEXT: NULL {{.*}}
|
||||
# CHECK: .orphan.ro PROGBITS {{.*}} A
|
||||
# CHECK: .dynamic DYNAMIC {{.*}} WA
|
||||
# CHECK-NEXT: __libc_atexit PROGBITS {{.*}} WA
|
||||
# CHECK-NEXT: .got PROGBITS {{.*}} WA
|
||||
# CHECK2-NEXT:.relro_padding NOBITS 0000000000010100 010100 000f00 00 WA
|
||||
# CHECK-NEXT: .got.plt PROGBITS {{.*}} WA
|
||||
# CHECK: .orphan.rw PROGBITS {{.*}} WA
|
||||
|
||||
@@ -26,18 +31,18 @@
|
||||
# CHECK1-NOT: GNU_RELRO
|
||||
|
||||
# CHECK2: Program Headers:
|
||||
# CHECK2-NEXT: Type
|
||||
# CHECK2-NEXT: PHDR
|
||||
# CHECK2-NEXT: LOAD
|
||||
# CHECK2-NEXT: LOAD
|
||||
# CHECK2-NEXT: LOAD
|
||||
# CHECK2-NEXT: LOAD
|
||||
# CHECK2-NEXT: DYNAMIC
|
||||
# CHECK2-NEXT: GNU_RELRO
|
||||
# CHECK2-NEXT: GNU_STACK
|
||||
# CHECK2-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
# CHECK2-NEXT: PHDR 0x000040
|
||||
# CHECK2-NEXT: LOAD 0x000000
|
||||
# CHECK2-NEXT: LOAD 0x0002b0
|
||||
# CHECK2-NEXT: LOAD 0x010000 0x0000000000010000 0x0000000000010000 0x000100 0x001000 RW 0x10000
|
||||
# CHECK2-NEXT: LOAD 0x020000 0x0000000000020000 0x0000000000020000 0x000034 0x000034 RW 0x10000
|
||||
# CHECK2-NEXT: DYNAMIC 0x010000 0x0000000000010000 0x0000000000010000 0x0000f0 0x0000f0 RW 0x8
|
||||
# CHECK2-NEXT: GNU_RELRO 0x010000 0x0000000000010000 0x0000000000010000 0x000100 0x001000 R 0x1
|
||||
# CHECK2-NEXT: GNU_STACK 0x000000
|
||||
|
||||
# CHECK2: Section to Segment mapping:
|
||||
# CHECK2: 06 .dynamic __libc_atexit .got {{$}}
|
||||
# CHECK2: 06 .dynamic __libc_atexit .got .relro_padding {{$}}
|
||||
|
||||
# RUN: sed '/DATA_SEGMENT_RELRO_END/d' %t/1.t > %t/2.t
|
||||
# RUN: not ld.lld %t/a.o %t/b.so -T %t/2.t -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
# CHECK2-NEXT: NULL
|
||||
# CHECK2-NEXT: .foo.text PROGBITS 000000000020{{.*}} [[#%x,]] 000008 00 AX
|
||||
# CHECK2-NEXT: .text PROGBITS [[#%x,]] [[#%x,]] 000008 00 AX
|
||||
# CHECK2-NEXT: .byte PROGBITS [[#%x,]] [[#%x,]] 000001 00 AX
|
||||
# CHECK2-NEXT: .byte PROGBITS [[#%x,]] [[#%x,]] 000001 00 WA
|
||||
# CHECK2-NEXT: .foo.data PROGBITS [[#%x,]] [[#%x,]] 000008 00 WA
|
||||
# CHECK2-NEXT: .data PROGBITS [[#%x,]] [[#%x,]] 000008 00 WA
|
||||
# CHECK2: Type {{.*}} Flg Align
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# CHECK-NEXT: <internal>:(.bss.rel.ro)
|
||||
## Ideally this is displayed as copy@v2.
|
||||
# CHECK-NEXT: copy{{$}}
|
||||
# CHECK-NEXT: .got.plt
|
||||
# CHECK-NEXT: .relro_padding
|
||||
|
||||
#--- 1.s
|
||||
.global _start
|
||||
|
||||
@@ -87,6 +87,8 @@ labs = 0x1AB5
|
||||
# CHECK-NEXT: 201420 201420 0 1 sharedFunc2
|
||||
# CHECK-NEXT: 202430 202430 100 8 .dynamic
|
||||
# CHECK-NEXT: 202430 202430 100 8 <internal>:(.dynamic)
|
||||
# CHECK-NEXT: 202530 202530 ad0 1 .relro_padding
|
||||
# CHECK-NEXT: 202530 202530 0 1 <internal>:(.relro_padding)
|
||||
# CHECK-NEXT: 203530 203530 28 8 .got.plt
|
||||
# CHECK-NEXT: 203530 203530 28 8 <internal>:(.got.plt)
|
||||
# CHECK-NEXT: 203560 203560 10 16 .bss
|
||||
@@ -100,8 +102,8 @@ labs = 0x1AB5
|
||||
# CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
|
||||
# CHECK-NEXT: 0 0 1b0 8 .symtab
|
||||
# CHECK-NEXT: 0 0 1b0 8 <internal>:(.symtab)
|
||||
# CHECK-NEXT: 0 0 84 1 .shstrtab
|
||||
# CHECK-NEXT: 0 0 84 1 <internal>:(.shstrtab)
|
||||
# CHECK-NEXT: 0 0 93 1 .shstrtab
|
||||
# CHECK-NEXT: 0 0 93 1 <internal>:(.shstrtab)
|
||||
# CHECK-NEXT: 0 0 71 1 .strtab
|
||||
# CHECK-NEXT: 0 0 71 1 <internal>:(.strtab)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
// CHECK-NEXT: Owner: GNU
|
||||
// CHECK-NEXT: Data size:
|
||||
// CHECK-NEXT: Type: NT_GNU_BUILD_ID (unique build ID bitstring)
|
||||
// CHECK-NEXT: Build ID: ab81108a3d85b729980356331fddc2bfc4c10177{{$}}
|
||||
// CHECK-NEXT: Build ID: d5101cb9d03b7e836ba9b64f5768a0b31980920f{{$}}
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
// PART0-NEXT: .plt PROGBITS
|
||||
// PART0-NEXT: .init_array INIT_ARRAY {{0*}}[[INIT_ARRAY_ADDR:[^ ]*]]
|
||||
// CHECK-NEXT: .dynamic DYNAMIC {{0*}}[[DYNAMIC_ADDR:[^ ]*]]
|
||||
// PART0-NEXT: .relro_padding NOBITS
|
||||
// PART0-NEXT: .data PROGBITS 000000000000[[DATA_SEGMENT:.]]178
|
||||
// PART1-NEXT: .data PROGBITS 000000000000[[DATA_SEGMENT:.]]130
|
||||
// PART0-NEXT: .got.plt PROGBITS {{0*}}[[GOT_PLT_ADDR:[^ ]*]]
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
# CHECK-NEXT: .dynamic
|
||||
# CHECK-NEXT: .got
|
||||
# CHECK-NEXT: .toc
|
||||
## The end of .relro_padding is aligned to a common-page-size boundary.
|
||||
# CHECK-NEXT: .relro_padding NOBITS 0000000010020400 000400 000c00 00 WA 0 0 1
|
||||
# CHECK-NEXT: .data
|
||||
# CHECK-NEXT: .branch_lt
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
// RUN: ld.lld %t.o %t.so -o %t3
|
||||
// RUN: llvm-readobj -S -l -r %t3 | FileCheck %s
|
||||
|
||||
/// Due to -z rodynamic, The only RELRO section is .bss.rel.ro. Test that we
|
||||
/// still append the .relro_padding section.
|
||||
// RUN: ld.lld -z rodynamic %t.o %t.so -o %t4
|
||||
// RUN: llvm-readelf -S -l %t4 | FileCheck %s --check-prefix=CHECK2
|
||||
|
||||
// CHECK: Name: .bss.rel.ro
|
||||
// CHECK-NEXT: Type: SHT_NOBITS (0x8)
|
||||
// CHECK-NEXT: Flags [ (0x3)
|
||||
@@ -28,6 +33,20 @@
|
||||
// CHECK: 0x202368 R_X86_64_COPY a 0x0
|
||||
// CHECK: 0x20236C R_X86_64_COPY b 0x0
|
||||
|
||||
// CHECK2: LOAD 0x000356 0x0000000000202356 0x0000000000202356 0x000000 0x000caa RW 0x1000
|
||||
// CHECK2: DYNAMIC 0x000258 0x0000000000200258 0x0000000000200258 0x0000b0 0x0000b0 R 0x8
|
||||
// CHECK2: GNU_RELRO 0x000356 0x0000000000202356 0x0000000000202356 0x000000 0x000caa R 0x1
|
||||
|
||||
// CHECK2: Section to Segment mapping:
|
||||
// CHECK2-NEXT: Segment Sections...
|
||||
// CHECK2-NEXT: 00
|
||||
// CHECK2-NEXT: 01 .dynsym .gnu.hash .hash .dynamic .dynstr .rela.dyn
|
||||
// CHECK2-NEXT: 02 .text
|
||||
// CHECK2-NEXT: 03 .bss.rel.ro .relro_padding
|
||||
// CHECK2-NEXT: 04 .dynamic
|
||||
// CHECK2-NEXT: 05 .bss.rel.ro .relro_padding
|
||||
// CHECK2-NEXT: 06
|
||||
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
# SEG: LOAD 0x0001c8 0x00000000002011c8 0x00000000002011c8 0x000001 0x000001 R E 0x1000
|
||||
# SEG-NEXT: LOAD 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x000001 0x002001 RW 0x1000
|
||||
# SEG-NEXT: LOAD 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x000001 0x002e37 RW 0x1000
|
||||
# SEG-NEXT: LOAD 0x0001ca 0x00000000002051ca 0x00000000002051ca 0x000001 0x000002 RW 0x1000
|
||||
# SEG-NEXT: GNU_RELRO 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x000001 0x002e37 R 0x1
|
||||
# SEG-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0
|
||||
@@ -24,6 +24,7 @@
|
||||
# [Nr] Name Type Address Off Size
|
||||
# CHECK: .data.rel.ro PROGBITS 00000000002021c9 0001c9 000001
|
||||
# CHECK-NEXT: .bss.rel.ro NOBITS 00000000002021ca 0001ca 002000
|
||||
# CHECK-NEXT: .relro_padding NOBITS 00000000002041ca 0001ca 000e36
|
||||
# CHECK-NEXT: .data PROGBITS 00000000002051ca 0001ca 000001
|
||||
# CHECK-NEXT: .bss NOBITS 00000000002051cb 0001cb 000001
|
||||
|
||||
|
||||
@@ -28,4 +28,4 @@ _start:
|
||||
.space 0x2000
|
||||
|
||||
// CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
// CHECK: GNU_RELRO 0x002150 0x0000000000000150 0x0000000000000150 0x000100 0x000eb0 R 0x1
|
||||
// CHECK: GNU_RELRO 0x002150 0x0000000000000150 0x0000000000000150 0x000100 0x000100 R 0x1
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
// CHECK-NEXT: GNU_RELRO
|
||||
// CHECK: Section to Segment mapping:
|
||||
|
||||
// FULLRELRO: 03 .openbsd.randomdata .dynamic .got .got.plt {{$}}
|
||||
// PARTRELRO: 03 .openbsd.randomdata .dynamic .got {{$}}
|
||||
// FULLRELRO: 03 .openbsd.randomdata .dynamic .got .got.plt .relro_padding {{$}}
|
||||
// PARTRELRO: 03 .openbsd.randomdata .dynamic .got .relro_padding {{$}}
|
||||
|
||||
|
||||
// NORELRO-NOT: GNU_RELRO
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# NOSDATA-NEXT: .tbss
|
||||
# NOSDATA-NEXT: .dynamic
|
||||
# NOSDATA-NEXT: .got
|
||||
# NOSDATA-NEXT: .relro_padding
|
||||
# NOSDATA-NEXT: .data PROGBITS [[#%x,DATA:]]
|
||||
# NOSDATA-NEXT: .bss NOBITS [[#%x,BSS:]]
|
||||
|
||||
@@ -36,6 +37,7 @@
|
||||
# CHECK-NEXT: .tbss
|
||||
# CHECK-NEXT: .dynamic
|
||||
# CHECK-NEXT: .got
|
||||
# CHECK-NEXT: .relro_padding
|
||||
# CHECK-NEXT: .data
|
||||
# CHECK-NEXT: .sdata PROGBITS [[#%x,SDATA:]]
|
||||
# CHECK-NEXT: .sbss NOBITS [[#%x,SBSS:]]
|
||||
|
||||
@@ -48,11 +48,12 @@ _start:
|
||||
// CHECK-NEXT: .tdata 00000001
|
||||
// CHECK-NEXT: .tbss 00000001
|
||||
// CHECK-NEXT: .data.rel.ro 00000004
|
||||
// CHECK-NEXT: .relro_padding 00000df5
|
||||
// CHECK-NEXT: .data 00000002
|
||||
// CHECK-NEXT: .foo.a 00000001
|
||||
// CHECK-NEXT: .foo 00000001
|
||||
// CHECK-NEXT: .bss 00000002
|
||||
// CHECK-NEXT: .comment 00000008
|
||||
// CHECK-NEXT: .symtab 00000030
|
||||
// CHECK-NEXT: .shstrtab 00000075
|
||||
// CHECK-NEXT: .shstrtab 00000084
|
||||
// CHECK-NEXT: .strtab 00000008
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# RUN: llvm-readelf -l %t | FileCheck --check-prefix=NONE %s
|
||||
# NONE: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x1000
|
||||
# NONE-NEXT: LOAD 0x000248 0x0000000000001248 0x0000000000001248 0x000001 0x000001 R E 0x1000
|
||||
# NONE-NEXT: LOAD 0x000250 0x0000000000002250 0x0000000000002250 0x000090 0x000090 RW 0x1000
|
||||
# NONE-NEXT: LOAD 0x000250 0x0000000000002250 0x0000000000002250 0x000090 0x000db0 RW 0x1000
|
||||
# NONE-NEXT: LOAD 0x0002e0 0x00000000000032e0 0x00000000000032e0 0x000001 0x000001 RW 0x1000
|
||||
|
||||
## -z separate-code makes text segment (RX) separate.
|
||||
@@ -16,7 +16,7 @@
|
||||
# RUN: llvm-readelf -l %t | FileCheck --check-prefix=CODE %s
|
||||
# CODE: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x1000
|
||||
# CODE-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000
|
||||
# CODE-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x000090 RW 0x1000
|
||||
# CODE-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x001000 RW 0x1000
|
||||
# CODE-NEXT: LOAD 0x002090 0x0000000000003090 0x0000000000003090 0x000001 0x000001 RW 0x1000
|
||||
|
||||
## -z separate-loadable-segments makes all segments separate.
|
||||
@@ -24,7 +24,7 @@
|
||||
# RUN: llvm-readelf -l %t | FileCheck --check-prefix=ALL %s
|
||||
# ALL: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x1000
|
||||
# ALL-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000
|
||||
# ALL-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x000090 RW 0x1000
|
||||
# ALL-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x001000 RW 0x1000
|
||||
# ALL-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000003000 0x000001 0x000001 RW 0x1000
|
||||
|
||||
nop
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
|
||||
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: ld.lld -z norelro %t.o -o %t
|
||||
# RUN: llvm-readelf -x .init -x .fini -x .init_array -x .fini_array %t | \
|
||||
# RUN: FileCheck --check-prefixes=CHECK,ORDERED %s
|
||||
|
||||
# RUN: ld.lld %t.o --shuffle-sections '*=1' -o %t1
|
||||
# RUN: ld.lld -z norelro %t.o --shuffle-sections '*=1' -o %t1
|
||||
# RUN: llvm-readelf -x .init -x .fini -x .init_array -x .fini_array %t1 | \
|
||||
# RUN: FileCheck --check-prefixes=CHECK,SHUFFLED %s
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# RUN: ld.lld --shuffle-sections='*=1' %t.o -o %t1.out
|
||||
# RUN: llvm-readelf -x .text %t1.out | FileCheck %s --check-prefix=SHUFFLE1
|
||||
# SHUFFLE1: Hex dump of section '.text':
|
||||
# SHUFFLE1-NEXT: 01020403
|
||||
# SHUFFLE1-NEXT: 030402cc 01
|
||||
|
||||
## Test that --shuffle-sections= can be used with --symbol-ordering-file
|
||||
# RUN: echo "foo" > %t_order.txt
|
||||
@@ -21,7 +21,7 @@
|
||||
# SHUFFLE2: Hex dump of section '.text':
|
||||
# SHUFFLE2-NEXT: 02cccccc 010304
|
||||
|
||||
# RUN: ld.lld --symbol-ordering-file %t_order.txt --shuffle-sections='*=3' %t.o -o %t3.out
|
||||
# RUN: ld.lld -z norelro --symbol-ordering-file %t_order.txt --shuffle-sections='*=3' %t.o -o %t3.out
|
||||
# RUN: llvm-readelf -x .text %t3.out | FileCheck %s --check-prefix=SHUFFLE3
|
||||
# SHUFFLE3: Hex dump of section '.text':
|
||||
# SHUFFLE3-NEXT: 02cccccc 010403
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# CHECK-NEXT: .dynstr {{.*}} A
|
||||
# CHECK-NEXT: .text {{.*}} AX
|
||||
# CHECK-NEXT: .dynamic {{.*}} WA
|
||||
# CHECK-NEXT: foo {{.*}} WA
|
||||
# CHECK: foo {{.*}} WA
|
||||
|
||||
.section foo, "aw"
|
||||
.byte 0
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
# CHECK-NEXT: .text PROGBITS 0000000000201304 000304 000001 00 AX 0 0 4
|
||||
# CHECK-NEXT: .tdata PROGBITS 0000000000202305 000305 000001 00 WAT 0 0 1
|
||||
# CHECK-NEXT: .tbss NOBITS 0000000000202306 000306 000002 00 WAT 0 0 1
|
||||
# CHECK-NEXT: .relro_padding NOBITS 0000000000202306 000306 000cfa 00 WA 0 0 1
|
||||
# CHECK-NEXT: .data PROGBITS 0000000000203306 000306 000001 00 WA 0 0 1
|
||||
# CHECK-NEXT: .bss NOBITS 0000000000203307 000307 001800 00 WA 0 0 1
|
||||
## We spend size(.bss) % MAXPAGESIZE bytes for .bss.
|
||||
@@ -36,7 +37,7 @@
|
||||
# CHECK-NEXT: PHDR 0x000040 0x0000000000200040 0x0000000000200040 {{.*}} {{.*}} R 0x8
|
||||
# CHECK-NEXT: LOAD 0x000000 0x0000000000200000 0x0000000000200000 0x000304 0x000304 R 0x1000
|
||||
# CHECK-NEXT: LOAD 0x000304 0x0000000000201304 0x0000000000201304 0x000001 0x000001 R E 0x1000
|
||||
# CHECK-NEXT: LOAD 0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000001 RW 0x1000
|
||||
# CHECK-NEXT: LOAD 0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000cfb RW 0x1000
|
||||
# CHECK-NEXT: LOAD 0x000306 0x0000000000203306 0x0000000000203306 0x000001 0x001801 RW 0x1000
|
||||
# CHECK-NEXT: LOAD 0x000b07 0x0000000000205b07 0x0000000000205b07 0x000003 0x000005 RW 0x1000
|
||||
|
||||
|
||||
Reference in New Issue
Block a user