Skip to content

Commit 347b0f5

Browse files
authored
Merge pull request #64266 from meg-gupta/fixnil
Fix IRGen for pointer auth qualified field function pointers when they are null
2 parents a528000 + c0204d3 commit 347b0f5

File tree

2 files changed

+101
-31
lines changed

2 files changed

+101
-31
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5869,26 +5869,52 @@ void IRGenSILFunction::visitBeginAccessInst(BeginAccessInst *access) {
58695869
auto *Int64PtrPtrTy = Int64PtrTy->getPointerTo();
58705870
if (access->getAccessKind() == SILAccessKind::Read) {
58715871
// When we see a signed read access, generate code to:
5872-
// authenticate the signed pointer, and store the authenticated value to a
5873-
// shadow stack location. Set the lowered address of the access to this
5874-
// stack location.
5872+
// authenticate the signed pointer if non-null, and store the
5873+
// authenticated value to a shadow stack location. Set the lowered address
5874+
// of the access to this stack location.
58755875
auto pointerAuthQual = sea->getField()->getPointerAuthQualifier();
58765876
auto *pointerToSignedFptr = getLoweredAddress(sea).getAddress();
58775877
auto *pointerToIntPtr =
58785878
Builder.CreateBitCast(pointerToSignedFptr, Int64PtrPtrTy);
58795879
auto *signedFptr = Builder.CreateLoad(pointerToIntPtr, Int64PtrTy,
58805880
IGM.getPointerAlignment());
5881-
auto *resignedFptr = emitPointerAuthResign(
5882-
*this, signedFptr,
5883-
PointerAuthInfo::emit(*this, pointerAuthQual, pointerToSignedFptr),
5884-
PointerAuthInfo::emit(*this,
5885-
IGM.getOptions().PointerAuth.FunctionPointers,
5886-
pointerToSignedFptr, PointerAuthEntity()));
5881+
5882+
// Create a stack temporary.
58875883
auto temp = ti.allocateStack(*this, access->getType(), "ptrauth.temp");
58885884
auto *tempAddressToIntPtr =
58895885
Builder.CreateBitCast(temp.getAddressPointer(), Int64PtrPtrTy);
5886+
5887+
// Branch based on pointer is null or not.
5888+
llvm::Value *cond = Builder.CreateICmpNE(
5889+
signedFptr, llvm::ConstantPointerNull::get(Int64PtrTy));
5890+
auto *resignNonNull = createBasicBlock("resign-nonnull");
5891+
auto *resignNull = createBasicBlock("resign-null");
5892+
auto *resignCont = createBasicBlock("resign-cont");
5893+
Builder.CreateCondBr(cond, resignNonNull, resignNull);
5894+
5895+
// Resign if non-null.
5896+
Builder.emitBlock(resignNonNull);
5897+
auto oldAuthInfo =
5898+
PointerAuthInfo::emit(*this, pointerAuthQual, pointerToSignedFptr);
5899+
// ClangImporter imports the c function pointer as an optional type.
5900+
PointerAuthEntity entity(
5901+
sea->getType().getOptionalObjectType().getAs<SILFunctionType>());
5902+
auto newAuthInfo = PointerAuthInfo::emit(
5903+
*this, IGM.getOptions().PointerAuth.FunctionPointers,
5904+
pointerToSignedFptr, entity);
5905+
auto *resignedFptr =
5906+
emitPointerAuthResign(*this, signedFptr, oldAuthInfo, newAuthInfo);
58905907
Builder.CreateStore(resignedFptr, tempAddressToIntPtr,
58915908
IGM.getPointerAlignment());
5909+
Builder.CreateBr(resignCont);
5910+
5911+
// If null, no need to resign.
5912+
Builder.emitBlock(resignNull);
5913+
Builder.CreateStore(signedFptr, tempAddressToIntPtr,
5914+
IGM.getPointerAlignment());
5915+
Builder.CreateBr(resignCont);
5916+
5917+
Builder.emitBlock(resignCont);
58925918
setLoweredAddress(access, temp.getAddress());
58935919
return;
58945920
}
@@ -5990,30 +6016,55 @@ void IRGenSILFunction::visitEndAccessInst(EndAccessInst *i) {
59906016
return;
59916017
}
59926018
// When we see a signed modify access, get the lowered address of the
5993-
// access which is the shadow stack slot, sign the value and write back to
5994-
// the struct field.
6019+
// access which is the shadow stack slot, sign the value if non-null and
6020+
// write back to the struct field.
6021+
auto *sea = cast<StructElementAddrInst>(access->getOperand());
59956022
auto *Int64PtrTy = llvm::Type::getInt64PtrTy(IGM.getLLVMContext());
59966023
auto *Int64PtrPtrTy = Int64PtrTy->getPointerTo();
59976024
auto pointerAuthQual = cast<StructElementAddrInst>(access->getOperand())
59986025
->getField()
59996026
->getPointerAuthQualifier();
60006027
auto *pointerToSignedFptr =
60016028
getLoweredAddress(access->getOperand()).getAddress();
6029+
auto *pointerToIntPtr =
6030+
Builder.CreateBitCast(pointerToSignedFptr, Int64PtrPtrTy);
60026031
auto tempAddress = getLoweredAddress(access);
60036032
auto *tempAddressToIntPtr =
60046033
Builder.CreateBitCast(tempAddress.getAddress(), Int64PtrPtrTy);
60056034
auto *tempAddressValue = Builder.CreateLoad(tempAddressToIntPtr, Int64PtrTy,
60066035
IGM.getPointerAlignment());
6007-
auto *signedFptr = emitPointerAuthResign(
6008-
*this, tempAddressValue,
6009-
PointerAuthInfo::emit(*this,
6010-
IGM.getOptions().PointerAuth.FunctionPointers,
6011-
tempAddress.getAddress(), PointerAuthEntity()),
6012-
PointerAuthInfo::emit(*this, pointerAuthQual, pointerToSignedFptr));
6013-
6014-
auto *pointerToIntPtr =
6015-
Builder.CreateBitCast(pointerToSignedFptr, Int64PtrPtrTy);
6036+
// Branch based on value is null or not.
6037+
llvm::Value *cond = Builder.CreateICmpNE(
6038+
tempAddressValue, llvm::ConstantPointerNull::get(Int64PtrTy));
6039+
auto *resignNonNull = createBasicBlock("resign-nonnull");
6040+
auto *resignNull = createBasicBlock("resign-null");
6041+
auto *resignCont = createBasicBlock("resign-cont");
6042+
6043+
Builder.CreateCondBr(cond, resignNonNull, resignNull);
6044+
6045+
Builder.emitBlock(resignNonNull);
6046+
6047+
// If non-null, resign
6048+
// ClangImporter imports the c function pointer as an optional type.
6049+
PointerAuthEntity entity(
6050+
sea->getType().getOptionalObjectType().getAs<SILFunctionType>());
6051+
auto oldAuthInfo = PointerAuthInfo::emit(
6052+
*this, IGM.getOptions().PointerAuth.FunctionPointers,
6053+
tempAddress.getAddress(), entity);
6054+
auto newAuthInfo =
6055+
PointerAuthInfo::emit(*this, pointerAuthQual, pointerToSignedFptr);
6056+
auto *signedFptr = emitPointerAuthResign(*this, tempAddressValue,
6057+
oldAuthInfo, newAuthInfo);
60166058
Builder.CreateStore(signedFptr, pointerToIntPtr, IGM.getPointerAlignment());
6059+
6060+
Builder.CreateBr(resignCont);
6061+
6062+
// If null, no need to resign
6063+
Builder.emitBlock(resignNull);
6064+
Builder.CreateStore(tempAddressValue, pointerToIntPtr, IGM.getPointerAlignment());
6065+
Builder.CreateBr(resignCont);
6066+
6067+
Builder.emitBlock(resignCont);
60176068
return;
60186069
}
60196070
}

test/IRGen/ptrauth_field_fptr_import.swift

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,19 @@ import PointerAuth
1515
// CHECK: %.secure_func_ptr = getelementptr inbounds %TSo12SecureStructV, %TSo12SecureStructV* %14, i32 0, i32 0
1616
// CHECK: [[CAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64*
1717
// CHECK: [[PTR:%.*]] = load i64*, i64** [[CAST2]], align 8
18+
// CHECK: [[CAST3:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
19+
// CHECK: [[COND:%.*]] = icmp ne i64* %16, null
20+
// CHECK: br i1 [[COND]], label %resign-nonnull, label %resign-null
21+
// CHECK: resign-nonnull: ; preds = %12
1822
// CHECK: [[SIGNEDINT:%.*]] = ptrtoint i64* [[PTR]] to i64
1923
// CHECK: [[DEFAULTSIGNVAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[SIGNEDINT]], i32 1, i64 88, i32 0, i64 0)
2024
// CHECK: [[AUTHPTR:%.*]] = inttoptr i64 [[DEFAULTSIGNVAL]] to i64*
21-
// CHECK: [[TMPCAST1:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
22-
// CHECK: store i64* [[AUTHPTR]], i64** [[TMPCAST1]], align 8
25+
// CHECK: store i64* [[AUTHPTR]], i64** [[CAST3]], align 8
26+
// CHECK: br label %resign-cont
27+
// CHECK: resign-null: ; preds = %12
28+
// CHECK: store i64* [[PTR]], i64** [[CAST3]], align 8
29+
// CHECK: br label %resign-cont
30+
// CHECK: resign-cont: ; preds = %resign-null, %resign-nonnull
2331
// CHECK: [[TMPCAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64*
2432
// CHECK: [[FUNCPTR:%.*]] = load i64, i64* [[TMPCAST2]], align 8
2533
func test_field_fn_read() -> Int32 {
@@ -34,13 +42,16 @@ func test_field_fn_read() -> Int32 {
3442
// CHECK: %.secure_func_ptr = getelementptr inbounds %TSo12SecureStructV, %TSo12SecureStructV* [[CAST1]], i32 0, i32 0
3543
// CHECK: [[CAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64*
3644
// CHECK: store i64 ptrtoint ({ i8*, i32, i64, i64 }* @returnInt.ptrauth to i64), i64* [[CAST2]], align 8
45+
// CHECK: [[PTR:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64**
3746
// CHECK: [[CAST3:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
3847
// CHECK: [[LD:%.*]] = load i64*, i64** [[CAST3]], align 8
48+
// CHECK: [[COND:%.*]] = icmp ne i64* [[LD]], null
49+
// CHECK: br i1 [[COND]], label %resign-nonnull, label %resign-null
50+
// CHECK: resign-nonnull: ; preds = %11
3951
// CHECK: [[CAST4:%.*]] = ptrtoint i64* [[LD]] to i64
4052
// CHECK: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST4]], i32 0, i64 0, i32 1, i64 88)
4153
// CHECK: [[CAST5:%.*]] = inttoptr i64 [[SIGN]] to i64*
42-
// CHECK: [[CAST6:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64**
43-
// CHECK: store i64* [[CAST5]], i64** [[CAST6]], align 8
54+
// CHECK: store i64* [[CAST5]], i64** [[PTR]], align 8
4455
func test_field_fn_ptr_modify() {
4556
ptr_to_secure_struct!.pointee.secure_func_ptr = returnInt
4657
}
@@ -56,13 +67,18 @@ func test_field_fn_ptr_modify() {
5667
// CHECK: %.secure_func_ptr = getelementptr inbounds %TSo32AddressDiscriminatedSecureStructV, %TSo32AddressDiscriminatedSecureStructV* [[CAST1]], i32 0, i32 0
5768
// CHECK: [[CAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64**
5869
// CHECK: [[PTR:%.*]] = load i64*, i64** [[CAST2]], align 8
70+
// CHECK: [[CAST3:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
71+
// CHECK: [[COND:%.*]] = icmp ne i64* [[PTR]], null
72+
// CHECK: br i1 [[COND]], label %resign-nonnull, label %resign-null
73+
// CHECK: resign-nonnull: ; preds = %12
5974
// CHECK: [[ADDR:%.*]] = ptrtoint %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64
6075
// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 88)
61-
// CHECK: [[CAST3:%.*]] = ptrtoint i64* [[PTR]] to i64
62-
// CHECK: [[DEFAULTSIGNVAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST3]], i32 1, i64 [[BLEND]], i32 0, i64 0)
76+
// CHECK: [[CAST4:%.*]] = ptrtoint i64* [[PTR]] to i64
77+
// CHECK: [[DEFAULTSIGNVAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST4]], i32 1, i64 [[BLEND]], i32 0, i64 0)
6378
// CHECK: [[AUTHPTR:%.*]] = inttoptr i64 [[DEFAULTSIGNVAL]] to i64*
64-
// CHECK: [[TMPCAST1:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
65-
// CHECK: store i64* [[AUTHPTR]], i64** [[TMPCAST1]], align 8
79+
// CHECK: store i64* [[AUTHPTR]], i64** [[CAST3]], align 8
80+
// CHECK: br label %resign-cont
81+
// CHECK: resign-cont: ; preds = %resign-null, %resign-nonnull
6682
// CHECK: [[TMPCAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64*
6783
// CHECK: [[FUNCPTR:%.*]] = load i64, i64* [[TMPCAST2]], align 8
6884
func test_addr_discriminated_field_fn_read() -> Int32 {
@@ -82,15 +98,18 @@ func test_addr_discriminated_field_fn_read() -> Int32 {
8298
// CHECK: %.secure_func_ptr = getelementptr inbounds %TSo32AddressDiscriminatedSecureStructV, %TSo32AddressDiscriminatedSecureStructV* [[CAST1]], i32 0, i32 0
8399
// CHECK: [[CAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64*
84100
// CHECK: store i64 ptrtoint ({ i8*, i32, i64, i64 }* @returnInt.ptrauth to i64), i64* [[CAST2]], align 8
101+
// CHECK: [[PTR:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64**
85102
// CHECK: [[CAST3:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
86103
// CHECK: [[LD:%.*]] = load i64*, i64** [[CAST3]], align 8
104+
// CHECK: [[COND:%.*]] = icmp ne i64* [[LD]], null
105+
// CHECK: br i1 [[COND]], label %resign-nonnull, label %resign-null
106+
// CHECK: resign-nonnull: ; preds = %11
87107
// CHECK: [[CAST4:%.*]] = ptrtoint %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64
88108
// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST4]], i64 88)
89109
// CHECK: [[CAST5:%.*]] = ptrtoint i64* [[LD]] to i64
90110
// CHECK: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST5]], i32 0, i64 0, i32 1, i64 [[BLEND]])
91-
// CHECK: [[CAST5:%.*]] = inttoptr i64 [[SIGN]] to i64*
92-
// CHECK: [[CAST6:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64**
93-
// CHECK: store i64* [[CAST5]], i64** [[CAST6]], align 8
111+
// CHECK: [[CAST6:%.*]] = inttoptr i64 [[SIGN]] to i64*
112+
// CHECK: store i64* [[CAST6]], i64** [[PTR]], align 8
94113
func test_addr_discriminated_field_fn_ptr_modify() {
95114
ptr_to_addr_discriminated_secure_struct!.pointee.secure_func_ptr = returnInt
96115
}

0 commit comments

Comments
 (0)