1 // Copyright 2017 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef CRASHPAD_HANDLER_LINUX_EXCEPTION_HANDLER_SERVER_H_
16 #define CRASHPAD_HANDLER_LINUX_EXCEPTION_HANDLER_SERVER_H_
17 
18 #include <stdint.h>
19 #include <sys/socket.h>
20 
21 #include <atomic>
22 #include <memory>
23 #include <unordered_map>
24 
25 #include "base/macros.h"
26 #include "util/file/file_io.h"
27 #include "util/linux/exception_handler_protocol.h"
28 #include "util/misc/address_types.h"
29 #include "util/misc/initialization_state_dcheck.h"
30 #include "util/misc/uuid.h"
31 
32 namespace crashpad {
33 
34 //! \brief Abstract base class for deciding how the handler should `ptrace` a
35 //!     client.
36 class PtraceStrategyDecider {
37  public:
38   virtual ~PtraceStrategyDecider() = default;
39 
40   //! \brief The possible return values for ChooseStrategy().
41   enum class Strategy {
42     //! \brief An error occurred,  with a message logged.
43     kError,
44 
45     //! \brief Ptrace cannot be used.
46     kNoPtrace,
47 
48     //! \brief The handler should `ptrace`-attach the client directly.
49     kDirectPtrace,
50 
51     //! \brief The client has `fork`ed a PtraceBroker for the handler.
52     kUseBroker,
53   };
54 
55   //! \brief Chooses an appropriate `ptrace` strategy.
56   //!
57   //! \param[in] sock A socket conncted to a ExceptionHandlerClient.
58   //! \param[in] multiple_clients `true` if the socket is connected to multiple
59   //!     clients. The broker is not supported in this configuration.
60   //! \param[in] client_credentials The credentials for the connected client.
61   //! \return the chosen #Strategy.
62   virtual Strategy ChooseStrategy(int sock,
63                                   bool multiple_clients,
64                                   const ucred& client_credentials) = 0;
65 
66  protected:
67   PtraceStrategyDecider() = default;
68 };
69 
70 //! \brief Runs the main exception-handling server in Crashpad’s handler
71 //!     process.
72 class ExceptionHandlerServer {
73  public:
74   class Delegate {
75    public:
76     //! \brief Called on receipt of a crash dump request from a client.
77     //!
78     //! \param[in] client_process_id The process ID of the crashing client.
79     //! \param[in] client_uid The user ID of the crashing client.
80     //! \param[in] info Information on the client.
81     //! \param[in] requesting_thread_stack_address Any address within the stack
82     //!     range for the the thread that sent the crash dump request. Optional.
83     //!     If unspecified or 0, \a requesting_thread_id will be -1.
84     //! \param[out] requesting_thread_id The thread ID of the thread which
85     //!     requested the crash dump if not `nullptr`. Set to -1 if the thread
86     //!     ID could not be determined. Optional.
87     //! \param[out] local_report_id The unique identifier for the report created
88     //!     in the local report database. Optional.
89     //! \return `true` on success. `false` on failure with a message logged.
90     virtual bool HandleException(
91         pid_t client_process_id,
92         uid_t client_uid,
93         const ExceptionHandlerProtocol::ClientInformation& info,
94         VMAddress requesting_thread_stack_address = 0,
95         pid_t* requesting_thread_id = nullptr,
96         UUID* local_report_id = nullptr) = 0;
97 
98     //! \brief Called on the receipt of a crash dump request from a client for a
99     //!     crash that should be mediated by a PtraceBroker.
100     //!
101     //! \param[in] client_process_id The process ID of the crashing client.
102     //! \param[in] client_uid The uid of the crashing client.
103     //! \param[in] info Information on the client.
104     //! \param[in] broker_sock A socket connected to the PtraceBroker.
105     //! \param[out] local_report_id The unique identifier for the report created
106     //!     in the local report database. Optional.
107     //! \return `true` on success. `false` on failure with a message logged.
108     virtual bool HandleExceptionWithBroker(
109         pid_t client_process_id,
110         uid_t client_uid,
111         const ExceptionHandlerProtocol::ClientInformation& info,
112         int broker_sock,
113         UUID* local_report_id = nullptr) = 0;
114 
~Delegate()115     virtual ~Delegate() {}
116   };
117 
118   ExceptionHandlerServer();
119   ~ExceptionHandlerServer();
120 
121   //! \brief Sets the handler's PtraceStrategyDecider.
122   //!
123   //! If this method is not called, a default PtraceStrategyDecider will be
124   //! used.
125   void SetPtraceStrategyDecider(std::unique_ptr<PtraceStrategyDecider> decider);
126 
127   //! \brief Initializes this object.
128   //!
129   //! This method must be successfully called before Run().
130   //!
131   //! \param[in] sock A socket on which to receive client requests.
132   //! \param[in] multiple_clients `true` if this socket is used by multiple
133   //!     clients. Using a broker process is not supported in this
134   //!     configuration.
135   //! \return `true` on success. `false` on failure with a message logged.
136   bool InitializeWithClient(ScopedFileHandle sock, bool multiple_clients);
137 
138   //! \brief Runs the exception-handling server.
139   //!
140   //! This method must only be called once on an ExceptionHandlerServer object.
141   //! This method returns when there are no more client connections or Stop()
142   //! has been called.
143   //!
144   //! \param[in] delegate An object to send exceptions to.
145   void Run(Delegate* delegate);
146 
147   //! \brief Stops a running exception-handling server.
148   //!
149   //! Stop() may be called at any time, and may be called from a signal handler.
150   //! If Stop() is called before Run() it will cause Run() to return as soon as
151   //! it is called. It is harmless to call Stop() after Run() has already
152   //! returned, or to call Stop() after it has already been called.
153   void Stop();
154 
155  private:
156   struct Event {
157     enum class Type {
158       // Used by Stop() to shutdown the server.
159       kShutdown,
160 
161       // A message from a client on a private socket connection.
162       kClientMessage,
163 
164       // A message from a client on a shared socket connection.
165       kSharedSocketMessage
166     };
167 
168     Type type;
169     ScopedFileHandle fd;
170   };
171 
172   void HandleEvent(Event* event, uint32_t event_type);
173   bool InstallClientSocket(ScopedFileHandle socket, Event::Type type);
174   bool UninstallClientSocket(Event* event);
175   bool ReceiveClientMessage(Event* event);
176   bool HandleCrashDumpRequest(
177       const ucred& creds,
178       const ExceptionHandlerProtocol::ClientInformation& client_info,
179       VMAddress requesting_thread_stack_address,
180       int client_sock,
181       bool multiple_clients);
182 
183   std::unordered_map<int, std::unique_ptr<Event>> clients_;
184   std::unique_ptr<Event> shutdown_event_;
185   std::unique_ptr<PtraceStrategyDecider> strategy_decider_;
186   Delegate* delegate_;
187   ScopedFileHandle pollfd_;
188   std::atomic<bool> keep_running_;
189   InitializationStateDcheck initialized_;
190 
191   DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServer);
192 };
193 
194 }  // namespace crashpad
195 
196 #endif  // CRASHPAD_HANDLER_LINUX_EXCEPTION_HANDLER_SERVER_H_
197