ipc_helper.cpp revision d618b567630d347be0929ea25ce6c68921005ed6
1#include "uds/ipc_helper.h" 2 3#include <alloca.h> 4#include <errno.h> 5#include <log/log.h> 6#include <poll.h> 7#include <string.h> 8#include <sys/inotify.h> 9#include <sys/param.h> 10#include <sys/socket.h> 11 12#include <algorithm> 13 14#include <pdx/service.h> 15#include <pdx/utility.h> 16 17namespace android { 18namespace pdx { 19namespace uds { 20 21namespace { 22 23// Default implementations of Send/Receive interfaces to use standard socket 24// send/sendmsg/recv/recvmsg functions. 25class SocketSender : public SendInterface { 26 public: 27 ssize_t Send(int socket_fd, const void* data, size_t size, 28 int flags) override { 29 return send(socket_fd, data, size, flags); 30 } 31 ssize_t SendMessage(int socket_fd, const msghdr* msg, int flags) override { 32 return sendmsg(socket_fd, msg, flags); 33 } 34} g_socket_sender; 35 36class SocketReceiver : public RecvInterface { 37 public: 38 ssize_t Receive(int socket_fd, void* data, size_t size, int flags) override { 39 return recv(socket_fd, data, size, flags); 40 } 41 ssize_t ReceiveMessage(int socket_fd, msghdr* msg, int flags) override { 42 return recvmsg(socket_fd, msg, flags); 43 } 44} g_socket_receiver; 45 46} // anonymous namespace 47 48// Helper wrappers around send()/sendmsg() which repeat send() calls on data 49// that was not sent with the initial call to send/sendmsg. This is important to 50// handle transmissions interrupted by signals. 51Status<void> SendAll(SendInterface* sender, const BorrowedHandle& socket_fd, 52 const void* data, size_t size) { 53 Status<void> ret; 54 const uint8_t* ptr = static_cast<const uint8_t*>(data); 55 while (size > 0) { 56 ssize_t size_written = 57 RETRY_EINTR(sender->Send(socket_fd.Get(), ptr, size, MSG_NOSIGNAL)); 58 if (size_written < 0) { 59 ret.SetError(errno); 60 ALOGE("SendAll: Failed to send data over socket: %s", 61 ret.GetErrorMessage().c_str()); 62 break; 63 } 64 size -= size_written; 65 ptr += size_written; 66 } 67 return ret; 68} 69 70Status<void> SendMsgAll(SendInterface* sender, const BorrowedHandle& socket_fd, 71 const msghdr* msg) { 72 Status<void> ret; 73 ssize_t sent_size = 74 RETRY_EINTR(sender->SendMessage(socket_fd.Get(), msg, MSG_NOSIGNAL)); 75 if (sent_size < 0) { 76 ret.SetError(errno); 77 ALOGE("SendMsgAll: Failed to send data over socket: %s", 78 ret.GetErrorMessage().c_str()); 79 return ret; 80 } 81 82 ssize_t chunk_start_offset = 0; 83 for (size_t i = 0; i < msg->msg_iovlen; i++) { 84 ssize_t chunk_end_offset = chunk_start_offset + msg->msg_iov[i].iov_len; 85 if (sent_size < chunk_end_offset) { 86 size_t offset_within_chunk = sent_size - chunk_start_offset; 87 size_t data_size = msg->msg_iov[i].iov_len - offset_within_chunk; 88 const uint8_t* chunk_base = 89 static_cast<const uint8_t*>(msg->msg_iov[i].iov_base); 90 ret = SendAll(sender, socket_fd, chunk_base + offset_within_chunk, 91 data_size); 92 if (!ret) 93 break; 94 sent_size += data_size; 95 } 96 chunk_start_offset = chunk_end_offset; 97 } 98 return ret; 99} 100 101// Helper wrappers around recv()/recvmsg() which repeat recv() calls on data 102// that was not received with the initial call to recvmsg(). This is important 103// to handle transmissions interrupted by signals as well as the case when 104// initial data did not arrive in a single chunk over the socket (e.g. socket 105// buffer was full at the time of transmission, and only portion of initial 106// message was sent and the rest was blocked until the buffer was cleared by the 107// receiving side). 108Status<void> RecvMsgAll(RecvInterface* receiver, 109 const BorrowedHandle& socket_fd, msghdr* msg) { 110 Status<void> ret; 111 ssize_t size_read = RETRY_EINTR(receiver->ReceiveMessage( 112 socket_fd.Get(), msg, MSG_WAITALL | MSG_CMSG_CLOEXEC)); 113 if (size_read < 0) { 114 ret.SetError(errno); 115 ALOGE("RecvMsgAll: Failed to receive data from socket: %s", 116 ret.GetErrorMessage().c_str()); 117 return ret; 118 } else if (size_read == 0) { 119 ret.SetError(ESHUTDOWN); 120 ALOGW("RecvMsgAll: Socket has been shut down"); 121 return ret; 122 } 123 124 ssize_t chunk_start_offset = 0; 125 for (size_t i = 0; i < msg->msg_iovlen; i++) { 126 ssize_t chunk_end_offset = chunk_start_offset + msg->msg_iov[i].iov_len; 127 if (size_read < chunk_end_offset) { 128 size_t offset_within_chunk = size_read - chunk_start_offset; 129 size_t data_size = msg->msg_iov[i].iov_len - offset_within_chunk; 130 uint8_t* chunk_base = static_cast<uint8_t*>(msg->msg_iov[i].iov_base); 131 ret = RecvAll(receiver, socket_fd, chunk_base + offset_within_chunk, 132 data_size); 133 if (!ret) 134 break; 135 size_read += data_size; 136 } 137 chunk_start_offset = chunk_end_offset; 138 } 139 return ret; 140} 141 142Status<void> RecvAll(RecvInterface* receiver, const BorrowedHandle& socket_fd, 143 void* data, size_t size) { 144 Status<void> ret; 145 uint8_t* ptr = static_cast<uint8_t*>(data); 146 while (size > 0) { 147 ssize_t size_read = RETRY_EINTR(receiver->Receive( 148 socket_fd.Get(), ptr, size, MSG_WAITALL | MSG_CMSG_CLOEXEC)); 149 if (size_read < 0) { 150 ret.SetError(errno); 151 ALOGE("RecvAll: Failed to receive data from socket: %s", 152 ret.GetErrorMessage().c_str()); 153 break; 154 } else if (size_read == 0) { 155 ret.SetError(ESHUTDOWN); 156 ALOGW("RecvAll: Socket has been shut down"); 157 break; 158 } 159 size -= size_read; 160 ptr += size_read; 161 } 162 return ret; 163} 164 165uint32_t kMagicPreamble = 0x7564736d; // 'udsm'. 166 167struct MessagePreamble { 168 uint32_t magic{0}; 169 uint32_t data_size{0}; 170 uint32_t fd_count{0}; 171}; 172 173Status<void> SendPayload::Send(const BorrowedHandle& socket_fd) { 174 return Send(socket_fd, nullptr); 175} 176 177Status<void> SendPayload::Send(const BorrowedHandle& socket_fd, 178 const ucred* cred) { 179 SendInterface* sender = sender_ ? sender_ : &g_socket_sender; 180 MessagePreamble preamble; 181 preamble.magic = kMagicPreamble; 182 preamble.data_size = buffer_.size(); 183 preamble.fd_count = file_handles_.size(); 184 Status<void> ret = SendAll(sender, socket_fd, &preamble, sizeof(preamble)); 185 if (!ret) 186 return ret; 187 188 msghdr msg = {}; 189 iovec recv_vect = {buffer_.data(), buffer_.size()}; 190 msg.msg_iov = &recv_vect; 191 msg.msg_iovlen = 1; 192 193 if (cred || !file_handles_.empty()) { 194 const size_t fd_bytes = file_handles_.size() * sizeof(int); 195 msg.msg_controllen = (cred ? CMSG_SPACE(sizeof(ucred)) : 0) + 196 (fd_bytes == 0 ? 0 : CMSG_SPACE(fd_bytes)); 197 msg.msg_control = alloca(msg.msg_controllen); 198 199 cmsghdr* control = CMSG_FIRSTHDR(&msg); 200 if (cred) { 201 control->cmsg_level = SOL_SOCKET; 202 control->cmsg_type = SCM_CREDENTIALS; 203 control->cmsg_len = CMSG_LEN(sizeof(ucred)); 204 memcpy(CMSG_DATA(control), cred, sizeof(ucred)); 205 control = CMSG_NXTHDR(&msg, control); 206 } 207 208 if (fd_bytes) { 209 control->cmsg_level = SOL_SOCKET; 210 control->cmsg_type = SCM_RIGHTS; 211 control->cmsg_len = CMSG_LEN(fd_bytes); 212 memcpy(CMSG_DATA(control), file_handles_.data(), fd_bytes); 213 } 214 } 215 216 return SendMsgAll(sender, socket_fd, &msg); 217} 218 219// MessageWriter 220void* SendPayload::GetNextWriteBufferSection(size_t size) { 221 return buffer_.grow_by(size); 222} 223 224OutputResourceMapper* SendPayload::GetOutputResourceMapper() { return this; } 225 226// OutputResourceMapper 227Status<FileReference> SendPayload::PushFileHandle(const LocalHandle& handle) { 228 if (handle) { 229 const int ref = file_handles_.size(); 230 file_handles_.push_back(handle.Get()); 231 return ref; 232 } else { 233 return handle.Get(); 234 } 235} 236 237Status<FileReference> SendPayload::PushFileHandle( 238 const BorrowedHandle& handle) { 239 if (handle) { 240 const int ref = file_handles_.size(); 241 file_handles_.push_back(handle.Get()); 242 return ref; 243 } else { 244 return handle.Get(); 245 } 246} 247 248Status<FileReference> SendPayload::PushFileHandle(const RemoteHandle& handle) { 249 return handle.Get(); 250} 251 252Status<ChannelReference> SendPayload::PushChannelHandle( 253 const LocalChannelHandle& /*handle*/) { 254 return ErrorStatus{EOPNOTSUPP}; 255} 256Status<ChannelReference> SendPayload::PushChannelHandle( 257 const BorrowedChannelHandle& /*handle*/) { 258 return ErrorStatus{EOPNOTSUPP}; 259} 260Status<ChannelReference> SendPayload::PushChannelHandle( 261 const RemoteChannelHandle& /*handle*/) { 262 return ErrorStatus{EOPNOTSUPP}; 263} 264 265Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd) { 266 return Receive(socket_fd, nullptr); 267} 268 269Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd, 270 ucred* cred) { 271 RecvInterface* receiver = receiver_ ? receiver_ : &g_socket_receiver; 272 MessagePreamble preamble; 273 Status<void> ret = RecvAll(receiver, socket_fd, &preamble, sizeof(preamble)); 274 if (!ret) 275 return ret; 276 277 if (preamble.magic != kMagicPreamble) { 278 ret.SetError(EIO); 279 return ret; 280 } 281 282 buffer_.resize(preamble.data_size); 283 file_handles_.clear(); 284 read_pos_ = 0; 285 286 msghdr msg = {}; 287 iovec recv_vect = {buffer_.data(), buffer_.size()}; 288 msg.msg_iov = &recv_vect; 289 msg.msg_iovlen = 1; 290 291 if (cred || preamble.fd_count) { 292 const size_t receive_fd_bytes = preamble.fd_count * sizeof(int); 293 msg.msg_controllen = 294 (cred ? CMSG_SPACE(sizeof(ucred)) : 0) + 295 (receive_fd_bytes == 0 ? 0 : CMSG_SPACE(receive_fd_bytes)); 296 msg.msg_control = alloca(msg.msg_controllen); 297 } 298 299 ret = RecvMsgAll(receiver, socket_fd, &msg); 300 if (!ret) 301 return ret; 302 303 bool cred_available = false; 304 file_handles_.reserve(preamble.fd_count); 305 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); 306 while (cmsg) { 307 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && 308 cred && cmsg->cmsg_len == CMSG_LEN(sizeof(ucred))) { 309 cred_available = true; 310 memcpy(cred, CMSG_DATA(cmsg), sizeof(ucred)); 311 } else if (cmsg->cmsg_level == SOL_SOCKET && 312 cmsg->cmsg_type == SCM_RIGHTS) { 313 socklen_t payload_len = cmsg->cmsg_len - CMSG_LEN(0); 314 const int* fds = reinterpret_cast<const int*>(CMSG_DATA(cmsg)); 315 size_t fd_count = payload_len / sizeof(int); 316 std::transform(fds, fds + fd_count, std::back_inserter(file_handles_), 317 [](int fd) { return LocalHandle{fd}; }); 318 } 319 cmsg = CMSG_NXTHDR(&msg, cmsg); 320 } 321 322 if (cred && !cred_available) 323 ret.SetError(EIO); 324 325 return ret; 326} 327 328// MessageReader 329MessageReader::BufferSection ReceivePayload::GetNextReadBufferSection() { 330 return {buffer_.data() + read_pos_, &*buffer_.end()}; 331} 332 333void ReceivePayload::ConsumeReadBufferSectionData(const void* new_start) { 334 read_pos_ = PointerDistance(new_start, buffer_.data()); 335} 336 337InputResourceMapper* ReceivePayload::GetInputResourceMapper() { return this; } 338 339// InputResourceMapper 340bool ReceivePayload::GetFileHandle(FileReference ref, LocalHandle* handle) { 341 if (ref < 0) { 342 *handle = LocalHandle{ref}; 343 return true; 344 } 345 if (static_cast<size_t>(ref) > file_handles_.size()) 346 return false; 347 *handle = std::move(file_handles_[ref]); 348 return true; 349} 350 351bool ReceivePayload::GetChannelHandle(ChannelReference /*ref*/, 352 LocalChannelHandle* /*handle*/) { 353 return false; 354} 355 356Status<void> SendData(const BorrowedHandle& socket_fd, const void* data, 357 size_t size) { 358 return SendAll(&g_socket_sender, socket_fd, data, size); 359} 360 361Status<void> SendDataVector(const BorrowedHandle& socket_fd, const iovec* data, 362 size_t count) { 363 msghdr msg = {}; 364 msg.msg_iov = const_cast<iovec*>(data); 365 msg.msg_iovlen = count; 366 return SendMsgAll(&g_socket_sender, socket_fd, &msg); 367} 368 369Status<void> ReceiveData(const BorrowedHandle& socket_fd, void* data, 370 size_t size) { 371 return RecvAll(&g_socket_receiver, socket_fd, data, size); 372} 373 374Status<void> ReceiveDataVector(const BorrowedHandle& socket_fd, 375 const iovec* data, size_t count) { 376 msghdr msg = {}; 377 msg.msg_iov = const_cast<iovec*>(data); 378 msg.msg_iovlen = count; 379 return RecvMsgAll(&g_socket_receiver, socket_fd, &msg); 380} 381 382size_t CountVectorSize(const iovec* vector, size_t count) { 383 return std::accumulate( 384 vector, vector + count, size_t{0}, 385 [](size_t size, const iovec& vec) { return size + vec.iov_len; }); 386} 387 388void InitRequest(android::pdx::uds::RequestHeader<BorrowedHandle>* request, 389 int opcode, uint32_t send_len, uint32_t max_recv_len, 390 bool is_impulse) { 391 request->op = opcode; 392 request->cred.pid = getpid(); 393 request->cred.uid = geteuid(); 394 request->cred.gid = getegid(); 395 request->send_len = send_len; 396 request->max_recv_len = max_recv_len; 397 request->is_impulse = is_impulse; 398} 399 400Status<void> WaitForEndpoint(const std::string& endpoint_path, 401 int64_t timeout_ms) { 402 // Endpoint path must be absolute. 403 if (endpoint_path.empty() || endpoint_path.front() != '/') 404 return ErrorStatus(EINVAL); 405 406 // Create inotify fd. 407 LocalHandle fd{inotify_init()}; 408 if (!fd) 409 return ErrorStatus(errno); 410 411 // Set the inotify fd to non-blocking. 412 int ret = fcntl(fd.Get(), F_GETFL); 413 fcntl(fd.Get(), F_SETFL, ret | O_NONBLOCK); 414 415 // Setup the pollfd. 416 pollfd pfd = {fd.Get(), POLLIN, 0}; 417 418 // Find locations of each path separator. 419 std::vector<size_t> separators{0}; // The path is absolute, so '/' is at #0. 420 size_t pos = endpoint_path.find('/', 1); 421 while (pos != std::string::npos) { 422 separators.push_back(pos); 423 pos = endpoint_path.find('/', pos + 1); 424 } 425 separators.push_back(endpoint_path.size()); 426 427 // Walk down the path, checking for existence and waiting if needed. 428 pos = 1; 429 size_t links = 0; 430 std::string current; 431 while (pos < separators.size() && links <= MAXSYMLINKS) { 432 std::string previous = current; 433 current = endpoint_path.substr(0, separators[pos]); 434 435 // Check for existence; proceed to setup a watch if not. 436 if (access(current.c_str(), F_OK) < 0) { 437 if (errno != ENOENT) 438 return ErrorStatus(errno); 439 440 // Extract the name of the path component to wait for. 441 std::string next = current.substr( 442 separators[pos - 1] + 1, separators[pos] - separators[pos - 1] - 1); 443 444 // Add a watch on the last existing directory we reach. 445 int wd = inotify_add_watch( 446 fd.Get(), previous.c_str(), 447 IN_CREATE | IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVED_TO); 448 if (wd < 0) { 449 if (errno != ENOENT) 450 return ErrorStatus(errno); 451 // Restart at the beginning if previous was deleted. 452 links = 0; 453 current.clear(); 454 pos = 1; 455 continue; 456 } 457 458 // Make sure current didn't get created before the watch was added. 459 ret = access(current.c_str(), F_OK); 460 if (ret < 0) { 461 if (errno != ENOENT) 462 return ErrorStatus(errno); 463 464 bool exit_poll = false; 465 while (!exit_poll) { 466 // Wait for an event or timeout. 467 ret = poll(&pfd, 1, timeout_ms); 468 if (ret <= 0) 469 return ErrorStatus(ret == 0 ? ETIMEDOUT : errno); 470 471 // Read events. 472 char buffer[sizeof(inotify_event) + NAME_MAX + 1]; 473 474 ret = read(fd.Get(), buffer, sizeof(buffer)); 475 if (ret < 0) { 476 if (errno == EAGAIN || errno == EWOULDBLOCK) 477 continue; 478 else 479 return ErrorStatus(errno); 480 } else if (static_cast<size_t>(ret) < sizeof(struct inotify_event)) { 481 return ErrorStatus(EIO); 482 } 483 484 auto* event = reinterpret_cast<const inotify_event*>(buffer); 485 auto* end = reinterpret_cast<const inotify_event*>(buffer + ret); 486 while (event < end) { 487 std::string event_for; 488 if (event->len > 0) 489 event_for = event->name; 490 491 if (event->mask & (IN_CREATE | IN_MOVED_TO)) { 492 // See if this is the droid we're looking for. 493 if (next == event_for) { 494 exit_poll = true; 495 break; 496 } 497 } else if (event->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) { 498 // Restart at the beginning if our watch dir is deleted. 499 links = 0; 500 current.clear(); 501 pos = 0; 502 exit_poll = true; 503 break; 504 } 505 506 event = reinterpret_cast<const inotify_event*>(AdvancePointer( 507 event, sizeof(struct inotify_event) + event->len)); 508 } // while (event < end) 509 } // while (!exit_poll) 510 } // Current dir doesn't exist. 511 ret = inotify_rm_watch(fd.Get(), wd); 512 if (ret < 0 && errno != EINVAL) 513 return ErrorStatus(errno); 514 } // if (access(current.c_str(), F_OK) < 0) 515 516 // Check for symbolic link and update link count. 517 struct stat stat_buf; 518 ret = lstat(current.c_str(), &stat_buf); 519 if (ret < 0 && errno != ENOENT) 520 return ErrorStatus(errno); 521 else if (ret == 0 && S_ISLNK(stat_buf.st_mode)) 522 links++; 523 pos++; 524 } // while (pos < separators.size() && links <= MAXSYMLINKS) 525 526 return {}; 527} 528 529} // namespace uds 530} // namespace pdx 531} // namespace android 532