Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e41826ac authored by Alex Vakulenko's avatar Alex Vakulenko
Browse files

libpdx_uds: Always create channel sockets in the server process

Whenever a client connects to PDX service endpoint, the connected
socket was being used as the channel connection. This makes it
difficult to ensure that the socket has the appropriate SELinux
label applied.

Changed the implementation to make sure that the actual channel socket
pair is created in one place in the server process.

The new Endpoint::CreateChannelSocketPair() is now being used to
create the channel sockets when an incoming connection is accepted
and when PushChannel request is received.

The newly created channel socket is sent to the client in response
to connection request.

Bug: 37646189
Test: Device boots. CubeSea launches.
Change-Id: Id3158484aeb18007f18b279afc60613076f80f14
parent 871795f9
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(

  bool connected = socket_.IsValid();
  if (!connected) {
    socket_.Reset(socket(AF_UNIX, SOCK_STREAM, 0));
    socket_.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
    LOG_ALWAYS_FATAL_IF(
        endpoint_path_.empty(),
        "ClientChannelFactory::Connect: unspecified socket path");
@@ -123,6 +123,15 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
      connected = true;
      ALOGD("ClientChannelFactory: Connected successfully to %s...",
            remote.sun_path);
      ChannelConnectionInfo<LocalHandle> connection_info;
      status = ReceiveData(socket_.Borrow(), &connection_info);
      if (!status)
        return status.error_status();
      socket_ = std::move(connection_info.channel_fd);
      if (!socket_) {
        ALOGE("ClientChannelFactory::Connect: Failed to obtain channel socket");
        return ErrorStatus(EIO);
      }
    }
    if (use_timeout)
      now = steady_clock::now();
@@ -132,11 +141,11 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
  InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
  status = SendData(socket_.Borrow(), request);
  if (!status)
    return ErrorStatus(status.error());
    return status.error_status();
  ResponseHeader<LocalHandle> response;
  status = ReceiveData(socket_.Borrow(), &response);
  if (!status)
    return ErrorStatus(status.error());
    return status.error_status();
  int ref = response.ret_code;
  if (ref < 0 || static_cast<size_t>(ref) > response.file_descriptors.size())
    return ErrorStatus(EIO);
+9 −0
Original line number Diff line number Diff line
@@ -115,6 +115,15 @@ class ChannelInfo {
  PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, event_fd);
};

template <typename FileHandleType>
class ChannelConnectionInfo {
 public:
  FileHandleType channel_fd;

 private:
  PDX_SERIALIZABLE_MEMBERS(ChannelConnectionInfo, channel_fd);
};

template <typename FileHandleType>
class RequestHeader {
 public:
+2 −0
Original line number Diff line number Diff line
@@ -142,6 +142,8 @@ class Endpoint : public pdx::Endpoint {
  BorrowedHandle GetChannelSocketFd(int32_t channel_id);
  BorrowedHandle GetChannelEventFd(int32_t channel_id);
  int32_t GetChannelId(const BorrowedHandle& channel_fd);
  Status<void> CreateChannelSocketPair(LocalHandle* local_socket,
                                       LocalHandle* remote_socket);

  std::string endpoint_path_;
  bool is_blocking_;
+54 −30
Original line number Diff line number Diff line
@@ -214,30 +214,42 @@ Status<void> Endpoint::AcceptConnection(Message* message) {

  sockaddr_un remote;
  socklen_t addrlen = sizeof(remote);
  LocalHandle channel_fd{accept4(socket_fd_.Get(),
                                 reinterpret_cast<sockaddr*>(&remote), &addrlen,
                                 SOCK_CLOEXEC)};
  if (!channel_fd) {
  LocalHandle connection_fd{accept4(socket_fd_.Get(),
                                    reinterpret_cast<sockaddr*>(&remote),
                                    &addrlen, SOCK_CLOEXEC)};
  if (!connection_fd) {
    ALOGE("Endpoint::AcceptConnection: failed to accept connection: %s",
          strerror(errno));
    return ErrorStatus(errno);
  }

  int optval = 1;
  if (setsockopt(channel_fd.Get(), SOL_SOCKET, SO_PASSCRED, &optval,
                 sizeof(optval)) == -1) {
    ALOGE(
        "Endpoint::AcceptConnection: Failed to enable the receiving of the "
        "credentials for channel %d: %s",
        channel_fd.Get(), strerror(errno));
    return ErrorStatus(errno);
  LocalHandle local_socket;
  LocalHandle remote_socket;
  auto status = CreateChannelSocketPair(&local_socket, &remote_socket);
  if (!status)
    return status;

  // Borrow the local channel handle before we move it into OnNewChannel().
  BorrowedHandle channel_handle = local_socket.Borrow();
  status = OnNewChannel(std::move(local_socket));
  if (!status)
    return status;

  // Send the channel socket fd to the client.
  ChannelConnectionInfo<LocalHandle> connection_info;
  connection_info.channel_fd = std::move(remote_socket);
  status = SendData(connection_fd.Borrow(), connection_info);

  if (status) {
    // Get the CHANNEL_OPEN message from client over the channel socket.
    status = ReceiveMessageForChannel(channel_handle, message);
  } else {
    CloseChannel(GetChannelId(channel_handle));
  }

  // Borrow the channel handle before we pass (move) it into OnNewChannel().
  BorrowedHandle borrowed_channel_handle = channel_fd.Borrow();
  auto status = OnNewChannel(std::move(channel_fd));
  if (status)
    status = ReceiveMessageForChannel(borrowed_channel_handle, message);
  // Don't need the connection socket anymore. Further communication should
  // happen over the channel socket.
  shutdown(connection_fd.Get(), SHUT_WR);
  return status;
}

@@ -349,29 +361,41 @@ Status<void> Endpoint::ModifyChannelEvents(int channel_id, int clear_mask,
  return ErrorStatus{EINVAL};
}

Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message,
                                                  int /*flags*/,
                                                  Channel* channel,
                                                  int* channel_id) {
Status<void> Endpoint::CreateChannelSocketPair(LocalHandle* local_socket,
                                               LocalHandle* remote_socket) {
  Status<void> status;
  int channel_pair[2] = {};
  if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_pair) == -1) {
    ALOGE("Endpoint::PushChannel: Failed to create a socket pair: %s",
    ALOGE("Endpoint::CreateChannelSocketPair: Failed to create socket pair: %s",
          strerror(errno));
    return ErrorStatus(errno);
    status.SetError(errno);
    return status;
  }

  LocalHandle local_socket{channel_pair[0]};
  LocalHandle remote_socket{channel_pair[1]};
  local_socket->Reset(channel_pair[0]);
  remote_socket->Reset(channel_pair[1]);

  int optval = 1;
  if (setsockopt(local_socket.Get(), SOL_SOCKET, SO_PASSCRED, &optval,
  if (setsockopt(local_socket->Get(), SOL_SOCKET, SO_PASSCRED, &optval,
                 sizeof(optval)) == -1) {
    ALOGE(
        "Endpoint::PushChannel: Failed to enable the receiving of the "
        "credentials for channel %d: %s",
        local_socket.Get(), strerror(errno));
    return ErrorStatus(errno);
        "Endpoint::CreateChannelSocketPair: Failed to enable the receiving of "
        "the credentials for channel %d: %s",
        local_socket->Get(), strerror(errno));
    status.SetError(errno);
  }
  return status;
}

Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message,
                                                  int /*flags*/,
                                                  Channel* channel,
                                                  int* channel_id) {
  LocalHandle local_socket;
  LocalHandle remote_socket;
  auto status = CreateChannelSocketPair(&local_socket, &remote_socket);
  if (!status)
    return status.error_status();

  std::lock_guard<std::mutex> autolock(channel_mutex_);
  auto channel_data = OnNewChannelLocked(std::move(local_socket), channel);