[PATCH] D141172: [ModuleUtils][KCFI] Set patchable-function-prefix for synthesized functions

Sami Tolvanen via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 6 16:45:38 PST 2023


samitolvanen created this revision.
Herald added a subscriber: hiraditya.
Herald added a project: All.
samitolvanen requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

When -fpatchable-function-entry is used to emit prefix nops
before functions, KCFI assumes all indirectly called functions
have the same number of prefix nops, because the nops are emitted
between the KCFI type hash and the function entry. However, as
patchable-function-prefix is a function attribute set by Clang,
functions later synthesized by LLVM don't inherit this attribute
and end up not having prefix nops. One of these functions
is asan.module_ctor, which the Linux kernel ends up calling
indirectly when KASAN is enabled.

In order to avoid tripping KCFI, save the expected prefix offset
to a module flag, and use it when we're setting KCFI type for the
relevant synthesized functions.

Link: https://github.com/ClangBuiltLinux/linux/issues/1742


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D141172

Files:
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/test/CodeGen/kcfi.c
  llvm/lib/Transforms/Utils/ModuleUtils.cpp
  llvm/test/Instrumentation/AddressSanitizer/kcfi-offset.ll


Index: llvm/test/Instrumentation/AddressSanitizer/kcfi-offset.ll
===================================================================
--- /dev/null
+++ llvm/test/Instrumentation/AddressSanitizer/kcfi-offset.ll
@@ -0,0 +1,15 @@
+;; Test that we set patchable-function-prefix for asan.module_ctor when kcfi-offset is defined.
+
+; RUN: opt < %s -passes=asan -S | FileCheck %s
+
+; CHECK: @llvm.global_ctors = {{.*}}{ i32 1, ptr @asan.module_ctor, ptr @asan.module_ctor }
+
+; CHECK: define internal void @asan.module_ctor()
+; CHECK-SAME: #[[#ATTR:]]
+; CHECK-SAME: !kcfi_type
+
+; CHECK: attributes #[[#ATTR]] = { {{.*}} "patchable-function-prefix"="3" }
+
+!llvm.module.flags = !{!0, !1}
+!0 = !{i32 4, !"kcfi", i32 1}
+!1 = !{i32 4, !"kcfi-offset", i32 3}
Index: llvm/lib/Transforms/Utils/ModuleUtils.cpp
===================================================================
--- llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -161,6 +161,14 @@
       MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
                            Type::getInt32Ty(Ctx),
                            static_cast<uint32_t>(xxHash64(MangledType))))));
+  // 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>(
+          M.getModuleFlag("kcfi-offset"))) {
+    unsigned Offset = MD->getZExtValue();
+    if (Offset)
+      F.addFnAttr("patchable-function-prefix", std::to_string(Offset));
+  }
 }
 
 FunctionCallee
Index: clang/test/CodeGen/kcfi.c
===================================================================
--- clang/test/CodeGen/kcfi.c
+++ clang/test/CodeGen/kcfi.c
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -x c++ -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fpatchable-function-entry-offset=3 -o - %s | FileCheck %s --check-prefixes=CHECK,OFFSET
 #if !__has_feature(kcfi)
 #error Missing kcfi?
 #endif
@@ -54,5 +55,6 @@
 }
 
 // CHECK-DAG: ![[#]] = !{i32 4, !"kcfi", i32 1}
+// OFFSET-DAG: ![[#]] = !{i32 4, !"kcfi-offset", i32 3}
 // CHECK-DAG: ![[#TYPE]] = !{i32 [[#HASH]]}
 // CHECK-DAG: ![[#TYPE2]] = !{i32 [[#%d,HASH2:]]}
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -758,8 +758,14 @@
                               CodeGenOpts.SanitizeCfiCanonicalJumpTables);
   }
 
-  if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
+  if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {
     getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1);
+    // KCFI assumes patchable-function-prefix is the same for all indirectly
+    // called functions. Store the expected offset for code generation.
+    if (CodeGenOpts.PatchableFunctionEntryOffset)
+      getModule().addModuleFlag(llvm::Module::Override, "kcfi-offset",
+                                CodeGenOpts.PatchableFunctionEntryOffset);
+  }
 
   if (CodeGenOpts.CFProtectionReturn &&
       Target.checkCFProtectionReturnSupported(getDiags())) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D141172.487017.patch
Type: text/x-patch
Size: 3326 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20230107/9f31920c/attachment.bin>


More information about the cfe-commits mailing list