nacl_ipc_adapter.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2013 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. #ifndef COMPONENTS_NACL_LOADER_NACL_IPC_ADAPTER_H_
  5. #define COMPONENTS_NACL_LOADER_NACL_IPC_ADAPTER_H_
  6. #include <stddef.h>
  7. #include <map>
  8. #include <memory>
  9. #include <string>
  10. #include "base/callback.h"
  11. #include "base/containers/queue.h"
  12. #include "base/files/scoped_file.h"
  13. #include "base/memory/ref_counted.h"
  14. #include "base/pickle.h"
  15. #include "base/synchronization/condition_variable.h"
  16. #include "base/synchronization/lock.h"
  17. #include "base/task/task_runner.h"
  18. #include "build/build_config.h"
  19. #include "ipc/ipc_listener.h"
  20. #include "ipc/ipc_platform_file.h"
  21. #include "ppapi/c/pp_stdint.h"
  22. #include "ppapi/proxy/nacl_message_scanner.h"
  23. struct NaClDesc;
  24. struct NaClImcTypedMsgHdr;
  25. namespace base {
  26. class SingleThreadTaskRunner;
  27. }
  28. namespace IPC {
  29. class Channel;
  30. struct ChannelHandle;
  31. }
  32. // Adapts a Chrome IPC channel to an IPC channel that we expose to Native
  33. // Client. This provides a mapping in both directions, so when IPC messages
  34. // come in from another process, we rewrite them and allow them to be received
  35. // via a recvmsg-like interface in the NaCl code. When NaCl code calls sendmsg,
  36. // we implement that as sending IPC messages on the channel.
  37. //
  38. // This object also provides the necessary logic for rewriting IPC messages.
  39. // NaCl code is platform-independent and runs in a Posix-like enviroment, but
  40. // some formatting in the message and the way handles are transferred varies
  41. // by platform. This class bridges that gap to provide what looks like a
  42. // normal platform-specific IPC implementation to Chrome, and a Posix-like
  43. // version on every platform to NaCl.
  44. //
  45. // This object must be threadsafe since the nacl environment determines which
  46. // thread every function is called on.
  47. class NaClIPCAdapter : public base::RefCountedThreadSafe<NaClIPCAdapter>,
  48. public IPC::Listener {
  49. public:
  50. // Chrome's IPC message format varies by platform, NaCl's does not. In
  51. // particular, the header has some extra fields on Posix platforms. Since
  52. // NaCl is a Posix environment, it gets that version of the header. This
  53. // header is duplicated here so we have a cross-platform definition of the
  54. // header we're exposing to NaCl.
  55. #pragma pack(push, 4)
  56. struct NaClMessageHeader : public base::Pickle::Header {
  57. int32_t routing;
  58. uint32_t type;
  59. uint32_t flags;
  60. uint16_t num_fds;
  61. uint16_t pad;
  62. };
  63. #pragma pack(pop)
  64. typedef base::OnceCallback<void(IPC::PlatformFileForTransit, base::FilePath)>
  65. ResolveFileTokenReplyCallback;
  66. typedef base::RepeatingCallback<void(uint64_t, // file_token_lo
  67. uint64_t, // file_token_hi
  68. ResolveFileTokenReplyCallback)>
  69. ResolveFileTokenCallback;
  70. typedef base::OnceCallback<
  71. void(const IPC::Message&, IPC::PlatformFileForTransit, base::FilePath)>
  72. OpenResourceReplyCallback;
  73. typedef base::RepeatingCallback<bool(const IPC::Message&,
  74. const std::string&, // key
  75. OpenResourceReplyCallback)>
  76. OpenResourceCallback;
  77. // Creates an adapter, using the thread associated with the given task
  78. // runner for posting messages. In normal use, the task runner will post to
  79. // the I/O thread of the process.
  80. //
  81. // If you use this constructor, you MUST call ConnectChannel after the
  82. // NaClIPCAdapter is constructed, or the NaClIPCAdapter's channel will not be
  83. // connected.
  84. //
  85. // |resolve_file_token_cb| is an optional callback to be invoked for
  86. // resolving file tokens received from the renderer. When the file token
  87. // is resolved, the ResolveFileTokenReplyCallback passed inside the
  88. // ResolveFileTokenCallback will be invoked. |open_resource_cb| is also an
  89. // optional callback to be invoked for intercepting open_resource IRT calls.
  90. // |open_resource_cb| may immediately call a OpenResourceReplyCallback
  91. // function to send a pre-opened resource descriptor to the untrusted side.
  92. // OpenResourceCallback returns true when OpenResourceReplyCallback is called.
  93. NaClIPCAdapter(const IPC::ChannelHandle& handle,
  94. const scoped_refptr<base::SingleThreadTaskRunner>& runner,
  95. ResolveFileTokenCallback resolve_file_token_cb,
  96. OpenResourceCallback open_resource_cb);
  97. // Initializes with a given channel that's already created for testing
  98. // purposes. This function will take ownership of the given channel.
  99. NaClIPCAdapter(std::unique_ptr<IPC::Channel> channel,
  100. base::TaskRunner* runner);
  101. NaClIPCAdapter(const NaClIPCAdapter&) = delete;
  102. NaClIPCAdapter& operator=(const NaClIPCAdapter&) = delete;
  103. // Connect the channel. This must be called after the constructor that accepts
  104. // an IPC::ChannelHandle, and causes the Channel to be connected on the IO
  105. // thread.
  106. void ConnectChannel();
  107. // Implementation of sendmsg. Returns the number of bytes written or -1 on
  108. // failure.
  109. int Send(const NaClImcTypedMsgHdr* msg);
  110. // Implementation of recvmsg. Returns the number of bytes read or -1 on
  111. // failure. This will block until there's an error or there is data to
  112. // read.
  113. int BlockingReceive(NaClImcTypedMsgHdr* msg);
  114. // Closes the IPC channel.
  115. void CloseChannel();
  116. // Make a NaClDesc that refers to this NaClIPCAdapter. Note that the returned
  117. // NaClDesc is reference-counted, and a reference is returned.
  118. NaClDesc* MakeNaClDesc();
  119. // Listener implementation.
  120. bool OnMessageReceived(const IPC::Message& message) override;
  121. void OnChannelConnected(int32_t peer_pid) override;
  122. void OnChannelError() override;
  123. private:
  124. friend class base::RefCountedThreadSafe<NaClIPCAdapter>;
  125. class RewrittenMessage;
  126. // This is the data that must only be accessed inside the lock. This struct
  127. // just separates it so it's easier to see.
  128. struct LockedData {
  129. LockedData();
  130. ~LockedData();
  131. // Messages that we have read off of the Chrome IPC channel that are waiting
  132. // to be received by the plugin.
  133. base::queue<std::unique_ptr<RewrittenMessage>> to_be_received_;
  134. ppapi::proxy::NaClMessageScanner nacl_msg_scanner_;
  135. // Data that we've queued from the plugin to send, but doesn't consist of a
  136. // full message yet. The calling code can break apart the message into
  137. // smaller pieces, and we need to send the message to the other process in
  138. // one chunk.
  139. //
  140. // The IPC channel always starts a new send() at the beginning of each
  141. // message, so we don't need to worry about arbitrary message boundaries.
  142. std::string to_be_sent_;
  143. bool channel_closed_;
  144. };
  145. // This is the data that must only be accessed on the I/O thread (as defined
  146. // by TaskRunner). This struct just separates it so it's easier to see.
  147. struct IOThreadData {
  148. IOThreadData();
  149. ~IOThreadData();
  150. std::unique_ptr<IPC::Channel> channel_;
  151. // When we send a synchronous message (from untrusted to trusted), we store
  152. // its type here, so that later we can associate the reply with its type
  153. // for scanning.
  154. typedef std::map<int, uint32_t> PendingSyncMsgMap;
  155. PendingSyncMsgMap pending_sync_msgs_;
  156. };
  157. ~NaClIPCAdapter() override;
  158. void SaveOpenResourceMessage(const IPC::Message& orig_msg,
  159. IPC::PlatformFileForTransit ipc_fd,
  160. base::FilePath file_path);
  161. bool RewriteMessage(const IPC::Message& msg, uint32_t type);
  162. // Returns 0 if nothing is waiting.
  163. int LockedReceive(NaClImcTypedMsgHdr* msg);
  164. // Sends a message that we know has been completed to the Chrome process.
  165. bool SendCompleteMessage(const char* buffer, size_t buffer_len);
  166. // Clears the LockedData.to_be_sent_ structure in a way to make sure that
  167. // the memory is deleted. std::string can sometimes hold onto the buffer
  168. // for future use which we don't want.
  169. void ClearToBeSent();
  170. void ConnectChannelOnIOThread();
  171. void CloseChannelOnIOThread();
  172. void SendMessageOnIOThread(std::unique_ptr<IPC::Message> message);
  173. // Saves the message to forward to NaCl. This method assumes that the caller
  174. // holds the lock for locked_data_.
  175. void SaveMessage(const IPC::Message& message,
  176. std::unique_ptr<RewrittenMessage> rewritten_message);
  177. base::Lock lock_;
  178. base::ConditionVariable cond_var_;
  179. scoped_refptr<base::TaskRunner> task_runner_;
  180. ResolveFileTokenCallback resolve_file_token_cb_;
  181. OpenResourceCallback open_resource_cb_;
  182. // To be accessed inside of lock_ only.
  183. LockedData locked_data_;
  184. // To be accessed on the I/O thread (via task runner) only.
  185. IOThreadData io_thread_data_;
  186. };
  187. // Export TranslatePepperFileReadWriteOpenFlags for testing.
  188. int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags);
  189. #endif // COMPONENTS_NACL_LOADER_NACL_IPC_ADAPTER_H_