[PATCH] D126385: [msan] Implement -msan-pass-caller-to-runtime.
Alexander Potapenko via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed May 25 08:10:28 PDT 2022
glider created this revision.
glider added reviewers: eugenis, vitalybuka.
Herald added a subscriber: hiraditya.
Herald added a project: All.
glider requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
Linux kernel has a concept of noinstr code, which is used to prevent
all kinds of instrumentation for annotated functions.
In particular, syscall and IRQ entry functions are implemented as
noinstr.
When these functions call KMSAN-instrumented functions, they fail to
properly set up the metadata for function arguments, potentially leading
to false positive reports.
In order to detect transitions from noinstr to instrumented code, we
introduce the -msan-pass-caller-to-runtime flag, which allows KMSAN to
pass the caller address to __msan_get_context_state(). That address can
be used by the runtime to figure out whether a call happened from a
noinstr function, and wipe the context state, preventing the error
reports.
For backward compatibility with BSD systems that use KMSAN, we keep
-msan-pass-caller-to-runtime=0 a default value.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D126385
Files:
llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
llvm/test/Instrumentation/MemorySanitizer/msan_kernel_pass-caller-to-runtime.ll
Index: llvm/test/Instrumentation/MemorySanitizer/msan_kernel_pass-caller-to-runtime.ll
===================================================================
--- /dev/null
+++ llvm/test/Instrumentation/MemorySanitizer/msan_kernel_pass-caller-to-runtime.ll
@@ -0,0 +1,22 @@
+; Test KMSAN behavior with and without -msan-pass-caller-to-runtime.
+; RUN: opt < %s -msan-kernel=1 -S -passes=msan 2>&1 | FileCheck %s -check-prefixes=CHECK-NOPASS
+; RUN: opt < %s -msan-kernel=1 -S -passes=msan -msan-pass-caller-to-runtime=1 2>&1 | FileCheck %s -check-prefixes=CHECK-PASS
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Check the instrumentation prologue.
+define void @Empty() nounwind uwtable sanitize_memory {
+entry:
+ ret void
+}
+
+; CHECK-LABEL: @Empty
+; CHECK: entry:
+; BSD systems: __msan_get_context_state() does not accept parameters.
+; CHECK-NOPASS: @__msan_get_context_state()
+; Linux systems: pass __builtin_return_address(0) to __msan_get_context_state().
+; CHECK-PASS: @llvm.returnaddress
+; CHECK-PASS: @__msan_get_context_state({{.*}})
+; %param_shadow:
+; CHECK: getelementptr {{.*}} i32 0, i32 0
Index: llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -271,6 +271,11 @@
cl::desc("conservative handling of inline assembly"), cl::Hidden,
cl::init(true));
+static cl::opt<bool> ClPassCallerToRuntime(
+ "msan-pass-caller-to-runtime",
+ cl::desc("(KMSAN only) pass caller address to the runtime to detect calls "
+ "from non-instrumented code"), cl::Hidden, cl::init(false));
+
// This flag controls whether we check the shadow of the address
// operand of load or store. Such bugs are very rare, since load from
// a garbage address typically results in SEGV, but still happen
@@ -709,8 +714,18 @@
ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), /* va_arg_origin */
IRB.getInt64Ty(), ArrayType::get(OriginTy, kParamTLSSize / 4), OriginTy,
OriginTy);
- MsanGetContextStateFn = M.getOrInsertFunction(
- "__msan_get_context_state", PointerType::get(MsanContextStateTy, 0));
+
+ if (ClPassCallerToRuntime) {
+ // __msan_get_context_state() takes the result of __builtin_return_address(0).
+ // Used by Linux.
+ MsanGetContextStateFn = M.getOrInsertFunction(
+ "__msan_get_context_state", PointerType::get(MsanContextStateTy, 0),
+ PointerType::get(IRB.getInt8Ty(), 0));
+ } else {
+ // __msan_get_context_state() doesn't take any parameters. Used by *BSD systems.
+ MsanGetContextStateFn = M.getOrInsertFunction(
+ "__msan_get_context_state", PointerType::get(MsanContextStateTy, 0));
+ }
Type *RetTy = StructType::get(PointerType::get(IRB.getInt8Ty(), 0),
PointerType::get(IRB.getInt32Ty(), 0));
@@ -1252,7 +1267,15 @@
// Returns the last instruction in the new prologue
void insertKmsanPrologue(IRBuilder<> &IRB) {
- Value *ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, {});
+ Value *ContextState = nullptr;
+ if (ClPassCallerToRuntime) {
+ Value *RetAddr = IRB.CreateCall(
+ Intrinsic::getDeclaration(F.getParent(), Intrinsic::returnaddress),
+ IRB.getInt32(0));
+ ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, RetAddr);
+ } else {
+ ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, {});
+ }
Constant *Zero = IRB.getInt32(0);
MS.ParamTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState,
{Zero, IRB.getInt32(0)}, "param_shadow");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D126385.432002.patch
Type: text/x-patch
Size: 3887 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220525/07e223ed/attachment.bin>
More information about the llvm-commits
mailing list