Skip to content

Commit f1574f3

Browse files
committed
Prevent resumption of the seized process
1 parent 0327be0 commit f1574f3

File tree

9 files changed

+91
-8
lines changed

9 files changed

+91
-8
lines changed

lldb/include/lldb/Host/common/NativeProcessProtocol.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,11 @@ class NativeProcessProtocol {
187187

188188
bool IsStepping() const { return m_state == lldb::eStateStepping; }
189189

190-
bool CanResume() const { return m_state == lldb::eStateStopped; }
190+
bool CanResume() const {
191+
return m_state == lldb::eStateStopped && !InNonResumableStop();
192+
}
193+
194+
bool IsStopped() const { return m_state == lldb::eStateStopped; }
191195

192196
lldb::ByteOrder GetByteOrder() const {
193197
return GetArchitecture().GetByteOrder();
@@ -409,6 +413,16 @@ class NativeProcessProtocol {
409413
"Not implemented");
410414
}
411415

416+
/// Check if the process is in a stop that cannot be safely resumed,
417+
/// instead only allowing exit of the program.
418+
///
419+
/// Some examples are in Linux being PTRACE_O_TRACEEXIT or calling
420+
/// PTRACE_SEIZE on a coredumping process.
421+
///
422+
/// \return
423+
/// A bool indicating whether this process can ever be resumed.
424+
virtual bool InNonResumableStop() const { return false; }
425+
412426
protected:
413427
struct SoftwareBreakpoint {
414428
uint32_t ref_count;

lldb/include/lldb/Utility/ProcessInfo.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ class ProcessInstanceInfo : public ProcessInfo {
247247

248248
std::optional<bool> IsZombie() const { return m_zombie; }
249249

250+
void SetNonResumable(bool is_non_resumable) {
251+
m_non_resumable = is_non_resumable;
252+
}
253+
254+
std::optional<bool> IsNonResumable() const { return m_non_resumable; }
255+
250256
void Dump(Stream &s, UserIDResolver &resolver) const;
251257

252258
static void DumpTableHeader(Stream &s, bool show_args, bool verbose);
@@ -266,6 +272,7 @@ class ProcessInstanceInfo : public ProcessInfo {
266272
struct timespec m_cumulative_system_time;
267273
std::optional<int8_t> m_priority_value = std::nullopt;
268274
std::optional<bool> m_zombie = std::nullopt;
275+
std::optional<bool> m_non_resumable = std::nullopt;
269276
};
270277

271278
typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList;

lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ NativeProcessLinux::Manager::Attach(
313313
Log *log = GetLog(POSIXLog::Process);
314314
LLDB_LOG(log, "pid = {0:x}", pid);
315315

316-
auto tids_or = NativeProcessLinux::Attach(pid);
316+
PtraceMethod method = PtraceMethod::Attach;
317+
auto tids_or = NativeProcessLinux::Attach(pid, method);
317318
if (!tids_or)
318319
return tids_or.takeError();
319320
ArrayRef<::pid_t> tids = *tids_or;
@@ -322,8 +323,16 @@ NativeProcessLinux::Manager::Attach(
322323
if (!arch_or)
323324
return arch_or.takeError();
324325

325-
return std::unique_ptr<NativeProcessLinux>(
326+
auto native_up = std::unique_ptr<NativeProcessLinux>(
326327
new NativeProcessLinux(pid, -1, native_delegate, *arch_or, *this, tids));
328+
329+
// We currently only seize a process if it's coredumping and thus unresumable.
330+
// This is a setter instead of being in the constructor because this could
331+
// also be extended in the future to stop the process from being resumed if it
332+
// stops for PTRACE_O_TRACEEXIT.
333+
native_up->SetNonResumableStop(method == PtraceMethod::Seize);
334+
335+
return std::move(native_up);
327336
}
328337

329338
NativeProcessLinux::Extension
@@ -462,12 +471,15 @@ static bool IsCoredumping(lldb::pid_t pid) {
462471
return result == "1";
463472
}
464473

465-
llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
474+
llvm::Expected<std::vector<::pid_t>>
475+
NativeProcessLinux::Attach(::pid_t pid, PtraceMethod &method) {
466476
Log *log = GetLog(POSIXLog::Process);
467477

468478
bool coreDumping = IsCoredumping(pid);
469479
LLDB_LOG(log, "{0} coredumping: {1}", pid, coreDumping);
470480
Status status;
481+
482+
method = coreDumping ? PtraceMethod::Seize : PtraceMethod::Attach;
471483
// Use a map to keep track of the threads which we have attached/need to
472484
// attach.
473485
Host::TidMap tids_to_attach;
@@ -528,6 +540,11 @@ llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
528540
}
529541
}
530542

543+
// TODO: Because the Seize during coredumping change introduces the
544+
// concept of a non resumable stop, we should also check for
545+
// PTRACE_O_TRACEEXIT, which per the man page the status will equal
546+
// status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXEC<<8))
547+
// and if this is true, we should say we can't resume.
531548
int wpid =
532549
llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL);
533550
// Need to use __WALL otherwise we receive an error with errno=ECHLD At
@@ -2113,3 +2130,11 @@ Expected<std::vector<uint8_t>> NativeProcessLinux::TraceGetBinaryData(
21132130
return m_intel_pt_collector.GetBinaryData(request);
21142131
return NativeProcessProtocol::TraceGetBinaryData(request);
21152132
}
2133+
2134+
void NativeProcessLinux::SetNonResumableStop(bool value) {
2135+
m_nonresumable_stop = value;
2136+
}
2137+
2138+
bool NativeProcessLinux::InNonResumableStop() const {
2139+
return m_nonresumable_stop;
2140+
}

lldb/source/Plugins/Process/Linux/NativeProcessLinux.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ class Status;
3131
class Scalar;
3232

3333
namespace process_linux {
34+
35+
// Helper structures to store information about how
36+
// we attached to a process, whether it was a normal
37+
// ptrace attach or a special case where we used seize.
38+
enum PtraceMethod { Attach, Seize };
39+
3440
/// \class NativeProcessLinux
3541
/// Manages communication with the inferior (debugee) process.
3642
///
@@ -164,6 +170,8 @@ class NativeProcessLinux : public NativeProcessELF,
164170
/// Writes a siginfo_t structure corresponding to the given thread ID to the
165171
/// memory region pointed to by \p siginfo.
166172
Status GetSignalInfo(lldb::tid_t tid, void *siginfo) const;
173+
void SetNonResumableStop(bool value);
174+
bool InNonResumableStop() const override;
167175

168176
protected:
169177
llvm::Expected<llvm::ArrayRef<uint8_t>>
@@ -174,7 +182,7 @@ class NativeProcessLinux : public NativeProcessELF,
174182
private:
175183
Manager &m_manager;
176184
ArchSpec m_arch;
177-
185+
bool m_nonresumable_stop = false;
178186
LazyBool m_supports_mem_region = eLazyBoolCalculate;
179187
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
180188

@@ -189,7 +197,8 @@ class NativeProcessLinux : public NativeProcessELF,
189197
llvm::ArrayRef<::pid_t> tids);
190198

191199
// Returns a list of process threads that we have attached to.
192-
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);
200+
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid,
201+
PtraceMethod &method);
193202

194203
static Status SetDefaultPtraceOpts(const lldb::pid_t);
195204

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,6 +2236,9 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
22362236
if (llvm::to_integer(x, vmaddr, 16))
22372237
m_binary_addresses.push_back(vmaddr);
22382238
}
2239+
} else if (name == "non_resumable") {
2240+
if (!value.getAsInteger(1, m_in_nonresumable_stop))
2241+
++num_keys_decoded;
22392242
}
22402243
}
22412244
if (num_keys_decoded > 0)

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
530530

531531
llvm::Expected<int> KillProcess(lldb::pid_t pid);
532532

533+
bool SafeToResume() const { return m_in_nonresumable_stop; }
534+
533535
protected:
534536
LazyBool m_supports_not_sending_acks = eLazyBoolCalculate;
535537
LazyBool m_supports_thread_suffix = eLazyBoolCalculate;
@@ -622,6 +624,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
622624
int m_target_vm_page_size = 0; // target system VM page size; 0 unspecified
623625
uint64_t m_max_packet_size = 0; // as returned by qSupported
624626
std::string m_qSupported_response; // the complete response to qSupported
627+
bool m_in_nonresumable_stop =
628+
false; // true if we are in a stop that cannot be resumed, only exited.
625629

626630
bool m_supported_async_json_packets_is_valid = false;
627631
lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp;

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,9 @@ void GDBRemoteCommunicationServerCommon::
13041304
if (!abi.empty())
13051305
response.Printf("elf_abi:%s;", abi.c_str());
13061306
response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize());
1307+
std::optional<bool> non_resumable = proc_info.IsNonResumable();
1308+
if (non_resumable)
1309+
response.Printf("non_resumable:%d", *non_resumable);
13071310
}
13081311
}
13091312

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ enum GDBRemoteServerError {
6262
eErrorFirst = 29,
6363
eErrorNoProcess = eErrorFirst,
6464
eErrorResume,
65-
eErrorExitStatus
65+
eErrorExitStatus,
66+
eErrorUnresumable
6667
};
6768
}
6869

@@ -1396,6 +1397,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
13961397
if (!Host::GetProcessInfo(pid, proc_info))
13971398
return SendErrorResponse(1);
13981399

1400+
// We check for the bool so we don't emit the false and waste bytes.
1401+
if (m_current_process->InNonResumableStop())
1402+
proc_info.SetNonResumable(true);
1403+
13991404
StreamString response;
14001405
CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
14011406
return SendPacketNoLock(response.GetString());
@@ -1676,7 +1681,11 @@ GDBRemoteCommunication::PacketResult
16761681
GDBRemoteCommunicationServerLLGS::Handle_vCont_actions(
16771682
StringExtractorGDBRemote &packet) {
16781683
StreamString response;
1679-
response.Printf("vCont;c;C;s;S;t");
1684+
if (m_current_process && m_current_process->CanResume()) {
1685+
response.Printf("vCont;c;C;s;S;t");
1686+
} else {
1687+
response.Printf("vCont");
1688+
}
16801689

16811690
return SendPacketNoLock(response.GetString());
16821691
}
@@ -1825,6 +1834,12 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
18251834
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
18261835
}
18271836

1837+
if (!process_it->second.process_up->CanResume()) {
1838+
LLDB_LOG(log, "vCont failed for process {0}: process not resumable",
1839+
x.first);
1840+
return SendErrorResponse(GDBRemoteServerError::eErrorUnresumable);
1841+
}
1842+
18281843
// There are four possible scenarios here. These are:
18291844
// 1. vCont on a stopped process that resumes at least one thread.
18301845
// In this case, we call Resume().

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,9 @@ void ProcessGDBRemote::DidAttach(ArchSpec &process_arch) {
11731173
}
11741174
11751175
Status ProcessGDBRemote::WillResume() {
1176+
if (!m_gdb_comm.SafeToResume())
1177+
return Status::FromErrorString("Process is in a non-resumable stop. Only "
1178+
"detach or exit are supported");
11761179
m_continue_c_tids.clear();
11771180
m_continue_C_tids.clear();
11781181
m_continue_s_tids.clear();

0 commit comments

Comments
 (0)