| 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 |