Skip to content

Commit 3f6c0e6

Browse files
authored
[clang][KCFI] Respect -fsanitize-cfi-icall-generalize-pointers (#152400)
This flag was previously ignored by KCFI.
1 parent 2fc1b3d commit 3f6c0e6

File tree

4 files changed

+75
-32
lines changed

4 files changed

+75
-32
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,7 +2335,40 @@ llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
23352335
return llvm::ConstantInt::get(Int64Ty, llvm::MD5Hash(MDS->getString()));
23362336
}
23372337

2338+
// Generalize pointer types to a void pointer with the qualifiers of the
2339+
// originally pointed-to type, e.g. 'const char *' and 'char * const *'
2340+
// generalize to 'const void *' while 'char *' and 'const char **' generalize to
2341+
// 'void *'.
2342+
static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
2343+
if (!Ty->isPointerType())
2344+
return Ty;
2345+
2346+
return Ctx.getPointerType(
2347+
QualType(Ctx.VoidTy)
2348+
.withCVRQualifiers(Ty->getPointeeType().getCVRQualifiers()));
2349+
}
2350+
2351+
// Apply type generalization to a FunctionType's return and argument types
2352+
static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) {
2353+
if (auto *FnType = Ty->getAs<FunctionProtoType>()) {
2354+
SmallVector<QualType, 8> GeneralizedParams;
2355+
for (auto &Param : FnType->param_types())
2356+
GeneralizedParams.push_back(GeneralizeType(Ctx, Param));
2357+
2358+
return Ctx.getFunctionType(GeneralizeType(Ctx, FnType->getReturnType()),
2359+
GeneralizedParams, FnType->getExtProtoInfo());
2360+
}
2361+
2362+
if (auto *FnType = Ty->getAs<FunctionNoProtoType>())
2363+
return Ctx.getFunctionNoProtoType(
2364+
GeneralizeType(Ctx, FnType->getReturnType()));
2365+
2366+
llvm_unreachable("Encountered unknown FunctionType");
2367+
}
2368+
23382369
llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
2370+
if (getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
2371+
T = GeneralizeFunctionType(getContext(), T);
23392372
if (auto *FnType = T->getAs<FunctionProtoType>())
23402373
T = getContext().getFunctionType(
23412374
FnType->getReturnType(), FnType->getParamTypes(),
@@ -2348,6 +2381,8 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
23482381

23492382
if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
23502383
Out << ".normalized";
2384+
if (getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
2385+
Out << ".generalized";
23512386

23522387
return llvm::ConstantInt::get(Int32Ty,
23532388
static_cast<uint32_t>(llvm::xxHash64(OutName)));
@@ -7886,38 +7921,6 @@ CodeGenModule::CreateMetadataIdentifierForVirtualMemPtrType(QualType T) {
78867921
return CreateMetadataIdentifierImpl(T, VirtualMetadataIdMap, ".virtual");
78877922
}
78887923

7889-
// Generalize pointer types to a void pointer with the qualifiers of the
7890-
// originally pointed-to type, e.g. 'const char *' and 'char * const *'
7891-
// generalize to 'const void *' while 'char *' and 'const char **' generalize to
7892-
// 'void *'.
7893-
static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
7894-
if (!Ty->isPointerType())
7895-
return Ty;
7896-
7897-
return Ctx.getPointerType(
7898-
QualType(Ctx.VoidTy).withCVRQualifiers(
7899-
Ty->getPointeeType().getCVRQualifiers()));
7900-
}
7901-
7902-
// Apply type generalization to a FunctionType's return and argument types
7903-
static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) {
7904-
if (auto *FnType = Ty->getAs<FunctionProtoType>()) {
7905-
SmallVector<QualType, 8> GeneralizedParams;
7906-
for (auto &Param : FnType->param_types())
7907-
GeneralizedParams.push_back(GeneralizeType(Ctx, Param));
7908-
7909-
return Ctx.getFunctionType(
7910-
GeneralizeType(Ctx, FnType->getReturnType()),
7911-
GeneralizedParams, FnType->getExtProtoInfo());
7912-
}
7913-
7914-
if (auto *FnType = Ty->getAs<FunctionNoProtoType>())
7915-
return Ctx.getFunctionNoProtoType(
7916-
GeneralizeType(Ctx, FnType->getReturnType()));
7917-
7918-
llvm_unreachable("Encountered unknown FunctionType");
7919-
}
7920-
79217924
llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) {
79227925
return CreateMetadataIdentifierImpl(GeneralizeFunctionType(getContext(), T),
79237926
GeneralizedMetadataIdMap, ".generalized");

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
851851
}
852852

853853
if (AllAddedKinds & SanitizerKind::KCFI) {
854+
CfiICallGeneralizePointers =
855+
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
854856
CfiICallNormalizeIntegers =
855857
Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
856858

clang/test/CodeGen/kcfi-generalize.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=kcfi -fsanitize-trap=kcfi -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=UNGENERALIZED %s
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=kcfi -fsanitize-trap=kcfi -fsanitize-cfi-icall-generalize-pointers -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GENERALIZED %s
3+
4+
// Test that const char* is generalized to const ptr and that char** is
5+
// generalized to ptr
6+
7+
// CHECK: define{{.*}} ptr @f({{.*}} !kcfi_type [[TYPE:![0-9]+]]
8+
int** f(const char *a, const char **b) {
9+
return (int**)0;
10+
}
11+
12+
// GENERALIZED: define{{.*}} ptr @f2({{.*}} !kcfi_type [[TYPE]]
13+
// UNGENERALIZED: define{{.*}} ptr @f2({{.*}} !kcfi_type [[TYPE2:![0-9]+]]
14+
int** f2(const int *a, const int **b) {
15+
return (int**)0;
16+
}
17+
18+
// CHECK: define{{.*}} ptr @f3({{.*}} !kcfi_type [[TYPE3:![0-9]+]]
19+
int** f3(char *a, char **b) {
20+
return (int**)0;
21+
}
22+
23+
void g(int** (*fp)(const char *, const char **)) {
24+
// UNGENERALIZED: call {{.*}} [ "kcfi"(i32 1296635908) ]
25+
// GENERALIZED: call {{.*}} [ "kcfi"(i32 -49168686) ]
26+
fp(0, 0);
27+
}
28+
29+
// UNGENERALIZED: [[TYPE]] = !{i32 1296635908}
30+
// GENERALIZED: [[TYPE]] = !{i32 -49168686}
31+
32+
// UNGENERALIZED: [[TYPE3]] = !{i32 874141567}
33+
// GENERALIZED: [[TYPE3]] = !{i32 954385378}

clang/test/Driver/fsanitize.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,11 @@
794794
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-icall-generalize-pointers -fsanitize-cfi-cross-dso -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-GENERALIZE-AND-CROSS-DSO
795795
// CHECK-CFI-GENERALIZE-AND-CROSS-DSO: error: invalid argument '-fsanitize-cfi-cross-dso' not allowed with '-fsanitize-cfi-icall-generalize-pointers'
796796

797+
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fsanitize-cfi-icall-generalize-pointers -fvisibility=hidden -flto -c -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-GENERALIZE-POINTERS
798+
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fvisibility=hidden -flto -c -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-KCFI-GENERALIZE-POINTERS
799+
// CHECK-KCFI-GENERALIZE-POINTERS: -fsanitize-cfi-icall-generalize-pointers
800+
// CHECK-NO-KCFI-GENERALIZE-POINTERS-NOT: -fsanitize-cfi-icall-generalize-pointers
801+
797802
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-canonical-jump-tables -fvisibility=hidden -flto -c -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-CANONICAL-JUMP-TABLES
798803
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=cfi-icall -fno-sanitize-cfi-canonical-jump-tables -fvisibility=hidden -flto -c %s -resource-dir=%S/Inputs/resource_dir -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-CFI-CANONICAL-JUMP-TABLES
799804
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=cfi-icall -fvisibility=hidden -flto -c -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-CANONICAL-JUMP-TABLES

0 commit comments

Comments
 (0)