Skip to content

Commit 191e062

Browse files
committed
[JITLink][MachO][arm64] Don't lower ptrauth edges in noalloc-lifetime sections.
Ptrauth relocations can only be fixed up in the executing process, but noalloc sections do not have any memory in the executing process. Failure to skip ptrauth edges results in signing instructions that operate on invalid addresses, leading to segfaults or data corruption. Ignoring noalloc sections for ptrauth lowering purposes allows the ptrauth edges to persist until they reach the applyFixup method, at which point they raise a useful error and cleanly terminate linking.
1 parent 13a313f commit 191e062

File tree

2 files changed

+208
-55
lines changed

2 files changed

+208
-55
lines changed

llvm/lib/ExecutionEngine/JITLink/aarch64.cpp

Lines changed: 72 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,20 @@ Error createEmptyPointerSigningFunction(LinkGraph &G) {
240240
// info encoded in the addend -- the only actually unknown quantity is the
241241
// fixup location, and we can probably put constraints even on that.
242242
size_t NumPtrAuthFixupLocations = 0;
243-
for (auto *B : G.blocks())
244-
for (auto &E : B->edges())
245-
NumPtrAuthFixupLocations +=
246-
E.getKind() == aarch64::Pointer64Authenticated;
243+
for (auto &Sec : G.sections()) {
244+
245+
// No-alloc sections can't have ptrauth edges. We don't need to error out
246+
// here: applyFixup will catch these edges if any make it to the fixup
247+
// stage.
248+
if (Sec.getMemLifetime() == orc::MemLifetime::NoAlloc)
249+
continue;
250+
251+
for (auto *B : Sec.blocks()) {
252+
for (auto &E : B->edges())
253+
NumPtrAuthFixupLocations +=
254+
E.getKind() == aarch64::Pointer64Authenticated;
255+
}
256+
}
247257

248258
constexpr size_t MaxPtrSignSeqLength =
249259
4 + // To materialize the value to sign.
@@ -316,58 +326,65 @@ Error lowerPointer64AuthEdgesToSigningFunction(LinkGraph &G) {
316326
return InstrWriter.writeInteger(Instr);
317327
};
318328

319-
for (auto *B : G.blocks()) {
320-
for (auto &E : B->edges()) {
321-
// We're only concerned with Pointer64Authenticated edges here.
322-
if (E.getKind() != aarch64::Pointer64Authenticated)
323-
continue;
324-
325-
uint64_t EncodedInfo = E.getAddend();
326-
int32_t RealAddend = (uint32_t)(EncodedInfo & 0xffffffff);
327-
auto ValueToSign = E.getTarget().getAddress() + RealAddend;
328-
if (!ValueToSign) {
329-
LLVM_DEBUG(dbgs() << " " << B->getFixupAddress(E) << " <- null\n");
330-
E.setAddend(RealAddend);
331-
E.setKind(aarch64::Pointer64);
332-
continue;
333-
}
329+
for (auto &Sec : G.sections()) {
330+
331+
if (Sec.getMemLifetime() == orc::MemLifetime::NoAlloc)
332+
continue;
334333

335-
uint32_t InitialDiscriminator = (EncodedInfo >> 32) & 0xffff;
336-
bool AddressDiversify = (EncodedInfo >> 48) & 0x1;
337-
uint32_t Key = (EncodedInfo >> 49) & 0x3;
338-
uint32_t HighBits = EncodedInfo >> 51;
339-
340-
if (HighBits != 0x1000)
341-
return make_error<JITLinkError>(
342-
"Pointer64Auth edge at " +
343-
formatv("{0:x}", B->getFixupAddress(E).getValue()) +
344-
" has invalid encoded addend " + formatv("{0:x}", EncodedInfo));
345-
346-
LLVM_DEBUG({
347-
const char *const KeyNames[] = {"IA", "IB", "DA", "DB"};
348-
dbgs() << " " << B->getFixupAddress(E) << " <- " << ValueToSign
349-
<< " : key = " << KeyNames[Key] << ", discriminator = "
350-
<< formatv("{0:x4}", InitialDiscriminator)
351-
<< ", address diversified = "
352-
<< (AddressDiversify ? "yes" : "no") << "\n";
353-
});
354-
355-
// Materialize pointer value.
356-
cantFail(writeMovRegImm64Seq(AppendInstr, Reg1, ValueToSign.getValue()));
357-
358-
// Materialize fixup pointer.
359-
cantFail(writeMovRegImm64Seq(AppendInstr, Reg2,
360-
B->getFixupAddress(E).getValue()));
361-
362-
// Write signing instruction(s).
363-
cantFail(writePACSignSeq(AppendInstr, Reg1, ValueToSign, Reg2, Reg3, Key,
364-
InitialDiscriminator, AddressDiversify));
365-
366-
// Store signed pointer.
367-
cantFail(writeStoreRegSeq(AppendInstr, Reg2, Reg1));
368-
369-
// Replace edge with a keep-alive to preserve dependence info.
370-
E.setKind(Edge::KeepAlive);
334+
for (auto *B : Sec.blocks()) {
335+
for (auto &E : B->edges()) {
336+
// We're only concerned with Pointer64Authenticated edges here.
337+
if (E.getKind() != aarch64::Pointer64Authenticated)
338+
continue;
339+
340+
uint64_t EncodedInfo = E.getAddend();
341+
int32_t RealAddend = (uint32_t)(EncodedInfo & 0xffffffff);
342+
auto ValueToSign = E.getTarget().getAddress() + RealAddend;
343+
if (!ValueToSign) {
344+
LLVM_DEBUG(dbgs() << " " << B->getFixupAddress(E) << " <- null\n");
345+
E.setAddend(RealAddend);
346+
E.setKind(aarch64::Pointer64);
347+
continue;
348+
}
349+
350+
uint32_t InitialDiscriminator = (EncodedInfo >> 32) & 0xffff;
351+
bool AddressDiversify = (EncodedInfo >> 48) & 0x1;
352+
uint32_t Key = (EncodedInfo >> 49) & 0x3;
353+
uint32_t HighBits = EncodedInfo >> 51;
354+
355+
if (HighBits != 0x1000)
356+
return make_error<JITLinkError>(
357+
"Pointer64Auth edge at " +
358+
formatv("{0:x}", B->getFixupAddress(E).getValue()) +
359+
" has invalid encoded addend " + formatv("{0:x}", EncodedInfo));
360+
361+
LLVM_DEBUG({
362+
const char *const KeyNames[] = {"IA", "IB", "DA", "DB"};
363+
dbgs() << " " << B->getFixupAddress(E) << " <- " << ValueToSign
364+
<< " : key = " << KeyNames[Key] << ", discriminator = "
365+
<< formatv("{0:x4}", InitialDiscriminator)
366+
<< ", address diversified = "
367+
<< (AddressDiversify ? "yes" : "no") << "\n";
368+
});
369+
370+
// Materialize pointer value.
371+
cantFail(
372+
writeMovRegImm64Seq(AppendInstr, Reg1, ValueToSign.getValue()));
373+
374+
// Materialize fixup pointer.
375+
cantFail(writeMovRegImm64Seq(AppendInstr, Reg2,
376+
B->getFixupAddress(E).getValue()));
377+
378+
// Write signing instruction(s).
379+
cantFail(writePACSignSeq(AppendInstr, Reg1, ValueToSign, Reg2, Reg3,
380+
Key, InitialDiscriminator, AddressDiversify));
381+
382+
// Store signed pointer.
383+
cantFail(writeStoreRegSeq(AppendInstr, Reg2, Reg1));
384+
385+
// Replace edge with a keep-alive to preserve dependence info.
386+
E.setKind(Edge::KeepAlive);
387+
}
371388
}
372389
}
373390

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: not llvm-jitlink -noexec %t 2>&1 | FileCheck %s
3+
#
4+
# Check that ptrauth edges are _not_ lowered for noalloc sections.
5+
#
6+
# Ptrauth edges are lowered to signing function instructions, so any ptrauth
7+
# edge in a noalloc section will introduce signing instructions that operate
8+
# illegally on linker working memory, rather than executor memory (this will
9+
# usually lead to a crash, but may silently corrupt memory in in-process JITs).
10+
#
11+
# By ignoring these edges during ptrauth lowering we prevent illegal signing
12+
# instructions from being generated, and the ptrauth edges error out in
13+
# applyFixup instead.
14+
#
15+
16+
# CHECK: llvm-jitlink error: {{.*}} unsupported edge kind Pointer64Authenticated
17+
18+
--- !mach-o
19+
FileHeader:
20+
magic: 0xFEEDFACF
21+
cputype: 0x100000C
22+
cpusubtype: 0x80000002
23+
filetype: 0x1
24+
ncmds: 4
25+
sizeofcmds: 440
26+
flags: 0x2000
27+
reserved: 0x0
28+
LoadCommands:
29+
- cmd: LC_SEGMENT_64
30+
cmdsize: 312
31+
segname: ''
32+
vmaddr: 0
33+
vmsize: 16
34+
fileoff: 472
35+
filesize: 16
36+
maxprot: 7
37+
initprot: 7
38+
nsects: 2
39+
flags: 0
40+
Sections:
41+
- sectname: __text
42+
segname: __TEXT
43+
addr: 0x0
44+
size: 8
45+
offset: 0x1D8
46+
align: 2
47+
reloff: 0x0
48+
nreloc: 0
49+
flags: 0x80000400
50+
reserved1: 0x0
51+
reserved2: 0x0
52+
reserved3: 0x0
53+
content: 00008052C0035FD6
54+
- sectname: __debug_stuff
55+
segname: __DWARF
56+
addr: 0x8
57+
size: 8
58+
offset: 0x1E0
59+
align: 3
60+
reloff: 0x1E8
61+
nreloc: 1
62+
flags: 0x2000000
63+
reserved1: 0x0
64+
reserved2: 0x0
65+
reserved3: 0x0
66+
content: '0000000000000080'
67+
relocations:
68+
- address: 0x0
69+
symbolnum: 3
70+
pcrel: false
71+
length: 3
72+
extern: true
73+
type: 11
74+
scattered: false
75+
value: 0
76+
- cmd: LC_BUILD_VERSION
77+
cmdsize: 24
78+
platform: 1
79+
minos: 983040
80+
sdk: 0
81+
ntools: 0
82+
- cmd: LC_SYMTAB
83+
cmdsize: 24
84+
symoff: 496
85+
nsyms: 4
86+
stroff: 560
87+
strsize: 24
88+
- cmd: LC_DYSYMTAB
89+
cmdsize: 80
90+
ilocalsym: 0
91+
nlocalsym: 2
92+
iextdefsym: 2
93+
nextdefsym: 2
94+
iundefsym: 4
95+
nundefsym: 0
96+
tocoff: 0
97+
ntoc: 0
98+
modtaboff: 0
99+
nmodtab: 0
100+
extrefsymoff: 0
101+
nextrefsyms: 0
102+
indirectsymoff: 0
103+
nindirectsyms: 0
104+
extreloff: 0
105+
nextrel: 0
106+
locreloff: 0
107+
nlocrel: 0
108+
LinkEditData:
109+
NameList:
110+
- n_strx: 18
111+
n_type: 0xE
112+
n_sect: 1
113+
n_desc: 0
114+
n_value: 0
115+
- n_strx: 12
116+
n_type: 0xE
117+
n_sect: 2
118+
n_desc: 0
119+
n_value: 8
120+
- n_strx: 1
121+
n_type: 0xF
122+
n_sect: 2
123+
n_desc: 0
124+
n_value: 8
125+
- n_strx: 6
126+
n_type: 0xF
127+
n_sect: 1
128+
n_desc: 0
129+
n_value: 0
130+
StringTable:
131+
- ''
132+
- _foo
133+
- _main
134+
- ltmp1
135+
- ltmp0
136+
...

0 commit comments

Comments
 (0)