Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: util/mach/child_port_handshake.h

Issue 756603003: Add ChildPortHandshake and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@child_port_server
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « DEPS ('k') | util/mach/child_port_handshake.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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_UTIL_MACH_CHILD_PORT_HANDSHAKE_H_
16 #define CRASHPAD_UTIL_MACH_CHILD_PORT_HANDSHAKE_H_
17
18 #include <mach/mach.h>
19
20 #include <string>
21
22 #include "base/basictypes.h"
23 #include "base/files/scoped_file.h"
24 #include "util/mach/child_port_server.h"
25
26 namespace crashpad {
27
28 //! \brief Implements a handshake protocol that allows a parent process to
29 //! obtain a Mach port right from a child process.
30 //!
31 //! Ordinarily, there is no way for parent and child processes to exchange port
32 //! rights, outside of the rights that children inherit from their parents.
33 //! These include task-special ports and exception ports, but all of these have
34 //! system-defined uses, and cannot reliably be replaced: in a multi-threaded
35 //! parent, it is impossible to temporarily change one an inheritable port while
36 //! maintaining a guarantee that another thread will not attempt to use it, and
37 //! in children, it difficult to guarantee that nothing will attempt to use an
38 //! inheritable port before it can be replaced with the correct one. This latter
39 //! concern is becoming increasingly more pronounced as system libraries perform
40 //! more operations that rely on an inheritable port in module initializers.
41 //!
42 //! The protocol implemented by this class involves a server that runs in the
43 //! parent process. The server is published with the bootstrap server, which the
44 //! child has access to because the bootstrap port is one of the inherited
45 //! task-special ports. The parent and child also share a pipe, which the parent
46 //! can write to and the child can read from. After launching a child process,
47 //! the parent will write a random token to this pipe, along with the name under
48 //! which its server has been registered with the bootstrap server. The child
49 //! can then obtain a send right to this server with `bootstrap_look_up()`, and
50 //! send a check-in message containing the token value and the port right of its
51 //! choice by calling `child_port_check_in()`.
52 //!
53 //! The inclusion of the token authenticates the child to its parent. This is
54 //! necessary because the service is published with the bootstrap server, which
55 //! opens up access to it to more than the child process. Because the token is
56 //! passed to the child by a shared pipe, it constitutes a shared secret not
57 //! known by other processes that may have incidental access to the server. This
58 //! mechanism is used instead of examining the request message’s audit trailer
59 //! to verify the sender’s process ID because in some process architectures, it
60 //! may be impossible to verify the child’s process ID. This may happen when the
61 //! child disassociates from the parent with a double fork(), and the actual
Robert Sesek 2014/11/25 18:29:27 For how long is the token valid? If a process does
62 //! client is the parent’s grandchild.
63 //!
64 //! The shared pipe serves another purpose: the server monitors it for an
65 //! end-of-file (no readers) condition . Once detected, it will stop its
Robert Sesek 2014/11/25 18:29:27 nit: space before .
66 //! blocking wait for a client to check in. This mechanism was chosen over
67 //! monitoring a child process directly for exit to account for the possibility
68 //! that the child might disassociate with a double fork().
69 //!
70 //! This class can be used to allow a child process to provide its parent with
71 //! a send right to its task port, in cases where it is desirable for the parent
72 //! to have such access. It can also be used to allow a child process to
73 //! establish its own server and provide its parent with a send right to that
74 //! server, for cases where a service is provided and it is undesirable or
75 //! impossible to provide it via the bootstrap or launchd interfaces.
76 class ChildPortHandshake : public ChildPortServer::Interface {
77 public:
78 //! \brief Initializes the server.
79 //!
80 //! This creates the pipe so that the “read” side can be obtained by calling
81 //! ReadPipeFD().
82 ChildPortHandshake();
83
84 ~ChildPortHandshake();
Robert Sesek 2014/11/25 18:29:26 override ?
Mark Mentovai 2014/11/25 19:20:29 Robert Sesek wrote:
85
86 //! \brief Obtains the “read” side of the pipe, to be used by the client.
87 //!
88 //! Callers must obtain this file descriptor and arrange for the caller to
89 //! have access to it before calling RunServer().
90 //!
91 //! \return The file descriptor that the client should read from.
92 int ReadPipeFD() const;
93
94 //! \brief Runs the server.
95 //!
96 //! This method performs these tasks:
97 //! - Closes the “read” side of the pipe in-process, so that the client
98 //! process holds the only file descriptor that can read from the pipe.
99 //! - Creates a random token and sends it via the pipe.
100 //! - Checks its service in with the bootstrap server, and sends the name
101 //! of its bootstrap service mapping via the pipe.
102 //! - Simultaneously receives messages on its Mach server and monitors the
103 //! pipe for end-of-file. This is a blocking operation.
104 //! - When a Mach message is received, calls HandleChildPortCheckIn() to
105 //! interpret and validate it, and if the message is valid, returns the
106 //! port right extracted from the message. If the message is not valid,
107 //! this method will continue waiting for a valid message. Valid messages
108 //! are properly formatted and have the correct token. If a valid message
109 //! carries a send or send-once right, it will be returned. If a valid
110 //! message contains a receive right, it will be destroyed and
111 //! `MACH_PORT_NULL` will be returned. If a message is not valid, this
112 //! method will continue waiting for pipe EOF or a valid message.
113 //! - When notified of pipe EOF, returns `MACH_PORT_NULL`.
114 //! - Regardless of return value, destroys the server’s receive right and
115 //! closes the pipe.
116 //!
117 //! \return On success, the send or send-once right to the port provided by
118 //! the client. The caller takes ownership of this right. On failure,
119 //! `MACH_PORT_NULL`, indicating that the client did not check in properly
120 //! before terminating, where termination is detected by noticing that the
121 //! read side of the shared pipe has closed. On failure, a message
122 //! indiciating the nature of the failure will be logged.
123 mach_port_t RunServer();
124
125 // ChildPortServer::Interface:
126 kern_return_t HandleChildPortCheckIn(child_port_server_t server,
127 child_port_token_t token,
128 mach_port_t port,
129 mach_msg_type_name_t right_type,
130 bool* destroy_complex_request) override;
131
132 //! \brief Runs the read-from-pipe portion of the client’s side of the
133 //! handshake. This is an implementation detail of RunClient and is only
Robert Sesek 2014/11/25 18:29:27 The alternative to this would be to move this into
134 //! exposed for testing purposes.
135 //!
136 //! \param[in] pipe_read The “read” side of the pipe shared with the server
137 //! process.
138 //! \param[out] token The token value read from \a pipe_read.
139 //! \param[out] service_name The service name as registered with the bootstrap
140 //! server, read from \a pipe_read.
141 static void RunClientInternal_ReadPipe(int pipe_read,
142 child_port_token_t* token,
143 std::string* service_name);
144
145 //! \brief Runs the check-in portion of the client’s side of the handshake.
146 //! This is an implementation detail of RunClient and is only exposed for
147 //! testing purposes.
148 //!
149 //! \param[in] service_name The service name as registered with the bootstrap
150 //! server, to be looked up with `bootstrap_look_up()`.
151 //! \param[in] token The token value to provide during check-in.
152 //! \param[in] port The port that will be passed to the server by
153 //! `child_port_check_in()`.
154 //! \param[in] right_type The right type to furnish the parent with.
155 static void RunClientInternal_SendCheckIn(const std::string& service_name,
156 child_port_token_t token,
157 mach_port_t port,
158 mach_msg_type_name_t right_type);
159
160 //! \brief Runs the client.
Robert Sesek 2014/11/25 18:29:27 If this isn't internal, move this above the intern
161 //!
162 //! This function performs these tasks:
163 //! - Reads the token from the pipe.
164 //! - Reads the bootstrap service name from the pipe.
165 //! - Obtains a send right to the server by calling `bootstrap_look_up()`.
166 //! - Sends a check-in message to the server by calling
167 //! `child_port_check_in()`, providing the token and the user-supplied port
168 //! right.
169 //! - Deallocates the send right to the server, and closes the pipe.
170 //!
171 //! \param[in] pipe_read The “read” side of the pipe shared with the server
172 //! process.
173 //! \param[in] port The port that will be passed to the server by
174 //! `child_port_check_in()`.
175 //! \param[in] right_type The right type to furnish the parent with. If \a
176 //! port is a send right, this can be `MACH_MSG_TYPE_COPY_SEND` or
177 //! `MACH_MSG_TYPE_MOVE_SEND`. If \a port is a send-once right, this can
178 //! be `MACH_MSG_TYPE_MOVE_SEND_ONCE`. If \a port is a receive right,
179 //! this can be `MACH_MSG_TYPE_MAKE_SEND`. `MACH_MSG_TYPE_MOVE_RECEIVE`
180 //! is supported by the client interface but will be silently rejected by
181 //! server run by RunServer(), which expects to receive only send or
182 //! send-once rights.
183 static void RunClient(int pipe_read,
Robert Sesek 2014/11/25 18:29:26 Should this return the status of the check-in?
184 mach_port_t port,
185 mach_msg_type_name_t right_type);
186
187 private:
188 // Communicates the token from RunServer(), where it’s generated, to
189 // HandleChildPortCheckIn(), where it’s validated.
190 child_port_token_t token_;
191
192 base::ScopedFD pipe_read_;
193 base::ScopedFD pipe_write_;
194
195 // Communicates the port received from the client from
196 // HandleChildPortCheckIn(), where it’s received, to RunServer(), where it’s
197 // returned. This is strongly-owned, but ownership is transferred to
198 // RunServer()’s caller.
199 mach_port_t child_port_;
200
201 // Communicates that a check-in with a valid token was received by
202 // HandleChildPortCheckIn(), and that the value of child_port_ should be
203 // returned to RunServer()’s caller.
204 bool checked_in_;
205
206 DISALLOW_COPY_AND_ASSIGN(ChildPortHandshake);
207 };
208
209 } // namespace crashpad
210
211 #endif // CRASHPAD_UTIL_MACH_CHILD_PORT_HANDSHAKE_H_
OLDNEW
« no previous file with comments | « DEPS ('k') | util/mach/child_port_handshake.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698