[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