Fix KCFI types for generated functions with integer normalization (#104826)

With -fsanitize-cfi-icall-experimental-normalize-integers, Clang
appends ".normalized" to KCFI types in CodeGenModule::CreateKCFITypeId,
which changes type hashes also for functions that don't have integer
types in their signatures. However, llvm::setKCFIType does not take
integer normalization into account, which means LLVM generated
functions with KCFI types, e.g. sanitizer constructors, will fail KCFI
checks when integer normalization is enabled in Clang.

Add a cfi-normalize-integers module flag to indicate integer
normalization is used, and append ".normalized" to KCFI types also in
llvm::setKCFIType to fix the type mismatch.
This commit is contained in:
Sami Tolvanen
2024-08-20 16:51:16 -07:00
committed by GitHub
parent 3145cff24b
commit e1c36bde05
5 changed files with 53 additions and 8 deletions

View File

@@ -1134,6 +1134,11 @@ void CodeGenModule::Release() {
CodeGenOpts.SanitizeCfiCanonicalJumpTables);
}
if (CodeGenOpts.SanitizeCfiICallNormalizeIntegers) {
getModule().addModuleFlag(llvm::Module::Override, "cfi-normalize-integers",
1);
}
if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {
getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1);
// KCFI assumes patchable-function-prefix is the same for all indirectly

View File

@@ -28,6 +28,7 @@ void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
fn(arg1, arg2, arg3);
}
// CHECK: ![[#]] = !{i32 4, !"cfi-normalize-integers", i32 1}
// CHECK: ![[TYPE1]] = !{i32 -1143117868}
// CHECK: ![[TYPE2]] = !{i32 -460921415}
// CHECK: ![[TYPE3]] = !{i32 -333839615}

View File

@@ -205,11 +205,13 @@ void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
// Matches CodeGenModule::CreateKCFITypeId in Clang.
LLVMContext &Ctx = M.getContext();
MDBuilder MDB(Ctx);
F.setMetadata(
LLVMContext::MD_kcfi_type,
MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
Type::getInt32Ty(Ctx),
static_cast<uint32_t>(xxHash64(MangledType))))));
std::string Type = MangledType.str();
if (M.getModuleFlag("cfi-normalize-integers"))
Type += ".normalized";
F.setMetadata(LLVMContext::MD_kcfi_type,
MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
Type::getInt32Ty(Ctx),
static_cast<uint32_t>(xxHash64(Type))))));
// If the module was compiled with -fpatchable-function-entry, ensure
// we use the same patchable-function-prefix.
if (auto *MD = mdconst::extract_or_null<ConstantInt>(

View File

@@ -0,0 +1,35 @@
;; Ensure __llvm_gcov_(writeout|reset|init) have the correct !kcfi_type
;; with integer normalization.
; RUN: mkdir -p %t && cd %t
; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
define dso_local void @empty() !dbg !5 {
entry:
ret void, !dbg !8
}
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !9, !10}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "a.c", directory: "")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 5}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = distinct !DISubprogram(name: "empty", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!6 = !DISubroutineType(types: !7)
!7 = !{null}
!8 = !DILocation(line: 2, column: 1, scope: !5)
!9 = !{i32 4, !"kcfi", i32 1}
!10 = !{i32 4, !"cfi-normalize-integers", i32 1}
; CHECK: define internal void @__llvm_gcov_writeout()
; CHECK-SAME: !kcfi_type ![[#TYPE:]]
; CHECK: define internal void @__llvm_gcov_reset()
; CHECK-SAME: !kcfi_type ![[#TYPE]]
; CHECK: define internal void @__llvm_gcov_init()
; CHECK-SAME: !kcfi_type ![[#TYPE]]
; CHECK: ![[#TYPE]] = !{i32 -440107680}

View File

@@ -24,8 +24,10 @@ entry:
!9 = !{i32 4, !"kcfi", i32 1}
; CHECK: define internal void @__llvm_gcov_writeout()
; CHECK-SAME: !kcfi_type
; CHECK-SAME: !kcfi_type ![[#TYPE:]]
; CHECK: define internal void @__llvm_gcov_reset()
; CHECK-SAME: !kcfi_type
; CHECK-SAME: !kcfi_type ![[#TYPE]]
; CHECK: define internal void @__llvm_gcov_init()
; CHECK-SAME: !kcfi_type
; CHECK-SAME: !kcfi_type ![[#TYPE]]
; CHECK: ![[#TYPE]] = !{i32 -1522505972}