diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst index 96eb498bc48b6..6f1733405d834 100644 --- a/clang/docs/PointerAuthentication.rst +++ b/clang/docs/PointerAuthentication.rst @@ -1429,10 +1429,11 @@ to be trivially copyable, which means they must be copyable with ``memcpy``. The use of a uniform constant discriminator greatly simplifies the adoption of arm64e, but it is a significant weakness in the mitigation because it allows any -C function pointer to be replaced with another. Clang supports -`-fptrauth-function-pointer-type-discrimination`, which enables a variant ABI -that uses type discrimination for function pointers. When generating the type -based discriminator for a function type all primitive integer types are +C function pointer to be replaced with another. The `-Wptrauth-weak-schema` +diagnostic warns about the use of weak pointer authentication schemas. Clang +supports `-fptrauth-function-pointer-type-discrimination`, which enables a +variant ABI that uses type discrimination for function pointers. When generating +the type based discriminator for a function type all primitive integer types are considered equivalent due to the prevalence of mismatching integer parameter types in real world code. Type discrimination of function pointers is ABI-incompatible with the standard arm64e ABI, but it can be used in constrained diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e1e497ccdbccd..21c1f87ef12ed 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -283,6 +283,12 @@ Improvements to Clang's diagnostics pointers under ``-Wthread-safety-beta`` (still experimental), which reduces both false positives but also false negatives through more precise analysis. +- A new warning ``-Wptrauth-weak-schema`` has been added to detect variable + declarations of function pointer type and internal linkage that use a weak + pointer authentication schema, either implicitly or by specifying a discriminator + with no diversifiers. This warning applies only to targets supporting pointer + authentication when the feature is enabled. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 1c17333b722f8..1580968e857d7 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -659,6 +659,11 @@ class ASTContext : public RefCountedBase { return findPointerAuthContent(T) != PointerAuthContent::None; } + // A simple helper function to short circuit pointer auth checks. + bool isPointerAuthenticationAvailable() const { + return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; + } + private: llvm::DenseMap RelocatableClasses; @@ -670,10 +675,6 @@ class ASTContext : public RefCountedBase { AddressDiscriminatedData }; - // A simple helper function to short circuit pointer auth checks. - bool isPointerAuthenticationAvailable() const { - return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; - } PointerAuthContent findPointerAuthContent(QualType T) const; mutable llvm::DenseMap RecordContainsAddressDiscriminatedPointerAuth; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b0e669cd3560d..35bedc9349686 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1046,6 +1046,11 @@ def err_ptrauth_address_discrimination_invalid : Error< def err_ptrauth_extra_discriminator_invalid : Error< "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between " "'0' and '%1'">; +def warn_ptrauth_weak_schema + : Warning<"%0 has internal linkage with a %select{|default }1" + "pointer authentication schema that should be overridden by " + "%select{a|an explicit}1 schema with unique diversifiers">, + InGroup>; /// main() // static main() is not an error in C, just in C++. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a7600ab88febe..ae1db0fab28c0 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3976,6 +3976,10 @@ class Sema final : public SemaBase { void CheckVariableDeclarationType(VarDecl *NewVD); void CheckCompleteVariableDeclaration(VarDecl *VD); + // Warn about the use of a weak pointer authentication schema on a variable of + // function pointer type and internal linkage. + void DiagnoseWeakPointerAuthenticationSchema(VarDecl *VD); + NamedDecl *ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7c1459e320167..b129d73cdc045 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7627,6 +7627,16 @@ static bool isMainVar(DeclarationName Name, VarDecl *VD) { VD->isExternC()); } +void Sema::DiagnoseWeakPointerAuthenticationSchema(VarDecl *VD) { + if (!Context.isPointerAuthenticationAvailable()) + return; + if (VD->isFunctionPointerType() && !VD->isExternallyVisible()) { + PointerAuthQualifier Q = VD->getType().getQualifiers().getPointerAuth(); + if (!Q || (!Q.isAddressDiscriminated() && Q.getExtraDiscriminator() == 0)) + Diag(VD->getLocation(), diag::warn_ptrauth_weak_schema) << VD << !Q; + } +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -8357,6 +8367,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( D.isFunctionDefinition()); } + DiagnoseWeakPointerAuthenticationSchema(NewVD); + if (NewTemplate) { if (NewVD->isInvalidDecl()) NewTemplate->setInvalidDecl(); diff --git a/clang/test/Sema/ptrauth-weak-schema.c b/clang/test/Sema/ptrauth-weak-schema.c new file mode 100644 index 0000000000000..1e48d01d6a796 --- /dev/null +++ b/clang/test/Sema/ptrauth-weak-schema.c @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls -fptrauth-intrinsics -fsyntax-only -Wno-unused-variable -verify %s +// RUN: %clang_cc1 -triple arm64e-apple-ios -DNO_PTRAUTH -fsyntax-only -Wno-unused-variable -verify=noptrauth %s + +// noptrauth-no-diagnostics + +#include + +#if defined(__PTRAUTH__) == defined(NO_PTRAUTH) +#error expected pointer authentication state does not match actual +#endif + +#if defined(NO_PTRAUTH) +#define FN_PTR_AUTH(address_diversity, constant_discriminator) +#else +#define FN_PTR_AUTH(address_diversity, constant_discriminator) \ + __ptrauth(ptrauth_key_function_pointer, address_diversity, constant_discriminator) +#endif + +// Global variables with external linkage and weak pointer authentication should +// not raise any warning. +extern void(* g1_external_weak)(void); +void(* FN_PTR_AUTH(0, 0) g2_external_weak)(void); + +// Global variables with internal linkage and strong pointer authentication +// should not raise any warning. +static void(* FN_PTR_AUTH(1, 65535) g1_internal_strong)(void); +static void(* FN_PTR_AUTH(0, 65535) g2_internal_strong)(void); +static void(* FN_PTR_AUTH(1, 0) g3_internal_strong)(void); + +#if !defined(NO_PTRAUTH) +// Global variables with internal linkage and weak pointer authentication should +// raise a warning. +static void(* g1_internal_weak)(void); +// expected-warning@-1 {{'g1_internal_weak' has internal linkage with a default pointer authentication schema that should be overridden by an explicit schema with unique diversifiers}} +static void(* FN_PTR_AUTH(0, 0) g2_internal_weak)(void); +// expected-warning@-1 {{'g2_internal_weak' has internal linkage with a pointer authentication schema that should be overridden by a schema with unique diversifiers}} + +// Assert that -Wptrauth-weak-schema silences warnings. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wptrauth-weak-schema" +static void(* g3_internal_weak)(void); +#pragma clang diagnostic pop +#endif + +void test_local_variables(void) { + #if !defined(NO_PTRAUTH) + // Local variables (internal linkage) with weak pointer authentication + // should raise a warning. + static void(* l1_internal_weak)(void); + // expected-warning@-1 {{'l1_internal_weak' has internal linkage with a default pointer authentication schema that should be overridden by an explicit schema with unique diversifiers}} + static void(* FN_PTR_AUTH(0, 0) l2_internal_weak)(void); + // expected-warning@-1 {{'l2_internal_weak' has internal linkage with a pointer authentication schema that should be overridden by a schema with unique diversifiers}} + void(* l3_internal_weak)(void); + // expected-warning@-1 {{'l3_internal_weak' has internal linkage with a default pointer authentication schema that should be overridden by an explicit schema with unique diversifiers}} + void(* FN_PTR_AUTH(0, 0) l4_internal_weak)(void); + // expected-warning@-1 {{'l4_internal_weak' has internal linkage with a pointer authentication schema that should be overridden by a schema with unique diversifiers}} + #endif + + // Local variables (internal linkage) with strong pointer authentication + // should not raise any warning. + static void(* FN_PTR_AUTH(1, 65535) l1_internal_strong)(void); + static void(* FN_PTR_AUTH(0, 65535) l2_internal_strong)(void); + static void(* FN_PTR_AUTH(1, 0) l3_internal_strong)(void); + void(* FN_PTR_AUTH(1, 65535) l4_internal_strong)(void); + void(* FN_PTR_AUTH(0, 65535) l5_internal_strong)(void); + void(* FN_PTR_AUTH(1, 0) l6_internal_strong)(void); +}