Skip to content

Commit d3e0e7a

Browse files
committed
[ptrauth] Signed AsyncFunctionPointers as data.
Previously, AsyncFunctionPointer constants were signed as code. That was incorrect considering that these constants are in fact data. Here, that is fixed. rdar://76118522
1 parent 3b6c070 commit d3e0e7a

File tree

14 files changed

+245
-41
lines changed

14 files changed

+245
-41
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,23 @@ struct PointerAuthOptions : clang::PointerAuthOptions {
142142
/// Resilient class stub initializer callbacks.
143143
PointerAuthSchema ResilientClassStubInitCallbacks;
144144

145+
/// Like SwiftFunctionPointers but for use with AsyncFunctionPointer values.
146+
PointerAuthSchema AsyncSwiftFunctionPointers;
147+
148+
/// Like SwiftClassMethods but for use with AsyncFunctionPointer values.
149+
PointerAuthSchema AsyncSwiftClassMethods;
150+
151+
/// Like ProtocolWitnesses but for use with AsyncFunctionPointer values.
152+
PointerAuthSchema AsyncProtocolWitnesses;
153+
154+
/// Like SwiftClassMethodPointers but for use with AsyncFunctionPointer
155+
/// values.
156+
PointerAuthSchema AsyncSwiftClassMethodPointers;
157+
158+
/// Like SwiftDynamicReplacements but for use with AsyncFunctionPointer
159+
/// values.
160+
PointerAuthSchema AsyncSwiftDynamicReplacements;
161+
145162
/// The parent async context stored within a child async context.
146163
PointerAuthSchema AsyncContextParent;
147164

include/swift/Runtime/Config.h

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,39 @@ static inline void swift_ptrauth_copy(T *dest, const T *src, unsigned extra) {
303303
#endif
304304
}
305305

306-
/// Initialize the destination with an address-discriminated signed pointer.
307-
/// This does not authenticate the source value, so be careful about how
308-
/// you construct it.
306+
/// Copy an address-discriminated signed data pointer from the source
307+
/// to the destination.
308+
template <class T>
309+
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
310+
static inline void swift_ptrauth_copy_data(T *dest, const T *src,
311+
unsigned extra) {
312+
#if SWIFT_PTRAUTH
313+
*dest = ptrauth_auth_and_resign(*src,
314+
ptrauth_key_process_independent_data,
315+
ptrauth_blend_discriminator(src, extra),
316+
ptrauth_key_process_independent_data,
317+
ptrauth_blend_discriminator(dest, extra));
318+
#else
319+
*dest = *src;
320+
#endif
321+
}
322+
323+
/// Copy an address-discriminated signed pointer from the source
324+
/// to the destination.
325+
template <class T>
326+
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE static inline void
327+
swift_ptrauth_copy_code_or_data(T *dest, const T *src, unsigned extra,
328+
bool isCode) {
329+
if (isCode) {
330+
return swift_ptrauth_copy(dest, src, extra);
331+
} else {
332+
return swift_ptrauth_copy_data(dest, src, extra);
333+
}
334+
}
335+
336+
/// Initialize the destination with an address-discriminated signed
337+
/// function pointer. This does not authenticate the source value, so be
338+
/// careful about how you construct it.
309339
template <class T>
310340
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
311341
static inline void swift_ptrauth_init(T *dest, T value, unsigned extra) {
@@ -319,6 +349,35 @@ static inline void swift_ptrauth_init(T *dest, T value, unsigned extra) {
319349
#endif
320350
}
321351

352+
/// Initialize the destination with an address-discriminated signed
353+
/// data pointer. This does not authenticate the source value, so be
354+
/// careful about how you construct it.
355+
template <class T>
356+
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
357+
static inline void swift_ptrauth_init_data(T *dest, T value, unsigned extra) {
358+
// FIXME: assert that T is not a function-pointer type?
359+
#if SWIFT_PTRAUTH
360+
*dest = ptrauth_sign_unauthenticated(value,
361+
ptrauth_key_process_independent_data,
362+
ptrauth_blend_discriminator(dest, extra));
363+
#else
364+
*dest = value;
365+
#endif
366+
}
367+
368+
/// Initialize the destination with an address-discriminated signed
369+
/// pointer. This does not authenticate the source value, so be
370+
/// careful about how you construct it.
371+
template <class T>
372+
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE static inline void
373+
swift_ptrauth_init_code_or_data(T *dest, T value, unsigned extra, bool isCode) {
374+
if (isCode) {
375+
return swift_ptrauth_init(dest, value, extra);
376+
} else {
377+
return swift_ptrauth_init_data(dest, value, extra);
378+
}
379+
}
380+
322381
template <typename T>
323382
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
324383
static inline T swift_auth_data_non_address(T value, unsigned extra) {

lib/IRGen/Callee.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,36 @@ namespace irgen {
101101
assert(isSigned());
102102
return Key;
103103
}
104+
bool hasCodeKey() const {
105+
assert(isSigned());
106+
return (getKey() == (unsigned)PointerAuthSchema::ARM8_3Key::ASIA) ||
107+
(getKey() == (unsigned)PointerAuthSchema::ARM8_3Key::ASIB);
108+
}
109+
bool hasDataKey() const {
110+
assert(isSigned());
111+
return (getKey() == (unsigned)PointerAuthSchema::ARM8_3Key::ASDA) ||
112+
(getKey() == (unsigned)PointerAuthSchema::ARM8_3Key::ASDB);
113+
}
114+
bool getCorrespondingCodeKey() const {
115+
assert(hasDataKey());
116+
switch (getKey()) {
117+
case (unsigned)PointerAuthSchema::ARM8_3Key::ASDA:
118+
return (unsigned)PointerAuthSchema::ARM8_3Key::ASIA;
119+
case (unsigned)PointerAuthSchema::ARM8_3Key::ASDB:
120+
return (unsigned)PointerAuthSchema::ARM8_3Key::ASIB;
121+
}
122+
llvm_unreachable("unhandled case");
123+
}
124+
bool getCorrespondingDataKey() const {
125+
assert(hasCodeKey());
126+
switch (getKey()) {
127+
case (unsigned)PointerAuthSchema::ARM8_3Key::ASIA:
128+
return (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;
129+
case (unsigned)PointerAuthSchema::ARM8_3Key::ASIB:
130+
return (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;
131+
}
132+
llvm_unreachable("unhandled case");
133+
}
104134
llvm::Value *getDiscriminator() const {
105135
assert(isSigned());
106136
return Discriminator;
@@ -219,6 +249,13 @@ namespace irgen {
219249
// The function pointer should have function type.
220250
assert(value->getType()->getPointerElementType()->isFunctionTy());
221251
// TODO: maybe assert similarity to signature.getType()?
252+
if (authInfo) {
253+
if (kind == Kind::Function) {
254+
assert(authInfo.hasCodeKey());
255+
} else {
256+
assert(authInfo.hasDataKey());
257+
}
258+
}
222259
}
223260

224261
// Temporary only!
@@ -295,7 +332,7 @@ namespace irgen {
295332
llvm::Value *getExplosionValue(IRGenFunction &IGF,
296333
CanSILFunctionType fnType) const;
297334

298-
/// Form a FunctionPointer whose KindTy is ::Function.
335+
/// Form a FunctionPointer whose Kind is ::Function.
299336
FunctionPointer getAsFunction(IRGenFunction &IGF) const;
300337

301338
bool useStaticContextSize() const {

lib/IRGen/GenCall.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,7 +2002,9 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
20022002
/*expectedType*/ functionPointer.getFunctionType()->getPointerTo());
20032003
}
20042004
if (auto authInfo = functionPointer.getAuthInfo()) {
2005-
fn = emitPointerAuthSign(IGF, fn, authInfo);
2005+
auto newAuthInfo = PointerAuthInfo(authInfo.getCorrespondingCodeKey(),
2006+
authInfo.getDiscriminator());
2007+
fn = emitPointerAuthSign(IGF, fn, newAuthInfo);
20062008
}
20072009
}
20082010
llvm::Value *size = nullptr;
@@ -2330,9 +2332,13 @@ class AsyncCallEmission final : public CallEmission {
23302332
}
23312333

23322334
FunctionPointer getCalleeFunctionPointer() override {
2335+
PointerAuthInfo newAuthInfo;
2336+
if (auto authInfo = CurCallee.getFunctionPointer().getAuthInfo()) {
2337+
newAuthInfo = PointerAuthInfo(authInfo.getCorrespondingCodeKey(),
2338+
authInfo.getDiscriminator());
2339+
}
23332340
return FunctionPointer(
2334-
FunctionPointer::Kind::Function, calleeFunction,
2335-
CurCallee.getFunctionPointer().getAuthInfo(),
2341+
FunctionPointer::Kind::Function, calleeFunction, newAuthInfo,
23362342
Signature::forAsyncAwait(IGF.IGM, getCallee().getOrigFunctionType()));
23372343
}
23382344

@@ -4695,7 +4701,9 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
46954701
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
46964702
/*expectedType*/ getFunctionType()->getPointerTo());
46974703
if (auto authInfo = AuthInfo) {
4698-
result = emitPointerAuthSign(IGF, result, authInfo);
4704+
auto newAuthInfo = PointerAuthInfo(authInfo.getCorrespondingCodeKey(),
4705+
authInfo.getDiscriminator());
4706+
result = emitPointerAuthSign(IGF, result, newAuthInfo);
46994707
}
47004708
return result;
47014709
}
@@ -4732,7 +4740,19 @@ FunctionPointer::getExplosionValue(IRGenFunction &IGF,
47324740
}
47334741

47344742
FunctionPointer FunctionPointer::getAsFunction(IRGenFunction &IGF) const {
4735-
return FunctionPointer(Kind::Function, getPointer(IGF), AuthInfo, Sig);
4743+
switch (getBasicKind()) {
4744+
case FunctionPointer::BasicKind::Function:
4745+
return *this;
4746+
case FunctionPointer::BasicKind::AsyncFunctionPointer: {
4747+
auto authInfo = AuthInfo;
4748+
if (authInfo) {
4749+
authInfo = PointerAuthInfo(AuthInfo.getCorrespondingCodeKey(),
4750+
AuthInfo.getDiscriminator());
4751+
}
4752+
return FunctionPointer(Kind::Function, getPointer(IGF), authInfo, Sig);
4753+
}
4754+
}
4755+
llvm_unreachable("unhandled case");
47364756
}
47374757

47384758
void irgen::emitAsyncReturn(

lib/IRGen/GenClass.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2643,7 +2643,9 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
26432643
signature.getType()->getPointerTo(),
26442644
IGF.IGM.getPointerAlignment());
26452645
auto fnPtr = IGF.emitInvariantLoad(slot);
2646-
auto &schema = IGF.getOptions().PointerAuth.SwiftClassMethods;
2646+
auto &schema = methodType->isAsync()
2647+
? IGF.getOptions().PointerAuth.AsyncSwiftClassMethods
2648+
: IGF.getOptions().PointerAuth.SwiftClassMethods;
26472649
auto authInfo =
26482650
PointerAuthInfo::emit(IGF, schema, slot.getAddress(), method);
26492651
return FunctionPointer(methodType, fnPtr, authInfo, signature);

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2573,7 +2573,9 @@ void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) {
25732573
auto *FnAddr = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
25742574
IGF.CurFn, FunctionPtrTy);
25752575

2576-
auto &schema = getOptions().PointerAuth.SwiftDynamicReplacements;
2576+
auto &schema = f->isAsync()
2577+
? getOptions().PointerAuth.AsyncSwiftDynamicReplacements
2578+
: getOptions().PointerAuth.SwiftDynamicReplacements;
25772579
llvm::Value *ReplFn = nullptr, *hasReplFn = nullptr;
25782580

25792581
if (UseBasicDynamicReplacement) {

lib/IRGen/GenMeta.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,10 @@ static Flags getMethodDescriptorFlags(ValueDecl *fn) {
262262
}
263263
llvm_unreachable("bad kind");
264264
}();
265-
return Flags(kind).withIsInstance(!fn->isStatic());
265+
bool hasAsync = false;
266+
if (auto *afd = dyn_cast<AbstractFunctionDecl>(fn))
267+
hasAsync = afd->hasAsync();
268+
return Flags(kind).withIsInstance(!fn->isStatic()).withIsAsync(hasAsync);
266269
}
267270

268271
static void buildMethodDescriptorFields(IRGenModule &IGM,
@@ -279,7 +282,9 @@ static void buildMethodDescriptorFields(IRGenModule &IGM,
279282
flags = flags.withIsDynamic(true);
280283

281284
// Include the pointer-auth discriminator.
282-
if (auto &schema = IGM.getOptions().PointerAuth.SwiftClassMethods) {
285+
if (auto &schema = func->hasAsync()
286+
? IGM.getOptions().PointerAuth.AsyncSwiftClassMethods
287+
: IGM.getOptions().PointerAuth.SwiftClassMethods) {
283288
auto discriminator =
284289
PointerAuthInfo::getOtherDiscriminator(IGM, schema, fn);
285290
flags = flags.withExtraDiscriminator(discriminator->getZExtValue());
@@ -3159,6 +3164,7 @@ namespace {
31593164
// Find the vtable entry.
31603165
assert(VTable && "no vtable?!");
31613166
auto entry = VTable->getEntry(IGM.getSILModule(), fn);
3167+
auto *afd = cast<AbstractFunctionDecl>(fn.getDecl());
31623168

31633169
// The class is fragile. Emit a direct reference to the vtable entry.
31643170
llvm::Constant *ptr;
@@ -3172,11 +3178,19 @@ namespace {
31723178
} else {
31733179
// The method is removed by dead method elimination.
31743180
// It should be never called. We add a pointer to an error function.
3175-
ptr = llvm::ConstantExpr::getBitCast(IGM.getDeletedMethodErrorFn(),
3176-
IGM.FunctionPtrTy);
3181+
if (afd->hasAsync()) {
3182+
ptr = llvm::ConstantExpr::getBitCast(
3183+
IGM.getDeletedAsyncMethodErrorAsyncFunctionPointer(),
3184+
IGM.FunctionPtrTy);
3185+
} else {
3186+
ptr = llvm::ConstantExpr::getBitCast(IGM.getDeletedMethodErrorFn(),
3187+
IGM.FunctionPtrTy);
3188+
}
31773189
}
31783190

3179-
auto &schema = IGM.getOptions().PointerAuth.SwiftClassMethods;
3191+
PointerAuthSchema schema =
3192+
afd->hasAsync() ? IGM.getOptions().PointerAuth.AsyncSwiftClassMethods
3193+
: IGM.getOptions().PointerAuth.SwiftClassMethods;
31803194
B.addSignedPointer(ptr, schema, fn);
31813195
}
31823196

lib/IRGen/GenPointerAuth.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ static const PointerAuthSchema &getFunctionPointerSchema(IRGenModule &IGM,
198198
case SILFunctionTypeRepresentation::Method:
199199
case SILFunctionTypeRepresentation::WitnessMethod:
200200
case SILFunctionTypeRepresentation::Closure:
201+
if (fnType->isAsync()) {
202+
return options.AsyncSwiftFunctionPointers;
203+
}
204+
201205
return options.SwiftFunctionPointers;
202206

203207
case SILFunctionTypeRepresentation::ObjCMethod:

lib/IRGen/GenProto.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
13331333
#endif
13341334

13351335
SILFunction *Func = entry.getMethodWitness().Witness;
1336+
auto *afd = cast<AbstractFunctionDecl>(
1337+
entry.getMethodWitness().Requirement.getDecl());
13361338
llvm::Constant *witness = nullptr;
13371339
if (Func) {
13381340
if (Func->isAsync()) {
@@ -1343,11 +1345,20 @@ class AccessorConformanceInfo : public ConformanceInfo {
13431345
} else {
13441346
// The method is removed by dead method elimination.
13451347
// It should be never called. We add a pointer to an error function.
1346-
witness = IGM.getDeletedMethodErrorFn();
1348+
if (afd->hasAsync()) {
1349+
witness = llvm::ConstantExpr::getBitCast(
1350+
IGM.getDeletedAsyncMethodErrorAsyncFunctionPointer(),
1351+
IGM.FunctionPtrTy);
1352+
} else {
1353+
witness = llvm::ConstantExpr::getBitCast(
1354+
IGM.getDeletedMethodErrorFn(), IGM.FunctionPtrTy);
1355+
}
13471356
}
13481357
witness = llvm::ConstantExpr::getBitCast(witness, IGM.Int8PtrTy);
13491358

1350-
auto &schema = IGM.getOptions().PointerAuth.ProtocolWitnesses;
1359+
PointerAuthSchema schema =
1360+
afd->hasAsync() ? IGM.getOptions().PointerAuth.AsyncProtocolWitnesses
1361+
: IGM.getOptions().PointerAuth.ProtocolWitnesses;
13511362
Table.addSignedPointer(witness, schema, requirement);
13521363
return;
13531364
}
@@ -3353,7 +3364,9 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
33533364
witnessFnPtr = IGF.Builder.CreateBitCast(witnessFnPtr,
33543365
signature.getType()->getPointerTo());
33553366

3356-
auto &schema = IGF.getOptions().PointerAuth.ProtocolWitnesses;
3367+
auto &schema = fnType->isAsync()
3368+
? IGF.getOptions().PointerAuth.AsyncProtocolWitnesses
3369+
: IGF.getOptions().PointerAuth.ProtocolWitnesses;
33573370
auto authInfo = PointerAuthInfo::emit(IGF, schema, slot, member);
33583371

33593372
return FunctionPointer(fnType, witnessFnPtr, authInfo, signature);

lib/IRGen/GenThunk.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,10 @@ void IRGenModule::emitMethodLookupFunction(ClassDecl *classDecl) {
472472
NotForDefinition);
473473
// Sign using the discriminator we would include in the method
474474
// descriptor.
475-
if (auto &schema = IGM.getOptions().PointerAuth.SwiftClassMethods) {
475+
if (auto &schema =
476+
entry->getImplementation()->getLoweredFunctionType()->isAsync()
477+
? IGM.getOptions().PointerAuth.AsyncSwiftClassMethods
478+
: IGM.getOptions().PointerAuth.SwiftClassMethods) {
476479
auto discriminator =
477480
PointerAuthInfo::getOtherDiscriminator(IGM, schema, method);
478481

lib/IRGen/IRGen.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,21 @@ static void setPointerAuthOptions(PointerAuthOptions &opts,
697697
PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Constant,
698698
SpecialPointerAuthDiscriminators::ResilientClassStubInitCallback);
699699

700+
opts.AsyncSwiftFunctionPointers =
701+
PointerAuthSchema(dataKey, /*address*/ false, Discrimination::Type);
702+
703+
opts.AsyncSwiftClassMethods =
704+
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Decl);
705+
706+
opts.AsyncProtocolWitnesses =
707+
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Decl);
708+
709+
opts.AsyncSwiftClassMethodPointers =
710+
PointerAuthSchema(dataKey, /*address*/ false, Discrimination::Decl);
711+
712+
opts.AsyncSwiftDynamicReplacements =
713+
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Decl);
714+
700715
opts.AsyncContextParent =
701716
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Constant,
702717
SpecialPointerAuthDiscriminators::AsyncContextParent);

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6694,7 +6694,9 @@ void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) {
66946694
auto sig = IGM.getSignature(methodType);
66956695
fnPtr = Builder.CreateBitCast(fnPtr, sig.getType()->getPointerTo());
66966696

6697-
auto &schema = getOptions().PointerAuth.SwiftClassMethodPointers;
6697+
auto &schema = methodType->isAsync()
6698+
? getOptions().PointerAuth.AsyncSwiftClassMethodPointers
6699+
: getOptions().PointerAuth.SwiftClassMethodPointers;
66986700
auto authInfo =
66996701
PointerAuthInfo::emit(*this, schema, /*storageAddress=*/nullptr, method);
67006702

0 commit comments

Comments
 (0)