[llvm] [asan][x86] Abort instrumenting memintrinsics that target fs, gs (PR #129291)

Thor Preimesberger via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 28 11:37:17 PST 2025


https://github.com/cheezeburglar created https://github.com/llvm/llvm-project/pull/129291

For #124238

Currently code such as
```
#include "stdint.h"
void test(uintptr_t addr) {
	__builtin_memcpy(( void __seg_fs*)addr, "x", 1);
}
```
and
```
...
call void @llvm.memcpy.p257.p0.i64(ptr addrspace(257) align 1 %4, ptr align 1 @.str, i64 1, i1 false)
...
```
are miscompiled by ASan. When any of mem{set, cpy, move} are intercepted, by ASan, the writes to fs and gs are effectively scrubbed from the calls to ASan's runtime. This commit just causes AddressSanitizer to bail when on instrumenting these sorts of memory intrinsics.

(Really sorry if you got pinged accidentally when I was editing the commit history before - my bad)

>From 064e4369e2844b3a7cb7be5a70030eb3ab137be8 Mon Sep 17 00:00:00 2001
From: Thor Preimesberger <ThorP at protonmail.com>
Date: Tue, 25 Feb 2025 05:32:18 -0600
Subject: [PATCH] [asan][x86] Abort instrumenting memintrinsics that target fs,
 gs to prevent miscompilation (#124238)

---
 .../Instrumentation/AddressSanitizer.cpp      | 12 ++++
 .../AddressSanitizer/X86/bug_124238.ll        | 60 +++++++++++++++++++
 2 files changed, 72 insertions(+)
 create mode 100644 llvm/test/Instrumentation/AddressSanitizer/X86/bug_124238.ll

diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 8d8d56035a48f..85edcb1276efe 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -797,6 +797,7 @@ struct AddressSanitizer {
                                  bool IsWrite, size_t AccessSizeIndex,
                                  Value *SizeArgument, uint32_t Exp,
                                  RuntimeCallInserter &RTCI);
+  bool maybeIgnoreMemIntrinsic(MemIntrinsic *MI, const Triple &TargetTriple);
   void instrumentMemIntrinsic(MemIntrinsic *MI, RuntimeCallInserter &RTCI);
   Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
   bool suppressInstrumentationSiteForDebug(int &Instrumented);
@@ -1340,10 +1341,21 @@ Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
     return IRB.CreateAdd(Shadow, ShadowBase);
 }
 
+bool AddressSanitizer::maybeIgnoreMemIntrinsic(MemIntrinsic *MI,
+                                               const Triple &TargetTriple) {
+  // Ignore FS and GS registers to prevent miscompilation
+  if (MI->getDestAddressSpace() >= 256 &&
+      TargetTriple.getArch() == Triple::x86_64)
+    return true;
+  return false;
+}
+
 // Instrument memset/memmove/memcpy
 void AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI,
                                               RuntimeCallInserter &RTCI) {
   InstrumentationIRBuilder IRB(MI);
+  if (maybeIgnoreMemIntrinsic(MI, TargetTriple))
+    return;
   if (isa<MemTransferInst>(MI)) {
     RTCI.createRuntimeCall(
         IRB, isa<MemMoveInst>(MI) ? AsanMemmove : AsanMemcpy,
diff --git a/llvm/test/Instrumentation/AddressSanitizer/X86/bug_124238.ll b/llvm/test/Instrumentation/AddressSanitizer/X86/bug_124238.ll
new file mode 100644
index 0000000000000..ce82bc48563a0
--- /dev/null
+++ b/llvm/test/Instrumentation/AddressSanitizer/X86/bug_124238.ll
@@ -0,0 +1,60 @@
+; RUN: opt -passes=asan %s -S | FileCheck %s
+
+;; Punt AddressSanitizer::instrumentMemIntrinsics out for MemIntrinsics
+;; that need write to unsupported registers on X86
+;; PR124238: https://www.github.com/llvm/llvm-project/issues/124238
+
+target triple = "x86_64-unknown-linux-gnu"
+
+$.str.658906a285b7a0f82dabd9915e07848c = comdat any
+ at .str = internal constant { [2 x i8], [30 x i8] } { [2 x i8] c"x\00", [30 x i8] zeroinitializer }, comdat($.str.658906a285b7a0f82dabd9915e07848c), align 32
+ at 0 = private alias { [2 x i8], [30 x i8] }, ptr @.str
+
+define void @test_memcpy(i64 noundef %addr) sanitize_address #0 {
+entry:
+  %addr.addr = alloca i64, align 8
+  store i64 %addr, ptr %addr.addr, align 8
+  %0 = load i64, ptr %addr.addr, align 8
+  %1 = inttoptr i64 %0 to ptr addrspace(257)
+  call void @llvm.memcpy.p257.p0.i64(ptr addrspace(257) align 1 %1, ptr align 1 @.str, i64 1, i1 false)
+; CHECK: llvm.memcpy
+  %2 = load i64, ptr %addr.addr, align 8
+  %3 = inttoptr i64 %2 to ptr addrspace(256)
+  call void @llvm.memcpy.p256.p0.i64(ptr addrspace(256) align 1 %3, ptr align 1 @.str, i64 1, i1 false)
+; CHECK: llvm.memcpy
+  ret void
+}
+
+define void @test_memset(i64 noundef %addr) sanitize_address #0 {
+entry:
+  %addr.addr = alloca i64, align 8
+  store i64 %addr, ptr %addr.addr, align 8
+  %0 = load i64, ptr %addr.addr, align 8
+  %1 = inttoptr i64 %0 to ptr addrspace(257)
+  call void @llvm.memset.p257.i64(ptr addrspace(257) align 1 %1, i8 0, i64 1, i1 false)
+; CHECK: llvm.memset
+  %2 = load i64, ptr %addr.addr, align 8
+  %3 = inttoptr i64 %2 to ptr addrspace(256)
+  call void @llvm.memset.p256.i64(ptr addrspace(256) align 1 %3, i8 0, i64 1, i1 false)
+; CHECK: llvm.memset
+  ret void
+}
+
+define void @test_memmove(i64 noundef %addr) sanitize_address #0 {
+entry:
+  %addr.addr = alloca i64, align 8
+  store i64 %addr, ptr %addr.addr, align 8
+  %0 = load i64, ptr %addr.addr, align 8
+  %1 = inttoptr i64 %0 to ptr addrspace(257)
+  %2 = load i64, ptr %addr.addr, align 8
+  %3 = inttoptr i64 %2 to ptr
+  call void @llvm.memmove.p257.p0.i64(ptr addrspace(257) align 1 %1, ptr align 1 %3, i64 1, i1 false)
+; CHECK: llvm.memmove
+  %4 = load i64, ptr %addr.addr, align 8
+  %5 = inttoptr i64 %4 to ptr addrspace(256)
+  %6 = load i64, ptr %addr.addr, align 8
+  %7 = inttoptr i64 %6 to ptr
+  call void @llvm.memmove.p256.p0.i64(ptr addrspace(256) align 1 %5, ptr align 1 %7, i64 1, i1 false)
+; CHECK: llvm.memmove
+  ret void
+}



More information about the llvm-commits mailing list