[Lldb-commits] [lldb] 6db44e5 - [Linux] Add kernel.yama.ptrace_scope note when ptrace fails to attach.

Jordan Rupprecht via lldb-commits lldb-commits at lists.llvm.org
Thu Mar 2 13:51:36 PST 2023


Author: Jordan Rupprecht
Date: 2023-03-02T13:51:30-08:00
New Revision: 6db44e52ce474bbeb66042073a6e3c6c586f78a2

URL: https://github.com/llvm/llvm-project/commit/6db44e52ce474bbeb66042073a6e3c6c586f78a2
DIFF: https://github.com/llvm/llvm-project/commit/6db44e52ce474bbeb66042073a6e3c6c586f78a2.diff

LOG: [Linux] Add kernel.yama.ptrace_scope note when ptrace fails to attach.

A common reason for LLDB failing to attach to an already-running process on Linux is the Yama security module: https://www.kernel.org/doc/Documentation/security/Yama.txt. This patch adds an explaination and suggested fix when it detects that case happening.

This was previously proposed in D106226, but hasn't been updated in a while. The last request was to put the check in a target-specific location, which is the approach this patch takes. I believe Yama only exists on Linux, so it's put in that package.

This has no end-to-end test because I'm not sure how to set `ptrace_scope` in a test environment -- if there are suggestions on how to do that, I'd be happy to add it. (Also, setting it to `3` is comically irreversible). I tested this locally.

Reviewed By: DavidSpickett, labath

Differential Revision: https://reviews.llvm.org/D144904

Added: 
    

Modified: 
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/source/Plugins/Process/Linux/Procfs.cpp
    lldb/source/Plugins/Process/Linux/Procfs.h
    lldb/unittests/Process/Linux/ProcfsTests.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index a0e5d25a233ba..6182525502545 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -45,6 +45,7 @@
 #include "lldb/Utility/StringExtractor.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Errno.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Threading.h"
 
@@ -214,6 +215,43 @@ static Status EnsureFDFlags(int fd, int flags) {
   return error;
 }
 
+static llvm::Error AddPtraceScopeNote(llvm::Error original_error) {
+  Expected<int> ptrace_scope = GetPtraceScope();
+  if (auto E = ptrace_scope.takeError()) {
+    Log *log = GetLog(POSIXLog::Process);
+    LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E);
+
+    // The original error is probably more interesting than not being able to
+    // read or interpret ptrace_scope.
+    return original_error;
+  }
+
+  // We only have suggestions to provide for 1-3.
+  switch (*ptrace_scope) {
+  case 1:
+  case 2:
+    return llvm::createStringError(
+        std::error_code(errno, std::generic_category()),
+        "The current value of ptrace_scope is %d, which can cause ptrace to "
+        "fail to attach to a running process. To fix this, run:\n"
+        "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n"
+        "For more information, see: "
+        "https://www.kernel.org/doc/Documentation/security/Yama.txt.",
+        *ptrace_scope);
+  case 3:
+    return llvm::createStringError(
+        std::error_code(errno, std::generic_category()),
+        "The current value of ptrace_scope is 3, which will cause ptrace to "
+        "fail to attach to a running process. This value cannot be changed "
+        "without rebooting.\n"
+        "For more information, see: "
+        "https://www.kernel.org/doc/Documentation/security/Yama.txt.");
+  case 0:
+  default:
+    return original_error;
+  }
+}
+
 // Public Static Methods
 
 llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
@@ -352,6 +390,11 @@ llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
             it = tids_to_attach.erase(it);
             continue;
           }
+          if (status.GetError() == EPERM) {
+            // Depending on the value of ptrace_scope, we can return a 
diff erent
+            // error that suggests how to fix it.
+            return AddPtraceScopeNote(status.ToError());
+          }
           return status.ToError();
         }
 

diff  --git a/lldb/source/Plugins/Process/Linux/Procfs.cpp b/lldb/source/Plugins/Process/Linux/Procfs.cpp
index 8186f79806681..c15c0c99133d1 100644
--- a/lldb/source/Plugins/Process/Linux/Procfs.cpp
+++ b/lldb/source/Plugins/Process/Linux/Procfs.cpp
@@ -8,6 +8,7 @@
 
 #include "Procfs.h"
 #include "lldb/Host/linux/Support.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Threading.h"
 #include <optional>
@@ -68,3 +69,18 @@ lldb_private::process_linux::GetAvailableLogicalCoreIDs() {
   }
   return *logical_cores_ids;
 }
+
+llvm::Expected<int> lldb_private::process_linux::GetPtraceScope() {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> ptrace_scope_file =
+      getProcFile("sys/kernel/yama/ptrace_scope");
+  if (!*ptrace_scope_file)
+    return errorCodeToError(ptrace_scope_file.getError());
+  // The contents should be something like "1\n". Trim it so we get "1".
+  StringRef buffer = (*ptrace_scope_file)->getBuffer().trim();
+  int ptrace_scope_value;
+  if (buffer.getAsInteger(10, ptrace_scope_value)) {
+    return createStringError(inconvertibleErrorCode(),
+                             "Invalid ptrace_scope value: '%s'", buffer.data());
+  }
+  return ptrace_scope_value;
+}

diff  --git a/lldb/source/Plugins/Process/Linux/Procfs.h b/lldb/source/Plugins/Process/Linux/Procfs.h
index a62447354f9fd..ea55e89e89840 100644
--- a/lldb/source/Plugins/Process/Linux/Procfs.h
+++ b/lldb/source/Plugins/Process/Linux/Procfs.h
@@ -28,5 +28,11 @@ GetAvailableLogicalCoreIDs(llvm::StringRef cpuinfo);
 ///     if errors didn't happen.
 llvm::Expected<llvm::ArrayRef<lldb::cpu_id_t>> GetAvailableLogicalCoreIDs();
 
+/// \return
+///     The current value of /proc/sys/kernel/yama/ptrace_scope, parsed as an
+///     integer, or an error if the proc file cannot be read or has non-integer
+///     contents.
+llvm::Expected<int> GetPtraceScope();
+
 } // namespace process_linux
 } // namespace lldb_private

diff  --git a/lldb/unittests/Process/Linux/ProcfsTests.cpp b/lldb/unittests/Process/Linux/ProcfsTests.cpp
index c069091b7b065..d95de649ed578 100644
--- a/lldb/unittests/Process/Linux/ProcfsTests.cpp
+++ b/lldb/unittests/Process/Linux/ProcfsTests.cpp
@@ -102,3 +102,19 @@ TEST(Perf, RealLogicalCoreIDs) {
   ASSERT_TRUE((bool)cpu_ids);
   ASSERT_GT((int)cpu_ids->size(), 0) << "We must see at least one core";
 }
+
+TEST(Perf, RealPtraceScope) {
+  // We first check we can read /proc/sys/kernel/yama/ptrace_scope
+  auto buffer_or_error =
+      errorOrToExpected(getProcFile("sys/kernel/yama/ptrace_scope"));
+  if (!buffer_or_error)
+    GTEST_SKIP() << toString(buffer_or_error.takeError());
+
+  // At this point we shouldn't fail parsing the ptrace_scope value.
+  Expected<int> ptrace_scope = GetPtraceScope();
+  ASSERT_TRUE((bool)ptrace_scope) << ptrace_scope.takeError();
+  ASSERT_GE(*ptrace_scope, 0)
+      << "Sensible values of ptrace_scope are between 0 and 3";
+  ASSERT_LE(*ptrace_scope, 3)
+      << "Sensible values of ptrace_scope are between 0 and 3";
+}


        


More information about the lldb-commits mailing list