How a ptrauth blend constant is calculated for Swift methods?

Hello,

I am researching how arm64e pointer authentication signing is implemented in Swift metadata, and I’ve noticed that for Swift methods, the metadata pointers are signed with a blend constant (the last argument of the .ptrauth IR structure) which is different for each method (I suppose it is derived from the method index, to prevent malicious method substitution, perhaps some hash of a method index number in a class?). In the example below its value is 41900:

@"$s12TestSwiftApp04OpenB5ClassC6getBtrSSyF.ptrauth" = private constant { ptr, i32, i64, i64 } { ptr @"$s12TestSwiftApp04OpenB5ClassC6getBtrSSyF", i32 0, i64 ptrtoint (ptr getelementptr inbounds (<{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, i32, i32, i32, i16, i16, i32, i32, ptr, ptr, i64, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr @"$s12TestSwiftApp04OpenB5ClassCMf", i32 0, i32 23) to i64), i64 41900 }, section "llvm.ptrauth", align 8

However another method of the same class has a different blend constant value of 58007:

@"$s12TestSwiftApp04OpenB5ClassC6getStrSSyF.ptrauth" = private constant { ptr, i32, i64, i64 } { ptr @"$s12TestSwiftApp04OpenB5ClassC6getStrSSyF", i32 0, i64 ptrtoint (ptr getelementptr inbounds (<{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, i32, i32, i32, i16, i16, i32, i32, ptr, ptr, i64, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr @"$s12TestSwiftApp04OpenB5ClassCMf", i32 0, i32 22) to i64), i64 58007 }, section "llvm.ptrauth", align 8

Can you please explain how this value is derived? I wasn’t able to find this in Swift source code.

Also I was wondering, how stable is implementation of signing of metadata structures in Swift in general, does it stay the same between Swift releases, or does it improve/harden with every new major Swift version?

Thank you

The signatures for functions and methods are derived from their types; this protects against attacks based on type confusion — you can only successfully use a signed function pointer if it is the same type as the one that the code expects. You can see the code that computes the discriminators used for pointer authentication in lib/IRGen/GenPointerAuth.cpp.

As for the signing of metadata structures, we do sometimes harden it — though we will obviously take care to keep existing software working one way or another.

1 Like

Thanks Alastair!