[Lldb-commits] [lldb] [lldb] Add `process launch --memory-tagging` option (PR #162944)

Julian Lettner via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 10 16:58:56 PDT 2025


https://github.com/yln created https://github.com/llvm/llvm-project/pull/162944

For debugging and bug-finding workflows, support
launching processes with MTE for binaries that are
not MTE entitled.

>From 5bcb5baa7f5ccfb0501c689de078ffff7c5d6a8d Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 14 Nov 2024 15:43:24 -0800
Subject: [PATCH 1/2] [lldb] Add `process launch --memory-tagging` option

For debugging and bug-finding workflows, support
launching processes with MTE for binaries that are
not MTE entitled.
---
 lldb/include/lldb/lldb-enumerations.h         |  2 ++
 lldb/source/Commands/CommandObjectProcess.cpp |  3 +++
 .../Commands/CommandOptionsProcessLaunch.cpp  |  4 +++
 .../Commands/CommandOptionsProcessLaunch.h    |  2 ++
 lldb/source/Commands/Options.td               |  4 +++
 lldb/source/Host/macosx/objcxx/Host.mm        | 27 +++++++++++++++++++
 lldb/test/API/macosx/mte/Makefile             |  9 ++++---
 lldb/test/API/macosx/mte/TestDarwinMTE.py     | 16 +++++++++--
 8 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index fec9fdef44df9..e21880e8dcfb2 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -130,6 +130,8 @@ FLAGS_ENUM(LaunchFlags){
     eLaunchFlagInheritTCCFromParent =
         (1u << 12), ///< Don't make the inferior responsible for its own TCC
                     ///< permissions but instead inherit them from its parent.
+    eLaunchFlagMemoryTagging =
+        (1u << 13), ///< Launch with memory tagging (MTE).
 };
 
 /// Thread Run Modes.
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 7d326404a5503..cce0a380479f7 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -181,6 +181,9 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
       disable_aslr = target->GetDisableASLR();
     }
 
+    if (m_options.memory_tagging == eLazyBoolYes)
+      m_options.launch_info.GetFlags().Set(eLaunchFlagMemoryTagging);
+
     if (!m_class_options.GetName().empty()) {
       m_options.launch_info.SetProcessPluginName("ScriptedProcess");
       ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
diff --git a/lldb/source/Commands/CommandOptionsProcessLaunch.cpp b/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
index 21d94d68ceb91..bb20bbbe2e8f7 100644
--- a/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
+++ b/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
@@ -127,6 +127,10 @@ Status CommandOptionsProcessLaunch::SetOptionValue(
     break;
   }
 
+  case 'M':
+    memory_tagging = true;
+    break;
+
   case 'c':
     if (!option_arg.empty())
       launch_info.SetShell(FileSpec(option_arg));
diff --git a/lldb/source/Commands/CommandOptionsProcessLaunch.h b/lldb/source/Commands/CommandOptionsProcessLaunch.h
index 7ab7fabe10503..640495422a694 100644
--- a/lldb/source/Commands/CommandOptionsProcessLaunch.h
+++ b/lldb/source/Commands/CommandOptionsProcessLaunch.h
@@ -34,6 +34,7 @@ class CommandOptionsProcessLaunch : public lldb_private::OptionGroup {
       lldb_private::ExecutionContext *execution_context) override {
     launch_info.Clear();
     disable_aslr = lldb_private::eLazyBoolCalculate;
+    memory_tagging = false;
   }
 
   llvm::ArrayRef<lldb_private::OptionDefinition> GetDefinitions() override;
@@ -42,6 +43,7 @@ class CommandOptionsProcessLaunch : public lldb_private::OptionGroup {
 
   lldb_private::ProcessLaunchInfo launch_info;
   lldb_private::LazyBool disable_aslr;
+  bool memory_tagging;
 }; // CommandOptionsProcessLaunch
 
 } // namespace lldb_private
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 595b3d08abec5..a3742aacb63a6 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1173,6 +1173,10 @@ let Command = "process launch" in {
         Arg<"Boolean">,
         Desc<"Set whether to shell expand arguments to the process when "
              "launching.">;
+  def process_launch_memory_tagging
+      : Option<"memory-tagging", "M">,
+        Desc<"Set whether to enable memory tagging (MTE) when launching the "
+             "process.">;
 }
 
 let Command = "process attach" in {
diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm
index 3c1d1179963d2..28f4717bfc87c 100644
--- a/lldb/source/Host/macosx/objcxx/Host.mm
+++ b/lldb/source/Host/macosx/objcxx/Host.mm
@@ -1210,6 +1210,33 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
     }
   }
 
+  if (launch_info.GetFlags().Test(eLaunchFlagMemoryTagging)) {
+    typedef int (*posix_spawnattr_set_use_sec_transition_shims_np_t)(
+        posix_spawnattr_t *attr, uint32_t flags);
+    posix_spawnattr_set_use_sec_transition_shims_np_t
+        posix_spawnattr_set_use_sec_transition_shims_np_fn =
+            (posix_spawnattr_set_use_sec_transition_shims_np_t)dlsym(
+                RTLD_DEFAULT,
+                "posix_spawnattr_set_use_sec_transition_shims_np");
+    if (posix_spawnattr_set_use_sec_transition_shims_np_fn) {
+      error =
+          Status(posix_spawnattr_set_use_sec_transition_shims_np_fn(&attr, 0),
+                 eErrorTypePOSIX);
+      if (error.Fail()) {
+        LLDB_LOG(log,
+                 "error: {0}, "
+                 "posix_spawnattr_set_use_sec_transition_shims_np(&attr, 0)",
+                 error);
+        return error;
+      }
+    } else {
+      LLDB_LOG(log,
+               "error: posix_spawnattr_set_use_sec_transition_shims_np not "
+               "available",
+               error);
+    }
+  }
+
   // Don't set the binpref if a shell was provided. After all, that's only
   // going to affect what version of the shell is launched, not what fork of
   // the binary is launched.  We insert "arch --arch <ARCH> as part of the
diff --git a/lldb/test/API/macosx/mte/Makefile b/lldb/test/API/macosx/mte/Makefile
index cb20942805e2a..d614e0f0a3bcd 100644
--- a/lldb/test/API/macosx/mte/Makefile
+++ b/lldb/test/API/macosx/mte/Makefile
@@ -1,12 +1,15 @@
 C_SOURCES := main.c
 
-EXE := uaf_mte
+EXE := uaf
 
-all: uaf_mte sign
+binary-plain:    uaf
+binary-entitled: uaf sign
+
+all: binary-entitled
 
 include Makefile.rules
 
-sign: mte-entitlements.plist uaf_mte
+sign: mte-entitlements.plist uaf
 ifeq ($(OS),Darwin)
 	codesign -s - -f --entitlements $^
 endif
diff --git a/lldb/test/API/macosx/mte/TestDarwinMTE.py b/lldb/test/API/macosx/mte/TestDarwinMTE.py
index ef858b1fc2710..a70b4b4aed26b 100644
--- a/lldb/test/API/macosx/mte/TestDarwinMTE.py
+++ b/lldb/test/API/macosx/mte/TestDarwinMTE.py
@@ -7,12 +7,24 @@
 from lldbsuite.test import lldbutil
 import lldbsuite.test.cpu_feature as cpu_feature
 
-exe_name = "uaf_mte"  # Must match Makefile
+exe_name = "uaf"  # Must match Makefile
 
 
 class TestDarwinMTE(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
+    @skipUnlessFeature(cpu_feature.AArch64.MTE)
+    def test_process_launch_memory_tagging(self):
+        self.build(make_targets=["binary-plain"])
+        self.createTestTarget(self.getBuildArtifact(exe_name))
+
+        self.expect("process launch", substrs=["exited with status = 0"])
+
+        self.expect(
+            "process launch --memory-tagging",
+            substrs=["stopped", "stop reason = EXC_ARM_MTE_TAG_FAULT"],
+        )
+
     @skipUnlessFeature(cpu_feature.AArch64.MTE)
     def test_tag_fault(self):
         self.build()
@@ -47,7 +59,7 @@ def test_memory_region(self):
         self.expect("memory region ptr", substrs=["memory tagging: enabled"])
 
     @skipUnlessFeature(cpu_feature.AArch64.MTE)
-    def test_memory_read_with_tags(self):
+    def test_memory_read_show_tags(self):
         self.build()
         lldbutil.run_to_source_breakpoint(
             self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name

>From 5e58d833e1ad1ab677b43edbc68d83b7302f5ae2 Mon Sep 17 00:00:00 2001
From: Julian Lettner <jlettner at apple.com>
Date: Fri, 10 Oct 2025 16:41:43 -0700
Subject: [PATCH 2/2] [lldb] Directly set memory_tagging in launch info flags

Directly set `memory_tagging` in launch info flags
eliminating the need for a dedicated member in
`CommandOptionsProcessLaunch`.
---
 lldb/source/Commands/CommandObjectProcess.cpp        | 3 ---
 lldb/source/Commands/CommandOptionsProcessLaunch.cpp | 2 +-
 lldb/source/Commands/CommandOptionsProcessLaunch.h   | 2 --
 3 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index cce0a380479f7..7d326404a5503 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -181,9 +181,6 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
       disable_aslr = target->GetDisableASLR();
     }
 
-    if (m_options.memory_tagging == eLazyBoolYes)
-      m_options.launch_info.GetFlags().Set(eLaunchFlagMemoryTagging);
-
     if (!m_class_options.GetName().empty()) {
       m_options.launch_info.SetProcessPluginName("ScriptedProcess");
       ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
diff --git a/lldb/source/Commands/CommandOptionsProcessLaunch.cpp b/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
index bb20bbbe2e8f7..8ae20bd76f456 100644
--- a/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
+++ b/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
@@ -128,7 +128,7 @@ Status CommandOptionsProcessLaunch::SetOptionValue(
   }
 
   case 'M':
-    memory_tagging = true;
+    launch_info.GetFlags().Set(eLaunchFlagMemoryTagging);
     break;
 
   case 'c':
diff --git a/lldb/source/Commands/CommandOptionsProcessLaunch.h b/lldb/source/Commands/CommandOptionsProcessLaunch.h
index 640495422a694..7ab7fabe10503 100644
--- a/lldb/source/Commands/CommandOptionsProcessLaunch.h
+++ b/lldb/source/Commands/CommandOptionsProcessLaunch.h
@@ -34,7 +34,6 @@ class CommandOptionsProcessLaunch : public lldb_private::OptionGroup {
       lldb_private::ExecutionContext *execution_context) override {
     launch_info.Clear();
     disable_aslr = lldb_private::eLazyBoolCalculate;
-    memory_tagging = false;
   }
 
   llvm::ArrayRef<lldb_private::OptionDefinition> GetDefinitions() override;
@@ -43,7 +42,6 @@ class CommandOptionsProcessLaunch : public lldb_private::OptionGroup {
 
   lldb_private::ProcessLaunchInfo launch_info;
   lldb_private::LazyBool disable_aslr;
-  bool memory_tagging;
 }; // CommandOptionsProcessLaunch
 
 } // namespace lldb_private



More information about the lldb-commits mailing list