Skip to content

Commit 7ee5e43

Browse files
committed
[CodeGen][KCFI] Provide alternative KCFI hash
In order to transition between KCFI hash, we need to be able to specify them. Add the Clang option -fsanitize-kcfi-hash= and a IR module option "kcfi-hash" that can choose between xxHash64 and FNV-1a. Default to xxHash64 to stay backward compatible, as we'll need to also update rustc to take a new option to change the hash to FNV-1a for interop with the coming GCC KCFI.
1 parent a6c1fda commit 7ee5e43

File tree

7 files changed

+90
-9
lines changed

7 files changed

+90
-9
lines changed

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/Frontend/Debug/Options.h"
2222
#include "llvm/Frontend/Driver/CodeGenOptions.h"
2323
#include "llvm/Support/CodeGen.h"
24+
#include "llvm/Support/Hash.h"
2425
#include "llvm/Support/Regex.h"
2526
#include "llvm/Target/TargetOptions.h"
2627
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
@@ -514,6 +515,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
514515
/// binary metadata pass should not be instrumented.
515516
std::vector<std::string> SanitizeMetadataIgnorelistFiles;
516517

518+
/// Hash algorithm to use for KCFI type IDs.
519+
llvm::KCFIHashAlgorithm SanitizeKcfiHash;
520+
517521
/// Name of the stack usage file (i.e., .su file) if user passes
518522
/// -fstack-usage. If empty, it can be implied that -fstack-usage is not
519523
/// passed on the command line.

clang/include/clang/Options/Options.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,6 +2690,16 @@ def fsanitize_kcfi_arity : Flag<["-"], "fsanitize-kcfi-arity">,
26902690
Group<f_clang_Group>,
26912691
HelpText<"Embed function arity information into the KCFI patchable function prefix">,
26922692
MarshallingInfoFlag<CodeGenOpts<"SanitizeKcfiArity">>;
2693+
def fsanitize_kcfi_hash_EQ
2694+
: Joined<["-"], "fsanitize-kcfi-hash=">,
2695+
HelpText<"Select hash algorithm for KCFI type IDs (xxHash64, FNV-1a)">,
2696+
Visibility<[ClangOption, CC1Option]>,
2697+
Values<"xxHash64,FNV-1a">,
2698+
NormalizedValuesScope<"llvm">,
2699+
NormalizedValues<["KCFIHashAlgorithm::xxHash64",
2700+
"KCFIHashAlgorithm::FNV1a"]>,
2701+
MarshallingInfoEnum<CodeGenOpts<"SanitizeKcfiHash">,
2702+
"KCFIHashAlgorithm::xxHash64">;
26932703
defm sanitize_stats : BoolOption<"f", "sanitize-stats",
26942704
CodeGenOpts<"SanitizeStats">, DefaultFalse,
26952705
PosFlag<SetTrue, [], [ClangOption], "Enable">,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include "llvm/Support/CommandLine.h"
6767
#include "llvm/Support/ConvertUTF.h"
6868
#include "llvm/Support/ErrorHandling.h"
69+
#include "llvm/Support/Hash.h"
6970
#include "llvm/Support/TimeProfiler.h"
7071
#include "llvm/TargetParser/RISCVISAInfo.h"
7172
#include "llvm/TargetParser/Triple.h"
@@ -1272,6 +1273,12 @@ void CodeGenModule::Release() {
12721273
CodeGenOpts.PatchableFunctionEntryOffset);
12731274
if (CodeGenOpts.SanitizeKcfiArity)
12741275
getModule().addModuleFlag(llvm::Module::Override, "kcfi-arity", 1);
1276+
// Store the hash algorithm choice for use in LLVM passes
1277+
getModule().addModuleFlag(
1278+
llvm::Module::Override, "kcfi-hash",
1279+
llvm::MDString::get(
1280+
getLLVMContext(),
1281+
llvm::stringifyKCFIHashAlgorithm(CodeGenOpts.SanitizeKcfiHash)));
12751282
}
12761283

12771284
if (CodeGenOpts.CFProtectionReturn &&
@@ -2434,7 +2441,8 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T, StringRef Salt) {
24342441
if (getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
24352442
Out << ".generalized";
24362443

2437-
return llvm::ConstantInt::get(Int32Ty, llvm::getKCFITypeID(OutName));
2444+
return llvm::ConstantInt::get(
2445+
Int32Ty, llvm::getKCFITypeID(OutName, getCodeGenOpts().SanitizeKcfiHash));
24382446
}
24392447

24402448
void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,

clang/test/CodeGen/kcfi-hash.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -o - %s | FileCheck --check-prefix=DEFAULT %s
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-kcfi-hash=xxHash64 -o - %s | FileCheck --check-prefix=XXHASH %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-kcfi-hash=FNV-1a -o - %s | FileCheck --check-prefix=FNV %s
4+
5+
void foo(void) {}
6+
7+
// DEFAULT: ![[#]] = !{i32 4, !"kcfi-hash", !"xxHash64"}
8+
// XXHASH: ![[#]] = !{i32 4, !"kcfi-hash", !"xxHash64"}
9+
// FNV: ![[#]] = !{i32 4, !"kcfi-hash", !"FNV-1a"}

llvm/include/llvm/Support/Hash.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,20 @@
1818

1919
namespace llvm {
2020

21-
/// Compute KCFI type ID from mangled type name using FNV-1a hash.
22-
uint32_t getKCFITypeID(StringRef MangledTypeName);
21+
enum class KCFIHashAlgorithm { xxHash64, FNV1a };
22+
23+
/// Parse a KCFI hash algorithm name.
24+
/// Returns xxHash64 if the name is not recognized.
25+
KCFIHashAlgorithm parseKCFIHashAlgorithm(StringRef Name);
26+
27+
/// Convert a KCFI hash algorithm enum to its string representation.
28+
StringRef stringifyKCFIHashAlgorithm(KCFIHashAlgorithm Algorithm);
29+
30+
/// Compute KCFI type ID from mangled type name.
31+
/// The algorithm can be xxHash64 or FNV-1a.
32+
uint32_t
33+
getKCFITypeID(StringRef MangledTypeName,
34+
KCFIHashAlgorithm Algorithm = KCFIHashAlgorithm::xxHash64);
2335

2436
} // end namespace llvm
2537

llvm/lib/Support/Hash.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@
1515

1616
using namespace llvm;
1717

18-
uint32_t llvm::getKCFITypeID(StringRef MangledTypeName) {
19-
return static_cast<uint32_t>(xxHash64(MangledTypeName));
18+
KCFIHashAlgorithm llvm::parseKCFIHashAlgorithm(StringRef Name) {
19+
if (Name == "FNV-1a")
20+
return KCFIHashAlgorithm::FNV1a;
21+
// Default to xxHash64 for backward compatibility
22+
return KCFIHashAlgorithm::xxHash64;
23+
}
24+
25+
StringRef llvm::stringifyKCFIHashAlgorithm(KCFIHashAlgorithm Algorithm) {
26+
switch (Algorithm) {
27+
case KCFIHashAlgorithm::xxHash64:
28+
return "xxHash64";
29+
case KCFIHashAlgorithm::FNV1a:
30+
return "FNV-1a";
31+
}
32+
llvm_unreachable("Unknown KCFI hash algorithm");
33+
}
34+
35+
uint32_t llvm::getKCFITypeID(StringRef MangledTypeName,
36+
KCFIHashAlgorithm Algorithm) {
37+
switch (Algorithm) {
38+
case KCFIHashAlgorithm::xxHash64:
39+
// Use lower 32 bits of xxHash64
40+
return static_cast<uint32_t>(xxHash64(MangledTypeName));
41+
case KCFIHashAlgorithm::FNV1a:
42+
// FNV-1a hash (32-bit)
43+
uint32_t Hash = 2166136261u; // FNV offset basis
44+
for (unsigned char C : MangledTypeName) {
45+
Hash ^= C;
46+
Hash *= 16777619u; // FNV prime
47+
}
48+
return Hash;
49+
}
50+
llvm_unreachable("Unknown KCFI hash algorithm");
2051
}

llvm/lib/Transforms/Utils/ModuleUtils.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/IR/MDBuilder.h"
2020
#include "llvm/IR/Module.h"
2121
#include "llvm/Support/Casting.h"
22+
#include "llvm/Support/Hash.h"
2223
#include "llvm/Support/MD5.h"
2324
#include "llvm/Support/raw_ostream.h"
2425
#include "llvm/Transforms/Instrumentation/KCFI.h"
@@ -208,10 +209,16 @@ void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
208209
std::string Type = MangledType.str();
209210
if (M.getModuleFlag("cfi-normalize-integers"))
210211
Type += ".normalized";
211-
F.setMetadata(
212-
LLVMContext::MD_kcfi_type,
213-
MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
214-
Type::getInt32Ty(Ctx), getKCFITypeID(Type)))));
212+
213+
// Determine which hash algorithm to use
214+
auto *MD = dyn_cast_or_null<MDString>(M.getModuleFlag("kcfi-hash"));
215+
KCFIHashAlgorithm Algorithm =
216+
parseKCFIHashAlgorithm(MD ? MD->getString() : "");
217+
218+
F.setMetadata(LLVMContext::MD_kcfi_type,
219+
MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
220+
Type::getInt32Ty(Ctx),
221+
getKCFITypeID(Type, Algorithm)))));
215222
// If the module was compiled with -fpatchable-function-entry, ensure
216223
// we use the same patchable-function-prefix.
217224
if (auto *MD = mdconst::extract_or_null<ConstantInt>(

0 commit comments

Comments
 (0)