Author: Raphael Isemann Date: 2026-06-22T10:59:20+01:00 New Revision: 2ffba269566eabccfbd7d2ee4586c4586d9a70a1
URL: https://github.com/llvm/llvm-project/commit/2ffba269566eabccfbd7d2ee4586c4586d9a70a1 DIFF: https://github.com/llvm/llvm-project/commit/2ffba269566eabccfbd7d2ee4586c4586d9a70a1.diff LOG: Revert "[lldb] Survive ptrace(PT_DENY_ATTACH) when attaching (#204688)" This reverts commit f4043dbcafc93f9107b7c93ee8740cdb0fe22d7c. Added: Modified: lldb/tools/debugserver/source/MacOSX/MachProcess.mm Removed: lldb/test/API/macosx/deny-attach/Makefile lldb/test/API/macosx/deny-attach/TestDenyAttach.py lldb/test/API/macosx/deny-attach/main.c ################################################################################ diff --git a/lldb/test/API/macosx/deny-attach/Makefile b/lldb/test/API/macosx/deny-attach/Makefile deleted file mode 100644 index 10495940055b6..0000000000000 --- a/lldb/test/API/macosx/deny-attach/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -C_SOURCES := main.c - -include Makefile.rules diff --git a/lldb/test/API/macosx/deny-attach/TestDenyAttach.py b/lldb/test/API/macosx/deny-attach/TestDenyAttach.py deleted file mode 100644 index f061bee51c31f..0000000000000 --- a/lldb/test/API/macosx/deny-attach/TestDenyAttach.py +++ /dev/null @@ -1,36 +0,0 @@ -import time -import lldb -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil - - -class DenyAttachTestCase(TestBase): - NO_DEBUG_INFO_TESTCASE = True - - @skipUnlessDarwin - @skipIfDarwinEmbedded # PT_DENY_ATTACH attach behavior diff ers on ios/tvos/etc - @skipIfAsan # Attach tests time out inconsistently under asan. - def test_attach_to_deny_attach_process(self): - """Attaching to a PT_DENY_ATTACH process reports an error, not a crash.""" - self.build() - exe = self.getBuildArtifact("a.out") - - # Use a file as a synchronization point between test and inferior: the - # inferior writes its pid only after it has called PT_DENY_ATTACH. - pid_file_path = lldbutil.append_to_process_working_directory( - self, "pid_file_%d" % (int(time.time())) - ) - self.addTearDownHook( - lambda: self.run_platform_command("rm %s" % (pid_file_path)) - ) - - popen = self.spawnSubprocess(exe, [pid_file_path]) - pid = lldbutil.wait_for_file_on_target(self, pid_file_path) - - self.expect( - "process attach -p " + pid, - startstr="error: attach failed:", - substrs=["PT_DENY_ATTACH"], - error=True, - ) diff --git a/lldb/test/API/macosx/deny-attach/main.c b/lldb/test/API/macosx/deny-attach/main.c deleted file mode 100644 index 1f19f6928604a..0000000000000 --- a/lldb/test/API/macosx/deny-attach/main.c +++ /dev/null @@ -1,60 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <sys/ptrace.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -// Write our pid into file_name atomically (write to a temp file, then rename) -// so the test never observes a partially written pid. -static int write_pid(const char *file_name) { - char tmp_name[1024]; - snprintf(tmp_name, sizeof(tmp_name), "%s_tmp", file_name); - - int fd = open(tmp_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd == -1) { - fprintf(stderr, "open(%s) failed: %s\n", tmp_name, strerror(errno)); - return 1; - } - - char buffer[64]; - int len = snprintf(buffer, sizeof(buffer), "%ld", (long)getpid()); - int result = 0; - if (write(fd, buffer, len) == -1) { - fprintf(stderr, "write failed: %s\n", strerror(errno)); - result = 1; - } - close(fd); - - if (rename(tmp_name, file_name) == -1) { - fprintf(stderr, "rename failed: %s\n", strerror(errno)); - result = 1; - } - return result; -} - -int main(int argc, char const *argv[]) { - if (argc < 2) { - fprintf(stderr, "invalid number of command line arguments\n"); - return 1; - } - - // Tell the kernel to refuse all debugger attachments to this process. Any - // subsequent ptrace(PT_ATTACHEXC) against us makes the kernel deliver SIGSEGV - // to the attaching process (debugserver). - if (ptrace(PT_DENY_ATTACH, 0, 0, 0) == -1) { - fprintf(stderr, "ptrace(PT_DENY_ATTACH) failed: %s\n", strerror(errno)); - return 1; - } - - if (write_pid(argv[1]) != 0) - return 1; - - // Wait for the debugger to try (and fail) to attach. - while (1) - sleep(60); - - return 0; -} diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm index 3374267f7bde8..d79313846438b 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -19,7 +19,6 @@ #include <mach/mach.h> #include <mach/task.h> #include <pthread.h> -#include <setjmp.h> #include <signal.h> #include <spawn.h> #include <sys/fcntl.h> @@ -2937,79 +2936,11 @@ static uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) { return NULL; } -namespace { -// The XNU kernel enforces ptrace(PT_DENY_ATTACH) by delivering a SIGSEGV to the -// process that tries to attach, while it is still inside the ptrace() syscall. -// That kills debugserver outright instead of failing the call with an error. -// This leaves lldb unable to tell the user why the attach failed. The condition -// can't be detected up front because the target's P_LNOATTACH flag isn't -// exposed to userspace, so instead we install a temporary SIGSEGV handler -// around the ptrace() call and jump back out of it if the signal fires, turning -// the fatal signal into a clean error. - -sigjmp_buf g_deny_attach_jmpbuf; -// Only act on the SIGSEGV if it arrives on the thread that armed the guard -// while a PT_ATTACHEXC call is in flight; anything else is a genuine crash. -volatile sig_atomic_t g_deny_attach_armed = 0; -pthread_t g_deny_attach_thread; - -void DenyAttachSIGSEGVHandler(int signo) { - if (g_deny_attach_armed && - pthread_equal(pthread_self(), g_deny_attach_thread)) { - g_deny_attach_armed = 0; - siglongjmp(g_deny_attach_jmpbuf, 1); - } - // Not the deny-attach case: restore the default disposition and re-raise so a - // real crash is still reported the usual way. - signal(signo, SIG_DFL); - raise(signo); -} - -// Wrapper around ptrace(PT_ATTACHEXC, pid) that survives the SIGSEGV the kernel -// sends when `pid` has called ptrace(PT_DENY_ATTACH). On a normal attach it -// behaves exactly like ptrace() (returning its result with errno set). If the -// attach is rejected via the deny-attach signal it sets `denied_attach` and -// returns -1 with errno set to EPERM. -int PTraceAttachExcDenyAttachSafe(pid_t pid, bool &denied_attach) { - denied_attach = false; - - struct sigaction new_action = {}; - struct sigaction old_action = {}; - new_action.sa_handler = DenyAttachSIGSEGVHandler; - sigemptyset(&new_action.sa_mask); - // SA_NODEFER so a genuine fault inside the handler crashes normally instead - // of deadlocking with SIGSEGV blocked. - new_action.sa_flags = SA_NODEFER; - - if (::sigaction(SIGSEGV, &new_action, &old_action) != 0) { - // Couldn't install the handler; fall back to the unguarded call. - return ::ptrace(PT_ATTACHEXC, pid, 0, 0); - } - - g_deny_attach_thread = pthread_self(); - int result; - int saved_errno; - if (sigsetjmp(g_deny_attach_jmpbuf, 1) == 0) { - g_deny_attach_armed = 1; - result = ::ptrace(PT_ATTACHEXC, pid, 0, 0); - saved_errno = errno; - g_deny_attach_armed = 0; - } else { - // The kernel delivered SIGSEGV: the target denied the attach. - denied_attach = true; - result = -1; - saved_errno = EPERM; - } - - ::sigaction(SIGSEGV, &old_action, nullptr); - errno = saved_errno; - return result; -} -} // namespace - pid_t MachProcess::AttachForDebug( - pid_t pid, const RNBContext::IgnoredExceptions &ignored_exceptions, - char *err_str, size_t err_len) { + pid_t pid, + const RNBContext::IgnoredExceptions &ignored_exceptions, + char *err_str, + size_t err_len) { // Clear out and clean up from any current state Clear(); if (pid != 0) { @@ -3042,8 +2973,7 @@ int PTraceAttachExcDenyAttachSafe(pid_t pid, bool &denied_attach) { DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), pid); errno = 0; - bool denied_attach = false; - int ptrace_result = PTraceAttachExcDenyAttachSafe(pid, denied_attach); + int ptrace_result = ::ptrace(PT_ATTACHEXC, pid, 0, 0); int ptrace_errno = errno; DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", getpid(), pid, ptrace_result); @@ -3060,18 +2990,6 @@ int PTraceAttachExcDenyAttachSafe(pid_t pid, bool &denied_attach) { m_flags |= eMachProcessFlagsAttached; DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid); return m_pid; - } else if (denied_attach) { - // The target denied being debugged via ptrace(PT_DENY_ATTACH). The kernel - // would normally kill debugserver for attempting this; we caught the - // signal instead, so report a useful error rather than crashing. - snprintf(err_str, err_len, - "cannot attach to process %d because it has disabled debugging " - "via ptrace(PT_DENY_ATTACH). Attach earlier, put a breakpoint " - "on ptrace and return 0.", - pid); - DNBLogError("[LaunchAttach] (%d) MachProcess::AttachForDebug pid %d " - "denied attach via ptrace(PT_DENY_ATTACH)", - getpid(), pid); } else { ::snprintf(err_str, err_len, "%s", err.AsString()); DNBLogError( _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
