Skip to content

Commit 75a00ad

Browse files
authored
Merge pull request #74625 from swiftlang/egorzhdan/upstream-ptrauth-vwt
[IRGen] Upstream pointer auth for value witness tables
2 parents 34c34b5 + b22057e commit 75a00ad

File tree

5 files changed

+121
-26
lines changed

5 files changed

+121
-26
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ struct PointerAuthOptions : clang::PointerAuthOptions {
109109
/// Swift value witness functions.
110110
PointerAuthSchema ValueWitnesses;
111111

112+
/// Pointers to Swift value witness tables stored in type metadata.
113+
PointerAuthSchema ValueWitnessTable;
114+
112115
/// Swift protocol witness functions.
113116
PointerAuthSchema ProtocolWitnesses;
114117

include/swift/Remote/MetadataReader.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -699,10 +699,11 @@ class MetadataReader {
699699
// pointer's referenced address.
700700
TargetValueWitnessTable<Runtime> VWT;
701701
auto ValueWitnessTableAddrAddr = MetadataAddress - sizeof(StoredPointer);
702-
StoredPointer ValueWitnessTableAddr;
702+
StoredSignedPointer SignedValueWitnessTableAddr;
703703
if (!Reader->readInteger(RemoteAddress(ValueWitnessTableAddrAddr),
704-
&ValueWitnessTableAddr))
704+
&SignedValueWitnessTableAddr))
705705
return std::nullopt;
706+
auto ValueWitnessTableAddr = stripSignedPointer(SignedValueWitnessTableAddr);
706707
if (!Reader->readBytes(RemoteAddress(ValueWitnessTableAddr),
707708
(uint8_t *)&VWT, sizeof(VWT)))
708709
return std::nullopt;

lib/IRGen/GenMeta.cpp

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "swift/Strings.h"
3939
#include "clang/AST/Decl.h"
4040
#include "clang/AST/DeclObjC.h"
41+
#include "clang/Basic/TargetInfo.h"
4142
#include "llvm/ADT/SmallString.h"
4243
#include "llvm/IR/DerivedTypes.h"
4344
#include "llvm/IR/Function.h"
@@ -4037,7 +4038,14 @@ namespace {
40374038

40384039
void addValueWitnessTable() {
40394040
assert(!isPureObjC());
4040-
B.add(asImpl().getValueWitnessTable(false).getValue());
4041+
4042+
auto wtable = asImpl().getValueWitnessTable(false).getValue();
4043+
if (!isa<llvm::ConstantPointerNull>(wtable)) {
4044+
auto schema = IGM.getOptions().PointerAuth.ValueWitnessTable;
4045+
B.addSignedPointer(wtable, schema, PointerAuthEntity());
4046+
} else {
4047+
B.add(wtable);
4048+
}
40414049
}
40424050

40434051
llvm::Constant *getAddrOfMetaclassObject(ForDefinition_t forDefinition) {
@@ -5412,19 +5420,36 @@ emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF,
54125420
/// Given a type metadata pointer, load its value witness table.
54135421
llvm::Value *
54145422
IRGenFunction::emitValueWitnessTableRefForMetadata(llvm::Value *metadata) {
5415-
auto witness = emitInvariantLoadFromMetadataAtIndex(*this, metadata, nullptr,
5416-
-1, IGM.WitnessTablePtrTy,
5417-
".valueWitnesses");
5423+
llvm::Value *addrOfWitnessTablePtr = nullptr;
5424+
llvm::LoadInst *loadOfWitnessTablePtr = emitInvariantLoadFromMetadataAtIndex(
5425+
*this, metadata, &addrOfWitnessTablePtr, -1, IGM.WitnessTablePtrTy,
5426+
".valueWitnesses");
5427+
5428+
const auto &ptrAuthOpts = IGM.getOptions().PointerAuth;
5429+
if (auto schema = IGM.getOptions().PointerAuth.ValueWitnessTable) {
5430+
llvm::Value *signedWitnessTablePtr = loadOfWitnessTablePtr;
5431+
llvm::Value *witnessTablePtr = emitPointerAuthAuth(
5432+
*this, signedWitnessTablePtr,
5433+
PointerAuthInfo::emit(*this, schema, addrOfWitnessTablePtr,
5434+
PointerAuthEntity()));
5435+
5436+
// TODO: We might be able to flag witnessTablePtr as dereferencable (see
5437+
// below) by adding an attribute (not setting the metadata). However, it
5438+
// is unclear if there are any benefits to be had at the cost of
5439+
// changing the APIs in multiple places.
5440+
return witnessTablePtr;
5441+
}
5442+
54185443
// A value witness table is dereferenceable to the number of value witness
54195444
// pointers.
54205445

54215446
// TODO: If we know the type statically has extra inhabitants, we know
54225447
// there are more witnesses.
54235448
auto numValueWitnesses
54245449
= unsigned(ValueWitness::Last_RequiredValueWitness) + 1;
5425-
setDereferenceableLoad(witness,
5450+
setDereferenceableLoad(loadOfWitnessTablePtr,
54265451
IGM.getPointerSize().getValue() * numValueWitnesses);
5427-
return witness;
5452+
return loadOfWitnessTablePtr;
54285453
}
54295454

54305455
/// Given a lowered SIL type, load a value witness table that represents its
@@ -5571,7 +5596,10 @@ namespace {
55715596
}
55725597

55735598
void addValueWitnessTable() {
5574-
B.add(asImpl().getValueWitnessTable(false).getValue());
5599+
auto vwtPointer = asImpl().getValueWitnessTable(false).getValue();
5600+
B.addSignedPointer(vwtPointer,
5601+
IGM.getOptions().PointerAuth.ValueWitnessTable,
5602+
PointerAuthEntity());
55755603
}
55765604

55775605
llvm::Constant *emitLayoutString() {
@@ -6052,7 +6080,11 @@ namespace {
60526080
}
60536081

60546082
void addValueWitnessTable() {
6055-
B.add(asImpl().getValueWitnessTable(false).getValue());
6083+
auto vwtPointer =
6084+
asImpl().getValueWitnessTable(/*relative*/ false).getValue();
6085+
B.addSignedPointer(vwtPointer,
6086+
IGM.getOptions().PointerAuth.ValueWitnessTable,
6087+
PointerAuthEntity());
60566088
}
60576089

60586090
llvm::Constant *emitNominalTypeDescriptor() {
@@ -6534,7 +6566,9 @@ namespace {
65346566
? IGM.Context.getAnyObjectType()
65356567
: IGM.Context.TheNativeObjectType);
65366568
auto wtable = IGM.getAddrOfValueWitnessTable(type);
6537-
B.add(wtable);
6569+
B.addSignedPointer(wtable,
6570+
IGM.getOptions().PointerAuth.ValueWitnessTable,
6571+
PointerAuthEntity());
65386572
}
65396573

65406574
void addMetadataFlags() {
@@ -6605,7 +6639,11 @@ namespace {
66056639

66066640
void addValueWitnessTable() {
66076641
auto type = getTargetType()->getCanonicalType();
6608-
B.add(irgen::emitValueWitnessTable(IGM, type, false, false).getValue());
6642+
auto vwtPointer =
6643+
irgen::emitValueWitnessTable(IGM, type, false, false).getValue();
6644+
B.addSignedPointer(vwtPointer,
6645+
IGM.getOptions().PointerAuth.ValueWitnessTable,
6646+
PointerAuthEntity());
66096647
}
66106648

66116649
void addMetadataFlags() {
@@ -6644,7 +6682,10 @@ namespace {
66446682
}
66456683

66466684
void addValueWitnessTable() {
6647-
B.add(emitValueWitnessTable(/*relative*/ false).getValue());
6685+
auto vwtPointer = emitValueWitnessTable(/*relative*/ false).getValue();
6686+
B.addSignedPointer(vwtPointer,
6687+
IGM.getOptions().PointerAuth.ValueWitnessTable,
6688+
PointerAuthEntity());
66486689
}
66496690

66506691
void flagUnfilledFieldOffset() {
@@ -6671,7 +6712,10 @@ namespace {
66716712
}
66726713

66736714
void addValueWitnessTable() {
6674-
B.add(emitValueWitnessTable(/*relative*/ false).getValue());
6715+
auto vwtPointer = emitValueWitnessTable(/*relative*/ false).getValue();
6716+
B.addSignedPointer(vwtPointer,
6717+
IGM.getOptions().PointerAuth.ValueWitnessTable,
6718+
PointerAuthEntity());
66756719
}
66766720

66776721
void addPayloadSize() const {

lib/IRGen/IRGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,9 @@ static void setPointerAuthOptions(PointerAuthOptions &opts,
728728
PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Decl);
729729
opts.ValueWitnesses =
730730
PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Decl);
731+
opts.ValueWitnessTable =
732+
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Constant,
733+
SpecialPointerAuthDiscriminators::ValueWitnessTable);
731734
opts.ProtocolWitnesses =
732735
PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Decl);
733736
opts.ProtocolAssociatedTypeAccessFunctions =

test/IRGen/ptrauth-value-witnesses.sil

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import Builtin
88

99
struct S { var a, b, c: Builtin.NativeObject }
10+
11+
// Check the constant discriminators for all value witnesses.
12+
1013
// CHECK: @"$s4test1SVwCP.ptrauth" = private constant {{.*}} i64 55882
1114
// CHECK: @"$s4test1SVwxx.ptrauth" = private constant {{.*}} i64 1272
1215
// CHECK: @"$s4test1SVwcp.ptrauth" = private constant {{.*}} i64 58298
@@ -16,15 +19,26 @@ struct S { var a, b, c: Builtin.NativeObject }
1619
// CHECK: @"$s4test1SVwet.ptrauth" = private constant {{.*}} i64 24816
1720
// CHECK: @"$s4test1SVwst.ptrauth" = private constant {{.*}} i64 41169
1821

22+
// The pointer to the value witness table is signed too.
23+
24+
// 0x2e3f == 11839 is the constant discriminator for value witness tables.
25+
// CHECK: @"$s4test1SVWV.ptrauth" = private constant {{.*}} i64 11839
26+
1927
sil @test_destroy : $@convention(thin) <T> (@in T) -> () {
2028
bb0(%0 : $*T):
2129
destroy_addr %0 : $*T
2230
%result = tuple ()
2331
return %result : $()
2432
}
2533
// CHECK-LABEL: define swiftcc void @test_destroy(
26-
// CHECK: [[VWT:%.*]] = load ptr,
27-
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32
34+
// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1
35+
// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]]
36+
// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]]
37+
// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839)
38+
// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]]
39+
// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]])
40+
// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]]
41+
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32
2842
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align
2943
// CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64
3044
// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 1272)
@@ -38,8 +52,14 @@ bb0(%0 : $*T, %1 : $*T):
3852
return %result : $()
3953
}
4054
// CHECK-LABEL: define swiftcc void @test_copy_init(
41-
// CHECK: [[VWT:%.*]] = load ptr,
42-
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32
55+
// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1
56+
// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]]
57+
// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]]
58+
// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839)
59+
// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]]
60+
// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]])
61+
// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]]
62+
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32
4363
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align
4464
// CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64
4565
// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 58298)
@@ -53,8 +73,14 @@ bb0(%0 : $*T, %1 : $*T):
5373
return %result : $()
5474
}
5575
// CHECK-LABEL: define swiftcc void @test_take_init(
56-
// CHECK: [[VWT:%.*]] = load ptr,
57-
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32
76+
// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1
77+
// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]]
78+
// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]]
79+
// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839)
80+
// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]]
81+
// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]])
82+
// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]]
83+
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32
5884
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align
5985
// CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64
6086
// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 18648)
@@ -68,8 +94,14 @@ bb0(%0 : $*T, %1 : $*T):
6894
return %result : $()
6995
}
7096
// CHECK-LABEL: define swiftcc void @test_copy_assign(
71-
// CHECK: [[VWT:%.*]] = load ptr,
72-
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32
97+
// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1
98+
// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]]
99+
// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]]
100+
// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839)
101+
// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]]
102+
// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]])
103+
// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]]
104+
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32
73105
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align
74106
// CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64
75107
// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 34641)
@@ -83,8 +115,14 @@ bb0(%0 : $*T, %1 : $*T):
83115
return %result : $()
84116
}
85117
// CHECK-LABEL: define swiftcc void @test_take_assign(
86-
// CHECK: [[VWT:%.*]] = load ptr,
87-
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32
118+
// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1
119+
// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]]
120+
// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]]
121+
// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839)
122+
// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]]
123+
// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]])
124+
// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]]
125+
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32
88126
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align
89127
// CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64
90128
// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 61402)
@@ -100,8 +138,14 @@ bb0(%0 : $*T, %1 : $*T):
100138
return %result : $()
101139
}
102140
// CHECK-LABEL: define swiftcc void @test_destroy_twice(
103-
// CHECK: [[VWT:%.*]] = load ptr,
104-
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32
141+
// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1
142+
// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]]
143+
// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]]
144+
// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839)
145+
// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]]
146+
// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]])
147+
// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]]
148+
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32
105149
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align
106150
// CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64
107151
// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 1272)

0 commit comments

Comments
 (0)