mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-30 23:42:29 +00:00
When a crashing process is in a different PID namespace than the handler, the crasher doesn't have a way of knowing its own thread ID in the handler's namespace and the kernel lacks mechanisms to perform this translation before Linux 4.1 (where the information is present in /proc/<pid>/status:NSPid). This patch gives the handler a way of identifying the requesting thread by sending a stack address along with the crash dump request, which the handler can search for in each of the process' threads. This information is useful both for attaching exception information to the right thread and to allow the handler to send signals to the correct thread when using a shared socket connection. Bug: crashpad:284, crashpad:286 Change-Id: I4fa366c8fb17f932b056265cf71a4af160ba342f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1558828 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
169 lines
6.3 KiB
C++
169 lines
6.3 KiB
C++
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
#ifndef CRASHPAD_HANDLER_LINUX_EXCEPTION_HANDLER_SERVER_H_
|
||
#define CRASHPAD_HANDLER_LINUX_EXCEPTION_HANDLER_SERVER_H_
|
||
|
||
#include <stdint.h>
|
||
#include <sys/socket.h>
|
||
|
||
#include <memory>
|
||
#include <unordered_map>
|
||
|
||
#include "base/macros.h"
|
||
#include "util/file/file_io.h"
|
||
#include "util/linux/exception_handler_protocol.h"
|
||
#include "util/misc/address_types.h"
|
||
#include "util/misc/initialization_state_dcheck.h"
|
||
#include "util/misc/uuid.h"
|
||
|
||
namespace crashpad {
|
||
|
||
//! \brief Abstract base class for deciding how the handler should `ptrace` a
|
||
//! client.
|
||
class PtraceStrategyDecider {
|
||
public:
|
||
virtual ~PtraceStrategyDecider() = default;
|
||
|
||
//! \brief The possible return values for ChooseStrategy().
|
||
enum class Strategy {
|
||
//! \brief An error occurred, with a message logged.
|
||
kError,
|
||
|
||
//! \brief Ptrace cannot be used.
|
||
kNoPtrace,
|
||
|
||
//! \brief The handler should `ptrace`-attach the client directly.
|
||
kDirectPtrace,
|
||
|
||
//! \brief The client has `fork`ed a PtraceBroker for the handler.
|
||
kUseBroker,
|
||
};
|
||
|
||
//! \brief Chooses an appropriate `ptrace` strategy.
|
||
//!
|
||
//! \param[in] sock A socket conncted to a ExceptionHandlerClient.
|
||
//! \param[in] client_credentials The credentials for the connected client.
|
||
//! \return the chosen #Strategy.
|
||
virtual Strategy ChooseStrategy(int sock,
|
||
const ucred& client_credentials) = 0;
|
||
|
||
protected:
|
||
PtraceStrategyDecider() = default;
|
||
};
|
||
|
||
//! \brief Runs the main exception-handling server in Crashpad’s handler
|
||
//! process.
|
||
class ExceptionHandlerServer {
|
||
public:
|
||
class Delegate {
|
||
public:
|
||
//! \brief Called on receipt of a crash dump request from a client.
|
||
//!
|
||
//! \param[in] client_process_id The process ID of the crashing client.
|
||
//! \param[in] info Information on the client.
|
||
//! \param[in] requesting_thread_stack_address Any address within the stack
|
||
//! range for the the thread that sent the crash dump request. Optional.
|
||
//! If unspecified or 0, \a requesting_thread_id will be -1.
|
||
//! \param[out] requesting_thread_id The thread ID of the thread which
|
||
//! requested the crash dump if not `nullptr`. Set to -1 if the thread
|
||
//! ID could not be determined. Optional.
|
||
//! \param[out] local_report_id The unique identifier for the report created
|
||
//! in the local report database. Optional.
|
||
//! \return `true` on success. `false` on failure with a message logged.
|
||
virtual bool HandleException(pid_t client_process_id,
|
||
const ClientInformation& info,
|
||
VMAddress requesting_thread_stack_address = 0,
|
||
pid_t* requesting_thread_id = nullptr,
|
||
UUID* local_report_id = nullptr) = 0;
|
||
|
||
//! \brief Called on the receipt of a crash dump request from a client for a
|
||
//! crash that should be mediated by a PtraceBroker.
|
||
//!
|
||
//! \param[in] client_process_id The process ID of the crashing client.
|
||
//! \param[in] info Information on the client.
|
||
//! \param[in] broker_sock A socket connected to the PtraceBroker.
|
||
//! \param[out] local_report_id The unique identifier for the report created
|
||
//! in the local report database. Optional.
|
||
//! \return `true` on success. `false` on failure with a message logged.
|
||
virtual bool HandleExceptionWithBroker(pid_t client_process_id,
|
||
const ClientInformation& info,
|
||
int broker_sock,
|
||
UUID* local_report_id = nullptr) = 0;
|
||
|
||
protected:
|
||
~Delegate() {}
|
||
};
|
||
|
||
ExceptionHandlerServer();
|
||
~ExceptionHandlerServer();
|
||
|
||
//! \brief Sets the handler's PtraceStrategyDecider.
|
||
//!
|
||
//! If this method is not called, a default PtraceStrategyDecider will be
|
||
//! used.
|
||
void SetPtraceStrategyDecider(std::unique_ptr<PtraceStrategyDecider> decider);
|
||
|
||
//! \brief Initializes this object.
|
||
//!
|
||
//! This method must be successfully called before Run().
|
||
//!
|
||
//! \param[in] sock A socket on which to receive client requests.
|
||
//! \return `true` on success. `false` on failure with a message logged.
|
||
bool InitializeWithClient(ScopedFileHandle sock);
|
||
|
||
//! \brief Runs the exception-handling server.
|
||
//!
|
||
//! This method must only be called once on an ExceptionHandlerServer object.
|
||
//! This method returns when there are no more client connections or Stop()
|
||
//! has been called.
|
||
//!
|
||
//! \param[in] delegate An object to send exceptions to.
|
||
void Run(Delegate* delegate);
|
||
|
||
//! \brief Stops a running exception-handling server.
|
||
//!
|
||
//! Stop() may be called at any time, and may be called from a signal handler.
|
||
//! If Stop() is called before Run() it will cause Run() to return as soon as
|
||
//! it is called. It is harmless to call Stop() after Run() has already
|
||
//! returned, or to call Stop() after it has already been called.
|
||
void Stop();
|
||
|
||
private:
|
||
struct Event;
|
||
|
||
void HandleEvent(Event* event, uint32_t event_type);
|
||
bool InstallClientSocket(ScopedFileHandle socket);
|
||
bool UninstallClientSocket(Event* event);
|
||
bool ReceiveClientMessage(Event* event);
|
||
bool HandleCrashDumpRequest(const msghdr& msg,
|
||
const ClientInformation& client_info,
|
||
VMAddress requesting_thread_stack_address,
|
||
int client_sock);
|
||
|
||
std::unordered_map<int, std::unique_ptr<Event>> clients_;
|
||
std::unique_ptr<Event> shutdown_event_;
|
||
std::unique_ptr<PtraceStrategyDecider> strategy_decider_;
|
||
Delegate* delegate_;
|
||
ScopedFileHandle pollfd_;
|
||
bool keep_running_;
|
||
InitializationStateDcheck initialized_;
|
||
|
||
DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServer);
|
||
};
|
||
|
||
} // namespace crashpad
|
||
|
||
#endif // CRASHPAD_HANDLER_LINUX_EXCEPTION_HANDLER_SERVER_H_
|