OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ipc/ipc_channel_posix.h" | |
6 | |
7 #include <errno.h> | |
8 #include <fcntl.h> | |
9 #include <stddef.h> | |
10 #include <stdint.h> | |
11 #include <sys/socket.h> | |
12 #include <sys/stat.h> | |
13 #include <sys/types.h> | |
14 #include <unistd.h> | |
15 | |
16 #include <memory> | |
17 | |
18 #include "base/memory/ptr_util.h" | |
19 | |
20 #if defined(OS_OPENBSD) | |
21 #include <sys/uio.h> | |
22 #endif | |
23 | |
24 #if !defined(OS_NACL_NONSFI) | |
25 #include <sys/un.h> | |
26 #endif | |
27 | |
28 #include <algorithm> | |
29 #include <map> | |
30 #include <string> | |
31 #include <utility> | |
32 | |
33 #include "base/command_line.h" | |
34 #include "base/files/file_path.h" | |
35 #include "base/files/file_util.h" | |
36 #include "base/location.h" | |
37 #include "base/logging.h" | |
38 #include "base/memory/singleton.h" | |
39 #include "base/posix/eintr_wrapper.h" | |
40 #include "base/posix/global_descriptors.h" | |
41 #include "base/process/process_handle.h" | |
42 #include "base/rand_util.h" | |
43 #include "base/stl_util.h" | |
44 #include "base/strings/string_util.h" | |
45 #include "base/synchronization/lock.h" | |
46 #include "build/build_config.h" | |
47 #include "ipc/attachment_broker.h" | |
48 #include "ipc/ipc_descriptors.h" | |
49 #include "ipc/ipc_listener.h" | |
50 #include "ipc/ipc_logging.h" | |
51 #include "ipc/ipc_message_attachment_set.h" | |
52 #include "ipc/ipc_message_utils.h" | |
53 #include "ipc/ipc_platform_file_attachment_posix.h" | |
54 #include "ipc/unix_domain_socket_util.h" | |
55 | |
56 namespace IPC { | |
57 | |
58 // IPC channels on Windows use named pipes (CreateNamedPipe()) with | |
59 // channel ids as the pipe names. Channels on POSIX use sockets as | |
60 // pipes These don't quite line up. | |
61 // | |
62 // When creating a child subprocess we use a socket pair and the parent side of | |
63 // the fork arranges it such that the initial control channel ends up on the | |
64 // magic file descriptor kPrimaryIPCChannel in the child. Future | |
65 // connections (file descriptors) can then be passed via that | |
66 // connection via sendmsg(). | |
67 // | |
68 // A POSIX IPC channel can also be set up as a server for a bound UNIX domain | |
69 // socket, and will handle multiple connect and disconnect sequences. Currently | |
70 // it is limited to one connection at a time. | |
71 | |
72 //------------------------------------------------------------------------------ | |
73 namespace { | |
74 | |
75 // The PipeMap class works around this quirk related to unit tests: | |
76 // | |
77 // When running as a server, we install the client socket in a | |
78 // specific file descriptor number (@kPrimaryIPCChannel). However, we | |
79 // also have to support the case where we are running unittests in the | |
80 // same process. (We do not support forking without execing.) | |
81 // | |
82 // Case 1: normal running | |
83 // The IPC server object will install a mapping in PipeMap from the | |
84 // name which it was given to the client pipe. When forking the client, the | |
85 // GetClientFileDescriptorMapping will ensure that the socket is installed in | |
86 // the magic slot (@kPrimaryIPCChannel). The client will search for the | |
87 // mapping, but it won't find any since we are in a new process. Thus the | |
88 // magic fd number is returned. Once the client connects, the server will | |
89 // close its copy of the client socket and remove the mapping. | |
90 // | |
91 // Case 2: unittests - client and server in the same process | |
92 // The IPC server will install a mapping as before. The client will search | |
93 // for a mapping and find out. It duplicates the file descriptor and | |
94 // connects. Once the client connects, the server will close the original | |
95 // copy of the client socket and remove the mapping. Thus, when the client | |
96 // object closes, it will close the only remaining copy of the client socket | |
97 // in the fd table and the server will see EOF on its side. | |
98 // | |
99 // TODO(port): a client process cannot connect to multiple IPC channels with | |
100 // this scheme. | |
101 | |
102 class PipeMap { | |
103 public: | |
104 static PipeMap* GetInstance() { return base::Singleton<PipeMap>::get(); } | |
105 | |
106 ~PipeMap() { | |
107 // Shouldn't have left over pipes. | |
108 DCHECK(map_.empty()); | |
109 } | |
110 | |
111 // Lookup a given channel id. Return -1 if not found. | |
112 int Lookup(const std::string& channel_id) { | |
113 base::AutoLock locked(lock_); | |
114 | |
115 ChannelToFDMap::const_iterator i = map_.find(channel_id); | |
116 if (i == map_.end()) | |
117 return -1; | |
118 return i->second; | |
119 } | |
120 | |
121 // Remove the mapping for the given channel id. No error is signaled if the | |
122 // channel_id doesn't exist | |
123 void Remove(const std::string& channel_id) { | |
124 base::AutoLock locked(lock_); | |
125 map_.erase(channel_id); | |
126 } | |
127 | |
128 // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a | |
129 // mapping if one already exists for the given channel_id | |
130 void Insert(const std::string& channel_id, int fd) { | |
131 base::AutoLock locked(lock_); | |
132 DCHECK_NE(-1, fd); | |
133 | |
134 ChannelToFDMap::const_iterator i = map_.find(channel_id); | |
135 CHECK(i == map_.end()) << "Creating second IPC server (fd " << fd << ") " | |
136 << "for '" << channel_id << "' while first " | |
137 << "(fd " << i->second << ") still exists"; | |
138 map_[channel_id] = fd; | |
139 } | |
140 | |
141 private: | |
142 base::Lock lock_; | |
143 typedef std::map<std::string, int> ChannelToFDMap; | |
144 ChannelToFDMap map_; | |
145 | |
146 friend struct base::DefaultSingletonTraits<PipeMap>; | |
147 #if defined(OS_ANDROID) | |
148 friend void ::IPC::Channel::NotifyProcessForkedForTesting(); | |
149 #endif | |
150 }; | |
151 | |
152 //------------------------------------------------------------------------------ | |
153 | |
154 bool SocketWriteErrorIsRecoverable() { | |
155 #if defined(OS_MACOSX) | |
156 // On OS X if sendmsg() is trying to send fds between processes and there | |
157 // isn't enough room in the output buffer to send the fd structure over | |
158 // atomically then EMSGSIZE is returned. | |
159 // | |
160 // EMSGSIZE presents a problem since the system APIs can only call us when | |
161 // there's room in the socket buffer and not when there is "enough" room. | |
162 // | |
163 // The current behavior is to return to the event loop when EMSGSIZE is | |
164 // received and hopefull service another FD. This is however still | |
165 // technically a busy wait since the event loop will call us right back until | |
166 // the receiver has read enough data to allow passing the FD over atomically. | |
167 return errno == EAGAIN || errno == EMSGSIZE; | |
168 #else | |
169 return errno == EAGAIN; | |
170 #endif // OS_MACOSX | |
171 } | |
172 | |
173 } // namespace | |
174 | |
175 #if defined(OS_ANDROID) | |
176 // When we fork for simple tests on Android, we can't 'exec', so we need to | |
177 // reset these entries manually to get the expected testing behavior. | |
178 void Channel::NotifyProcessForkedForTesting() { | |
179 PipeMap::GetInstance()->map_.clear(); | |
180 } | |
181 #endif | |
182 | |
183 //------------------------------------------------------------------------------ | |
184 | |
185 #if defined(OS_LINUX) | |
186 int ChannelPosix::global_pid_ = 0; | |
187 #endif // OS_LINUX | |
188 | |
189 ChannelPosix::ChannelPosix(const IPC::ChannelHandle& channel_handle, | |
190 Mode mode, | |
191 Listener* listener) | |
192 : ChannelReader(listener), | |
193 mode_(mode), | |
194 peer_pid_(base::kNullProcessId), | |
195 is_blocked_on_write_(false), | |
196 waiting_connect_(true), | |
197 message_send_bytes_written_(0), | |
198 pipe_name_(channel_handle.name), | |
199 in_dtor_(false), | |
200 must_unlink_(false) { | |
201 if (!CreatePipe(channel_handle)) { | |
202 // The pipe may have been closed already. | |
203 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client"; | |
204 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name | |
205 << "\" in " << modestr << " mode"; | |
206 } | |
207 } | |
208 | |
209 ChannelPosix::~ChannelPosix() { | |
210 in_dtor_ = true; | |
211 CleanUp(); | |
212 Close(); | |
213 } | |
214 | |
215 bool SocketPair(int* fd1, int* fd2) { | |
216 int pipe_fds[2]; | |
217 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) { | |
218 PLOG(ERROR) << "socketpair()"; | |
219 return false; | |
220 } | |
221 | |
222 // Set both ends to be non-blocking. | |
223 if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 || | |
224 fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) { | |
225 PLOG(ERROR) << "fcntl(O_NONBLOCK)"; | |
226 if (IGNORE_EINTR(close(pipe_fds[0])) < 0) | |
227 PLOG(ERROR) << "close"; | |
228 if (IGNORE_EINTR(close(pipe_fds[1])) < 0) | |
229 PLOG(ERROR) << "close"; | |
230 return false; | |
231 } | |
232 | |
233 *fd1 = pipe_fds[0]; | |
234 *fd2 = pipe_fds[1]; | |
235 | |
236 return true; | |
237 } | |
238 | |
239 bool ChannelPosix::CreatePipe( | |
240 const IPC::ChannelHandle& channel_handle) { | |
241 DCHECK(!server_listen_pipe_.is_valid() && !pipe_.is_valid()); | |
242 | |
243 // Four possible cases: | |
244 // 1) It's a channel wrapping a pipe that is given to us. | |
245 // 2) It's for a named channel, so we create it. | |
246 // 3) It's for a client that we implement ourself. This is used | |
247 // in single-process unittesting. | |
248 // 4) It's the initial IPC channel: | |
249 // 4a) Client side: Pull the pipe out of the GlobalDescriptors set. | |
250 // 4b) Server side: create the pipe. | |
251 | |
252 base::ScopedFD local_pipe; | |
253 if (channel_handle.socket.fd != -1) { | |
254 // Case 1 from comment above. | |
255 local_pipe.reset(channel_handle.socket.fd); | |
256 } else if (mode_ & MODE_NAMED_FLAG) { | |
257 #if defined(OS_NACL_NONSFI) | |
258 LOG(FATAL) | |
259 << "IPC channels in nacl_helper_nonsfi should not be in NAMED mode."; | |
260 #else | |
261 // Case 2 from comment above. | |
262 int local_pipe_fd = -1; | |
263 | |
264 if (mode_ & MODE_SERVER_FLAG) { | |
265 if (!CreateServerUnixDomainSocket(base::FilePath(pipe_name_), | |
266 &local_pipe_fd)) { | |
267 return false; | |
268 } | |
269 | |
270 must_unlink_ = true; | |
271 } else if (mode_ & MODE_CLIENT_FLAG) { | |
272 if (!CreateClientUnixDomainSocket(base::FilePath(pipe_name_), | |
273 &local_pipe_fd)) { | |
274 return false; | |
275 } | |
276 } else { | |
277 LOG(ERROR) << "Bad mode: " << mode_; | |
278 return false; | |
279 } | |
280 | |
281 local_pipe.reset(local_pipe_fd); | |
282 #endif // !defined(OS_NACL_NONSFI) | |
283 } else { | |
284 local_pipe.reset(PipeMap::GetInstance()->Lookup(pipe_name_)); | |
285 if (mode_ & MODE_CLIENT_FLAG) { | |
286 if (local_pipe.is_valid()) { | |
287 // Case 3 from comment above. | |
288 // We only allow one connection. | |
289 local_pipe.reset(HANDLE_EINTR(dup(local_pipe.release()))); | |
290 PipeMap::GetInstance()->Remove(pipe_name_); | |
291 } else { | |
292 // Case 4a from comment above. | |
293 // Guard against inappropriate reuse of the initial IPC channel. If | |
294 // an IPC channel closes and someone attempts to reuse it by name, the | |
295 // initial channel must not be recycled here. http://crbug.com/26754. | |
296 static bool used_initial_channel = false; | |
297 if (used_initial_channel) { | |
298 LOG(FATAL) << "Denying attempt to reuse initial IPC channel for " | |
299 << pipe_name_; | |
300 return false; | |
301 } | |
302 used_initial_channel = true; | |
303 | |
304 local_pipe.reset( | |
305 base::GlobalDescriptors::GetInstance()->Get(kPrimaryIPCChannel)); | |
306 } | |
307 } else if (mode_ & MODE_SERVER_FLAG) { | |
308 // Case 4b from comment above. | |
309 if (local_pipe.is_valid()) { | |
310 LOG(ERROR) << "Server already exists for " << pipe_name_; | |
311 // This is a client side pipe registered by other server and | |
312 // shouldn't be closed. | |
313 ignore_result(local_pipe.release()); | |
314 return false; | |
315 } | |
316 base::AutoLock lock(client_pipe_lock_); | |
317 int local_pipe_fd = -1, client_pipe_fd = -1; | |
318 if (!SocketPair(&local_pipe_fd, &client_pipe_fd)) | |
319 return false; | |
320 local_pipe.reset(local_pipe_fd); | |
321 client_pipe_.reset(client_pipe_fd); | |
322 PipeMap::GetInstance()->Insert(pipe_name_, client_pipe_fd); | |
323 } else { | |
324 LOG(ERROR) << "Bad mode: " << mode_; | |
325 return false; | |
326 } | |
327 } | |
328 | |
329 if ((mode_ & MODE_SERVER_FLAG) && (mode_ & MODE_NAMED_FLAG)) { | |
330 #if defined(OS_NACL_NONSFI) | |
331 LOG(FATAL) << "IPC channels in nacl_helper_nonsfi " | |
332 << "should not be in NAMED or SERVER mode."; | |
333 #else | |
334 server_listen_pipe_.reset(local_pipe.release()); | |
335 #endif | |
336 } else { | |
337 pipe_.reset(local_pipe.release()); | |
338 } | |
339 return true; | |
340 } | |
341 | |
342 bool ChannelPosix::Connect() { | |
343 WillConnect(); | |
344 | |
345 if (!server_listen_pipe_.is_valid() && !pipe_.is_valid()) { | |
346 DLOG(WARNING) << "Channel creation failed: " << pipe_name_; | |
347 return false; | |
348 } | |
349 | |
350 bool did_connect = true; | |
351 if (server_listen_pipe_.is_valid()) { | |
352 #if defined(OS_NACL_NONSFI) | |
353 LOG(FATAL) << "IPC channels in nacl_helper_nonsfi " | |
354 << "should always be in client mode."; | |
355 #else | |
356 // Watch the pipe for connections, and turn any connections into | |
357 // active sockets. | |
358 base::MessageLoopForIO::current()->WatchFileDescriptor( | |
359 server_listen_pipe_.get(), | |
360 true, | |
361 base::MessageLoopForIO::WATCH_READ, | |
362 &server_listen_connection_watcher_, | |
363 this); | |
364 #endif | |
365 } else { | |
366 did_connect = OnConnect(); | |
367 } | |
368 return did_connect; | |
369 } | |
370 | |
371 void ChannelPosix::CloseFileDescriptors(Message* msg) { | |
372 #if defined(OS_MACOSX) | |
373 // There is a bug on OSX which makes it dangerous to close | |
374 // a file descriptor while it is in transit. So instead we | |
375 // store the file descriptor in a set and send a message to | |
376 // the recipient, which is queued AFTER the message that | |
377 // sent the FD. The recipient will reply to the message, | |
378 // letting us know that it is now safe to close the file | |
379 // descriptor. For more information, see: | |
380 // http://crbug.com/298276 | |
381 std::vector<int> to_close; | |
382 msg->attachment_set()->ReleaseFDsToClose(&to_close); | |
383 for (size_t i = 0; i < to_close.size(); i++) { | |
384 fds_to_close_.insert(to_close[i]); | |
385 QueueCloseFDMessage(to_close[i], 2); | |
386 } | |
387 #else | |
388 msg->attachment_set()->CommitAllDescriptors(); | |
389 #endif | |
390 } | |
391 | |
392 bool ChannelPosix::ProcessOutgoingMessages() { | |
393 if (waiting_connect_) | |
394 return true; | |
395 if (is_blocked_on_write_) | |
396 return true; | |
397 if (output_queue_.empty()) | |
398 return true; | |
399 if (!pipe_.is_valid()) | |
400 return false; | |
401 | |
402 // Write out all the messages we can till the write blocks or there are no | |
403 // more outgoing messages. | |
404 while (!output_queue_.empty()) { | |
405 OutputElement* element = output_queue_.front(); | |
406 | |
407 size_t amt_to_write = element->size() - message_send_bytes_written_; | |
408 DCHECK_NE(0U, amt_to_write); | |
409 const char* out_bytes = reinterpret_cast<const char*>(element->data()) + | |
410 message_send_bytes_written_; | |
411 | |
412 struct msghdr msgh = {0}; | |
413 struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write}; | |
414 msgh.msg_iov = &iov; | |
415 msgh.msg_iovlen = 1; | |
416 char buf[CMSG_SPACE(sizeof(int) * | |
417 MessageAttachmentSet::kMaxDescriptorsPerMessage)]; | |
418 | |
419 ssize_t bytes_written = 1; | |
420 int fd_written = -1; | |
421 | |
422 Message* msg = element->get_message(); | |
423 if (message_send_bytes_written_ == 0 && msg && | |
424 msg->attachment_set()->num_non_brokerable_attachments()) { | |
425 // This is the first chunk of a message which has descriptors to send | |
426 struct cmsghdr *cmsg; | |
427 const unsigned num_fds = | |
428 msg->attachment_set()->num_non_brokerable_attachments(); | |
429 | |
430 DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage); | |
431 if (msg->attachment_set()->ContainsDirectoryDescriptor()) { | |
432 LOG(FATAL) << "Panic: attempting to transport directory descriptor over" | |
433 " IPC. Aborting to maintain sandbox isolation."; | |
434 // If you have hit this then something tried to send a file descriptor | |
435 // to a directory over an IPC channel. Since IPC channels span | |
436 // sandboxes this is very bad: the receiving process can use openat | |
437 // with ".." elements in the path in order to reach the real | |
438 // filesystem. | |
439 } | |
440 | |
441 msgh.msg_control = buf; | |
442 msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); | |
443 cmsg = CMSG_FIRSTHDR(&msgh); | |
444 cmsg->cmsg_level = SOL_SOCKET; | |
445 cmsg->cmsg_type = SCM_RIGHTS; | |
446 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); | |
447 msg->attachment_set()->PeekDescriptors( | |
448 reinterpret_cast<int*>(CMSG_DATA(cmsg))); | |
449 msgh.msg_controllen = cmsg->cmsg_len; | |
450 | |
451 // DCHECK_LE above already checks that | |
452 // num_fds < kMaxDescriptorsPerMessage so no danger of overflow. | |
453 msg->header()->num_fds = static_cast<uint16_t>(num_fds); | |
454 } | |
455 | |
456 if (bytes_written == 1) { | |
457 fd_written = pipe_.get(); | |
458 bytes_written = HANDLE_EINTR(sendmsg(pipe_.get(), &msgh, MSG_DONTWAIT)); | |
459 } | |
460 if (bytes_written > 0 && msg) | |
461 CloseFileDescriptors(msg); | |
462 | |
463 if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) { | |
464 // We can't close the pipe here, because calling OnChannelError | |
465 // may destroy this object, and that would be bad if we are | |
466 // called from Send(). Instead, we return false and hope the | |
467 // caller will close the pipe. If they do not, the pipe will | |
468 // still be closed next time OnFileCanReadWithoutBlocking is | |
469 // called. | |
470 #if defined(OS_MACOSX) | |
471 // On OSX writing to a pipe with no listener returns EPERM. | |
472 if (errno == EPERM) { | |
473 return false; | |
474 } | |
475 #endif // OS_MACOSX | |
476 if (errno == EPIPE) { | |
477 return false; | |
478 } | |
479 PLOG(ERROR) << "pipe error on " | |
480 << fd_written | |
481 << " Currently writing message of size: " | |
482 << element->size(); | |
483 return false; | |
484 } | |
485 | |
486 if (static_cast<size_t>(bytes_written) != amt_to_write) { | |
487 if (bytes_written > 0) { | |
488 // If write() fails with EAGAIN then bytes_written will be -1. | |
489 message_send_bytes_written_ += bytes_written; | |
490 } | |
491 | |
492 // Tell libevent to call us back once things are unblocked. | |
493 is_blocked_on_write_ = true; | |
494 base::MessageLoopForIO::current()->WatchFileDescriptor( | |
495 pipe_.get(), | |
496 false, // One shot | |
497 base::MessageLoopForIO::WATCH_WRITE, | |
498 &write_watcher_, | |
499 this); | |
500 return true; | |
501 } else { | |
502 message_send_bytes_written_ = 0; | |
503 | |
504 // Message sent OK! | |
505 if (msg) { | |
506 DVLOG(2) << "sent message @" << msg << " on channel @" << this | |
507 << " with type " << msg->type() << " on fd " << pipe_.get(); | |
508 } else { | |
509 DVLOG(2) << "sent buffer @" << element->data() << " on channel @" | |
510 << this << " on fd " << pipe_.get(); | |
511 } | |
512 delete output_queue_.front(); | |
513 output_queue_.pop(); | |
514 } | |
515 } | |
516 return true; | |
517 } | |
518 | |
519 bool ChannelPosix::Send(Message* message) { | |
520 DCHECK(!message->HasMojoHandles()); | |
521 DVLOG(2) << "sending message @" << message << " on channel @" << this | |
522 << " with type " << message->type() | |
523 << " (" << output_queue_.size() << " in queue)"; | |
524 | |
525 if (!prelim_queue_.empty()) { | |
526 prelim_queue_.push(message); | |
527 return true; | |
528 } | |
529 | |
530 if (message->HasBrokerableAttachments() && | |
531 peer_pid_ == base::kNullProcessId) { | |
532 prelim_queue_.push(message); | |
533 return true; | |
534 } | |
535 | |
536 return ProcessMessageForDelivery(message); | |
537 } | |
538 | |
539 AttachmentBroker* ChannelPosix::GetAttachmentBroker() { | |
540 return AttachmentBroker::GetGlobal(); | |
541 } | |
542 | |
543 int ChannelPosix::GetClientFileDescriptor() const { | |
544 base::AutoLock lock(client_pipe_lock_); | |
545 return client_pipe_.get(); | |
546 } | |
547 | |
548 base::ScopedFD ChannelPosix::TakeClientFileDescriptor() { | |
549 base::AutoLock lock(client_pipe_lock_); | |
550 if (!client_pipe_.is_valid()) | |
551 return base::ScopedFD(); | |
552 PipeMap::GetInstance()->Remove(pipe_name_); | |
553 return std::move(client_pipe_); | |
554 } | |
555 | |
556 void ChannelPosix::CloseClientFileDescriptor() { | |
557 base::AutoLock lock(client_pipe_lock_); | |
558 if (!client_pipe_.is_valid()) | |
559 return; | |
560 PipeMap::GetInstance()->Remove(pipe_name_); | |
561 client_pipe_.reset(); | |
562 } | |
563 | |
564 bool ChannelPosix::AcceptsConnections() const { | |
565 return server_listen_pipe_.is_valid(); | |
566 } | |
567 | |
568 bool ChannelPosix::HasAcceptedConnection() const { | |
569 return AcceptsConnections() && pipe_.is_valid(); | |
570 } | |
571 | |
572 #if !defined(OS_NACL_NONSFI) | |
573 // GetPeerEuid is not supported in nacl_helper_nonsfi. | |
574 bool ChannelPosix::GetPeerEuid(uid_t* peer_euid) const { | |
575 DCHECK(!(mode_ & MODE_SERVER) || HasAcceptedConnection()); | |
576 return IPC::GetPeerEuid(pipe_.get(), peer_euid); | |
577 } | |
578 #endif | |
579 | |
580 void ChannelPosix::ResetToAcceptingConnectionState() { | |
581 // Unregister libevent for the unix domain socket and close it. | |
582 read_watcher_.StopWatchingFileDescriptor(); | |
583 write_watcher_.StopWatchingFileDescriptor(); | |
584 ResetSafely(&pipe_); | |
585 | |
586 while (!output_queue_.empty()) { | |
587 OutputElement* element = output_queue_.front(); | |
588 output_queue_.pop(); | |
589 if (element->get_message()) | |
590 CloseFileDescriptors(element->get_message()); | |
591 delete element; | |
592 } | |
593 | |
594 // Close any outstanding, received file descriptors. | |
595 ClearInputFDs(); | |
596 | |
597 #if defined(OS_MACOSX) | |
598 // Clear any outstanding, sent file descriptors. | |
599 for (std::set<int>::iterator i = fds_to_close_.begin(); | |
600 i != fds_to_close_.end(); | |
601 ++i) { | |
602 if (IGNORE_EINTR(close(*i)) < 0) | |
603 PLOG(ERROR) << "close"; | |
604 } | |
605 fds_to_close_.clear(); | |
606 #endif | |
607 } | |
608 | |
609 // static | |
610 bool ChannelPosix::IsNamedServerInitialized( | |
611 const std::string& channel_id) { | |
612 return base::PathExists(base::FilePath(channel_id)); | |
613 } | |
614 | |
615 #if defined(OS_LINUX) | |
616 // static | |
617 void ChannelPosix::SetGlobalPid(int pid) { | |
618 global_pid_ = pid; | |
619 } | |
620 // static | |
621 int ChannelPosix::GetGlobalPid() { | |
622 return global_pid_; | |
623 } | |
624 #endif // OS_LINUX | |
625 | |
626 // Called by libevent when we can read from the pipe without blocking. | |
627 void ChannelPosix::OnFileCanReadWithoutBlocking(int fd) { | |
628 if (fd == server_listen_pipe_.get()) { | |
629 #if defined(OS_NACL_NONSFI) | |
630 LOG(FATAL) | |
631 << "IPC channels in nacl_helper_nonsfi should not be SERVER mode."; | |
632 #else | |
633 int new_pipe = 0; | |
634 if (!ServerOnConnect(server_listen_pipe_.get(), &new_pipe) || | |
635 new_pipe < 0) { | |
636 Close(); | |
637 listener()->OnChannelListenError(); | |
638 } | |
639 | |
640 if (pipe_.is_valid()) { | |
641 // We already have a connection. We only handle one at a time. | |
642 // close our new descriptor. | |
643 if (HANDLE_EINTR(shutdown(new_pipe, SHUT_RDWR)) < 0) | |
644 DPLOG(ERROR) << "shutdown " << pipe_name_; | |
645 if (IGNORE_EINTR(close(new_pipe)) < 0) | |
646 DPLOG(ERROR) << "close " << pipe_name_; | |
647 listener()->OnChannelDenied(); | |
648 return; | |
649 } | |
650 pipe_.reset(new_pipe); | |
651 | |
652 // Verify that the IPC channel peer is running as the same user. | |
653 uid_t client_euid; | |
654 if (!GetPeerEuid(&client_euid)) { | |
655 DLOG(ERROR) << "Unable to query client euid"; | |
656 ResetToAcceptingConnectionState(); | |
657 return; | |
658 } | |
659 if (client_euid != geteuid()) { | |
660 DLOG(WARNING) << "Client euid is not authorised"; | |
661 ResetToAcceptingConnectionState(); | |
662 return; | |
663 } | |
664 | |
665 if (!OnConnect()) { | |
666 NOTREACHED() << "AcceptConnection should not fail on server"; | |
667 } | |
668 waiting_connect_ = false; | |
669 #endif | |
670 } else if (fd == pipe_) { | |
671 if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) { | |
672 waiting_connect_ = false; | |
673 } | |
674 if (ProcessIncomingMessages() == DISPATCH_ERROR) { | |
675 // ClosePipeOnError may delete this object, so we mustn't call | |
676 // ProcessOutgoingMessages. | |
677 ClosePipeOnError(); | |
678 return; | |
679 } | |
680 } else { | |
681 NOTREACHED() << "Unknown pipe " << fd; | |
682 } | |
683 | |
684 // If we're a server and handshaking, then we want to make sure that we | |
685 // only send our handshake message after we've processed the client's. | |
686 // This gives us a chance to kill the client if the incoming handshake | |
687 // is invalid. This also flushes any closefd messages. | |
688 if (!ProcessOutgoingMessages()) { | |
689 ClosePipeOnError(); | |
690 } | |
691 } | |
692 | |
693 // Called by libevent when we can write to the pipe without blocking. | |
694 void ChannelPosix::OnFileCanWriteWithoutBlocking(int fd) { | |
695 DCHECK_EQ(pipe_.get(), fd); | |
696 is_blocked_on_write_ = false; | |
697 if (!ProcessOutgoingMessages()) { | |
698 ClosePipeOnError(); | |
699 } | |
700 } | |
701 | |
702 bool ChannelPosix::ProcessMessageForDelivery(Message* message) { | |
703 // Sending a brokerable attachment requires a call to Channel::Send(), so | |
704 // Send() may be re-entrant. | |
705 if (message->HasBrokerableAttachments()) { | |
706 DCHECK(GetAttachmentBroker()); | |
707 DCHECK(peer_pid_ != base::kNullProcessId); | |
708 for (const scoped_refptr<IPC::BrokerableAttachment>& attachment : | |
709 message->attachment_set()->GetBrokerableAttachments()) { | |
710 if (!GetAttachmentBroker()->SendAttachmentToProcess(attachment, | |
711 peer_pid_)) { | |
712 delete message; | |
713 return false; | |
714 } | |
715 } | |
716 } | |
717 | |
718 #ifdef IPC_MESSAGE_LOG_ENABLED | |
719 Logging::GetInstance()->OnSendMessage(message, ""); | |
720 #endif // IPC_MESSAGE_LOG_ENABLED | |
721 | |
722 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), | |
723 "ChannelPosix::Send", | |
724 message->flags(), | |
725 TRACE_EVENT_FLAG_FLOW_OUT); | |
726 | |
727 // |output_queue_| takes ownership of |message|. | |
728 OutputElement* element = new OutputElement(message); | |
729 output_queue_.push(element); | |
730 | |
731 if (message->HasBrokerableAttachments()) { | |
732 // |output_queue_| takes ownership of |ids.buffer|. | |
733 Message::SerializedAttachmentIds ids = | |
734 message->SerializedIdsOfBrokerableAttachments(); | |
735 output_queue_.push(new OutputElement(ids.buffer, ids.size)); | |
736 } | |
737 | |
738 return ProcessOutgoingMessages(); | |
739 } | |
740 | |
741 bool ChannelPosix::FlushPrelimQueue() { | |
742 DCHECK_NE(peer_pid_, base::kNullProcessId); | |
743 | |
744 // Due to the possibly re-entrant nature of ProcessMessageForDelivery(), | |
745 // |prelim_queue_| should appear empty. | |
746 std::queue<Message*> prelim_queue; | |
747 std::swap(prelim_queue_, prelim_queue); | |
748 | |
749 bool processing_error = false; | |
750 while (!prelim_queue.empty()) { | |
751 Message* m = prelim_queue.front(); | |
752 processing_error = !ProcessMessageForDelivery(m); | |
753 prelim_queue.pop(); | |
754 if (processing_error) | |
755 break; | |
756 } | |
757 | |
758 // Delete any unprocessed messages. | |
759 while (!prelim_queue.empty()) { | |
760 Message* m = prelim_queue.front(); | |
761 delete m; | |
762 prelim_queue.pop(); | |
763 } | |
764 | |
765 return !processing_error; | |
766 } | |
767 | |
768 bool ChannelPosix::OnConnect() { | |
769 base::MessageLoopForIO::current()->WatchFileDescriptor( | |
770 pipe_.get(), | |
771 true, | |
772 base::MessageLoopForIO::WATCH_READ, | |
773 &read_watcher_, | |
774 this); | |
775 QueueHelloMessage(); | |
776 | |
777 if (mode_ & MODE_CLIENT_FLAG) { | |
778 // If we are a client we want to send a hello message out immediately. | |
779 // In server mode we will send a hello message when we receive one from a | |
780 // client. | |
781 waiting_connect_ = false; | |
782 return ProcessOutgoingMessages(); | |
783 } else if (mode_ & MODE_SERVER_FLAG) { | |
784 waiting_connect_ = true; | |
785 return true; | |
786 } else { | |
787 NOTREACHED(); | |
788 return false; | |
789 } | |
790 } | |
791 | |
792 void ChannelPosix::ClosePipeOnError() { | |
793 if (HasAcceptedConnection()) { | |
794 ResetToAcceptingConnectionState(); | |
795 listener()->OnChannelError(); | |
796 } else { | |
797 Close(); | |
798 if (AcceptsConnections()) { | |
799 listener()->OnChannelListenError(); | |
800 } else { | |
801 listener()->OnChannelError(); | |
802 } | |
803 } | |
804 } | |
805 | |
806 int ChannelPosix::GetHelloMessageProcId() const { | |
807 #if defined(OS_NACL_NONSFI) | |
808 // In nacl_helper_nonsfi, getpid() invoked by GetCurrentProcId() is not | |
809 // allowed and would cause a SIGSYS crash because of the seccomp sandbox. | |
810 return -1; | |
811 #else | |
812 int pid = base::GetCurrentProcId(); | |
813 #if defined(OS_LINUX) | |
814 // Our process may be in a sandbox with a separate PID namespace. | |
815 if (global_pid_) { | |
816 pid = global_pid_; | |
817 } | |
818 #endif // defined(OS_LINUX) | |
819 return pid; | |
820 #endif // defined(OS_NACL_NONSFI) | |
821 } | |
822 | |
823 void ChannelPosix::QueueHelloMessage() { | |
824 // Create the Hello message | |
825 std::unique_ptr<Message> msg(new Message(MSG_ROUTING_NONE, HELLO_MESSAGE_TYPE, | |
826 IPC::Message::PRIORITY_NORMAL)); | |
827 if (!msg->WriteInt(GetHelloMessageProcId())) { | |
828 NOTREACHED() << "Unable to pickle hello message proc id"; | |
829 } | |
830 OutputElement* element = new OutputElement(msg.release()); | |
831 output_queue_.push(element); | |
832 } | |
833 | |
834 ChannelPosix::ReadState ChannelPosix::ReadData( | |
835 char* buffer, | |
836 int buffer_len, | |
837 int* bytes_read) { | |
838 if (!pipe_.is_valid()) | |
839 return READ_FAILED; | |
840 | |
841 struct msghdr msg = {0}; | |
842 | |
843 struct iovec iov = {buffer, static_cast<size_t>(buffer_len)}; | |
844 msg.msg_iov = &iov; | |
845 msg.msg_iovlen = 1; | |
846 | |
847 char input_cmsg_buf[kMaxReadFDBuffer]; | |
848 msg.msg_control = input_cmsg_buf; | |
849 | |
850 // recvmsg() returns 0 if the connection has closed or EAGAIN if no data | |
851 // is waiting on the pipe. | |
852 msg.msg_controllen = sizeof(input_cmsg_buf); | |
853 *bytes_read = HANDLE_EINTR(recvmsg(pipe_.get(), &msg, MSG_DONTWAIT)); | |
854 | |
855 if (*bytes_read < 0) { | |
856 if (errno == EAGAIN) { | |
857 return READ_PENDING; | |
858 #if defined(OS_MACOSX) | |
859 } else if (errno == EPERM) { | |
860 // On OSX, reading from a pipe with no listener returns EPERM | |
861 // treat this as a special case to prevent spurious error messages | |
862 // to the console. | |
863 return READ_FAILED; | |
864 #endif // OS_MACOSX | |
865 } else if (errno == ECONNRESET || errno == EPIPE) { | |
866 return READ_FAILED; | |
867 } else { | |
868 PLOG(ERROR) << "pipe error (" << pipe_.get() << ")"; | |
869 return READ_FAILED; | |
870 } | |
871 } else if (*bytes_read == 0) { | |
872 // The pipe has closed... | |
873 return READ_FAILED; | |
874 } | |
875 DCHECK(*bytes_read); | |
876 | |
877 CloseClientFileDescriptor(); | |
878 | |
879 // Read any file descriptors from the message. | |
880 if (!ExtractFileDescriptorsFromMsghdr(&msg)) | |
881 return READ_FAILED; | |
882 return READ_SUCCEEDED; | |
883 } | |
884 | |
885 bool ChannelPosix::ShouldDispatchInputMessage(Message* msg) { | |
886 return true; | |
887 } | |
888 | |
889 // On Posix, we need to fix up the file descriptors before the input message | |
890 // is dispatched. | |
891 // | |
892 // This will read from the input_fds_ (READWRITE mode only) and read more | |
893 // handles from the FD pipe if necessary. | |
894 bool ChannelPosix::GetNonBrokeredAttachments(Message* msg) { | |
895 uint16_t header_fds = msg->header()->num_fds; | |
896 if (!header_fds) | |
897 return true; // Nothing to do. | |
898 | |
899 // The message has file descriptors. | |
900 const char* error = NULL; | |
901 if (header_fds > input_fds_.size()) { | |
902 // The message has been completely received, but we didn't get | |
903 // enough file descriptors. | |
904 error = "Message needs unreceived descriptors"; | |
905 } | |
906 | |
907 if (header_fds > MessageAttachmentSet::kMaxDescriptorsPerMessage) | |
908 error = "Message requires an excessive number of descriptors"; | |
909 | |
910 if (error) { | |
911 LOG(WARNING) << error | |
912 << " channel:" << this | |
913 << " message-type:" << msg->type() | |
914 << " header()->num_fds:" << header_fds; | |
915 // Abort the connection. | |
916 ClearInputFDs(); | |
917 return false; | |
918 } | |
919 | |
920 // The shenaniganery below with &foo.front() requires input_fds_ to have | |
921 // contiguous underlying storage (such as a simple array or a std::vector). | |
922 // This is why the header warns not to make input_fds_ a deque<>. | |
923 msg->attachment_set()->AddDescriptorsToOwn(&input_fds_.front(), header_fds); | |
924 input_fds_.erase(input_fds_.begin(), input_fds_.begin() + header_fds); | |
925 return true; | |
926 } | |
927 | |
928 bool ChannelPosix::DidEmptyInputBuffers() { | |
929 // When the input data buffer is empty, the fds should be too. If this is | |
930 // not the case, we probably have a rogue renderer which is trying to fill | |
931 // our descriptor table. | |
932 return input_fds_.empty(); | |
933 } | |
934 | |
935 bool ChannelPosix::ExtractFileDescriptorsFromMsghdr(msghdr* msg) { | |
936 // Check that there are any control messages. On OSX, CMSG_FIRSTHDR will | |
937 // return an invalid non-NULL pointer in the case that controllen == 0. | |
938 if (msg->msg_controllen == 0) | |
939 return true; | |
940 | |
941 for (cmsghdr* cmsg = CMSG_FIRSTHDR(msg); | |
942 cmsg; | |
943 cmsg = CMSG_NXTHDR(msg, cmsg)) { | |
944 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { | |
945 unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); | |
946 DCHECK_EQ(0U, payload_len % sizeof(int)); | |
947 const int* file_descriptors = reinterpret_cast<int*>(CMSG_DATA(cmsg)); | |
948 unsigned num_file_descriptors = payload_len / 4; | |
949 input_fds_.insert(input_fds_.end(), | |
950 file_descriptors, | |
951 file_descriptors + num_file_descriptors); | |
952 | |
953 // Check this after adding the FDs so we don't leak them. | |
954 if (msg->msg_flags & MSG_CTRUNC) { | |
955 ClearInputFDs(); | |
956 return false; | |
957 } | |
958 | |
959 return true; | |
960 } | |
961 } | |
962 | |
963 // No file descriptors found, but that's OK. | |
964 return true; | |
965 } | |
966 | |
967 void ChannelPosix::ClearInputFDs() { | |
968 for (size_t i = 0; i < input_fds_.size(); ++i) { | |
969 if (IGNORE_EINTR(close(input_fds_[i])) < 0) | |
970 PLOG(ERROR) << "close "; | |
971 } | |
972 input_fds_.clear(); | |
973 } | |
974 | |
975 void ChannelPosix::QueueCloseFDMessage(int fd, int hops) { | |
976 switch (hops) { | |
977 case 1: | |
978 case 2: { | |
979 // Create the message | |
980 std::unique_ptr<Message> msg(new Message(MSG_ROUTING_NONE, | |
981 CLOSE_FD_MESSAGE_TYPE, | |
982 IPC::Message::PRIORITY_NORMAL)); | |
983 if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) { | |
984 NOTREACHED() << "Unable to pickle close fd."; | |
985 } | |
986 | |
987 OutputElement* element = new OutputElement(msg.release()); | |
988 output_queue_.push(element); | |
989 break; | |
990 } | |
991 | |
992 default: | |
993 NOTREACHED(); | |
994 break; | |
995 } | |
996 } | |
997 | |
998 void ChannelPosix::HandleInternalMessage(const Message& msg) { | |
999 // The Hello message contains only the process id. | |
1000 base::PickleIterator iter(msg); | |
1001 | |
1002 switch (msg.type()) { | |
1003 default: | |
1004 NOTREACHED(); | |
1005 break; | |
1006 | |
1007 case Channel::HELLO_MESSAGE_TYPE: | |
1008 int pid; | |
1009 if (!iter.ReadInt(&pid)) | |
1010 NOTREACHED(); | |
1011 | |
1012 peer_pid_ = pid; | |
1013 listener()->OnChannelConnected(pid); | |
1014 | |
1015 if (!FlushPrelimQueue()) | |
1016 ClosePipeOnError(); | |
1017 | |
1018 if (IsAttachmentBrokerEndpoint() && | |
1019 AttachmentBroker::GetGlobal() && | |
1020 AttachmentBroker::GetGlobal()->IsPrivilegedBroker()) { | |
1021 AttachmentBroker::GetGlobal()->ReceivedPeerPid(pid); | |
1022 } | |
1023 break; | |
1024 | |
1025 #if defined(OS_MACOSX) | |
1026 case Channel::CLOSE_FD_MESSAGE_TYPE: | |
1027 int fd, hops; | |
1028 if (!iter.ReadInt(&hops)) | |
1029 NOTREACHED(); | |
1030 if (!iter.ReadInt(&fd)) | |
1031 NOTREACHED(); | |
1032 if (hops == 0) { | |
1033 if (fds_to_close_.erase(fd) > 0) { | |
1034 if (IGNORE_EINTR(close(fd)) < 0) | |
1035 PLOG(ERROR) << "close"; | |
1036 } else { | |
1037 NOTREACHED(); | |
1038 } | |
1039 } else { | |
1040 QueueCloseFDMessage(fd, hops); | |
1041 } | |
1042 break; | |
1043 #endif | |
1044 } | |
1045 } | |
1046 | |
1047 base::ProcessId ChannelPosix::GetSenderPID() { | |
1048 return GetPeerPID(); | |
1049 } | |
1050 | |
1051 bool ChannelPosix::IsAttachmentBrokerEndpoint() { | |
1052 return is_attachment_broker_endpoint(); | |
1053 } | |
1054 | |
1055 void ChannelPosix::Close() { | |
1056 // Close can be called multiple time, so we need to make sure we're | |
1057 // idempotent. | |
1058 | |
1059 ResetToAcceptingConnectionState(); | |
1060 | |
1061 if (must_unlink_) { | |
1062 unlink(pipe_name_.c_str()); | |
1063 must_unlink_ = false; | |
1064 } | |
1065 | |
1066 if (server_listen_pipe_.is_valid()) { | |
1067 #if defined(OS_NACL_NONSFI) | |
1068 LOG(FATAL) | |
1069 << "IPC channels in nacl_helper_nonsfi should not be SERVER mode."; | |
1070 #else | |
1071 server_listen_pipe_.reset(); | |
1072 // Unregister libevent for the listening socket and close it. | |
1073 server_listen_connection_watcher_.StopWatchingFileDescriptor(); | |
1074 #endif | |
1075 } | |
1076 | |
1077 CloseClientFileDescriptor(); | |
1078 } | |
1079 | |
1080 base::ProcessId ChannelPosix::GetPeerPID() const { | |
1081 return peer_pid_; | |
1082 } | |
1083 | |
1084 base::ProcessId ChannelPosix::GetSelfPID() const { | |
1085 return GetHelloMessageProcId(); | |
1086 } | |
1087 | |
1088 void ChannelPosix::ResetSafely(base::ScopedFD* fd) { | |
1089 if (!in_dtor_) { | |
1090 fd->reset(); | |
1091 return; | |
1092 } | |
1093 | |
1094 // crbug.com/449233 | |
1095 // The CL [1] tightened the error check for closing FDs, but it turned | |
1096 // out that there are existing cases that hit the newly added check. | |
1097 // ResetSafely() is the workaround for that crash, turning it from | |
1098 // from PCHECK() to DPCHECK() so that it doesn't crash in production. | |
1099 // [1] https://crrev.com/ce44fef5fd60dd2be5c587d4b084bdcd36adcee4 | |
1100 int fd_to_close = fd->release(); | |
1101 if (-1 != fd_to_close) { | |
1102 int rv = IGNORE_EINTR(close(fd_to_close)); | |
1103 DPCHECK(0 == rv); | |
1104 } | |
1105 } | |
1106 | |
1107 //------------------------------------------------------------------------------ | |
1108 // Channel's methods | |
1109 | |
1110 // static | |
1111 std::unique_ptr<Channel> Channel::Create( | |
1112 const IPC::ChannelHandle& channel_handle, | |
1113 Mode mode, | |
1114 Listener* listener) { | |
1115 return base::WrapUnique(new ChannelPosix(channel_handle, mode, listener)); | |
1116 } | |
1117 | |
1118 // static | |
1119 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) { | |
1120 // A random name is sufficient validation on posix systems, so we don't need | |
1121 // an additional shared secret. | |
1122 | |
1123 std::string id = prefix; | |
1124 if (!id.empty()) | |
1125 id.append("."); | |
1126 | |
1127 return id.append(GenerateUniqueRandomChannelID()); | |
1128 } | |
1129 | |
1130 bool Channel::IsNamedServerInitialized( | |
1131 const std::string& channel_id) { | |
1132 return ChannelPosix::IsNamedServerInitialized(channel_id); | |
1133 } | |
1134 | |
1135 #if defined(OS_LINUX) | |
1136 // static | |
1137 void Channel::SetGlobalPid(int pid) { | |
1138 ChannelPosix::SetGlobalPid(pid); | |
1139 } | |
1140 int Channel::GetGlobalPid() { | |
1141 return ChannelPosix::GetGlobalPid(); | |
1142 } | |
1143 #endif // OS_LINUX | |
1144 | |
1145 } // namespace IPC | |
OLD | NEW |