[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 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 | |
| 5 | #include "ppapi/proxy/nacl_message_scanner.h" |
| 6 | |
avi | e029c413 | 2015-12-23 06:45:22 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
tzik | a0f614d | 2016-03-08 00:35:15 | [diff] [blame] | 9 | #include <tuple> |
dcheng | d2b9f61 | 2015-12-18 19:08:51 | [diff] [blame] | 10 | #include <utility> |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 11 | #include <vector> |
dcheng | d2b9f61 | 2015-12-18 19:08:51 | [diff] [blame] | 12 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 13 | #include "base/bind.h" |
avi | e029c413 | 2015-12-23 06:45:22 | [diff] [blame] | 14 | #include "build/build_config.h" |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 15 | #include "ipc/ipc_message.h" |
| 16 | #include "ipc/ipc_message_macros.h" |
| 17 | #include "ppapi/proxy/ppapi_messages.h" |
| 18 | #include "ppapi/proxy/resource_message_params.h" |
| 19 | #include "ppapi/proxy/serialized_handle.h" |
| 20 | #include "ppapi/proxy/serialized_var.h" |
| 21 | |
| 22 | class NaClDescImcShm; |
| 23 | |
| 24 | namespace IPC { |
| 25 | class Message; |
| 26 | } |
| 27 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 28 | using ppapi::proxy::ResourceMessageReplyParams; |
| 29 | using ppapi::proxy::SerializedHandle; |
| 30 | using ppapi::proxy::SerializedVar; |
| 31 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 32 | namespace { |
| 33 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 34 | typedef std::vector<SerializedHandle> Handles; |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 35 | |
| 36 | struct ScanningResults { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 37 | ScanningResults() : handle_index(0), pp_resource(0) {} |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 38 | |
| 39 | // Vector to hold handles found in the message. |
| 40 | Handles handles; |
| 41 | // Current handle index in the rewritten message. During the scan, it will be |
| 42 | // be less than or equal to handles.size(). After the scan it should be equal. |
| 43 | int handle_index; |
| 44 | // The rewritten message. This may be NULL, so all ScanParam overloads should |
[email protected] | e74d2d1 | 2013-11-02 16:17:37 | [diff] [blame] | 45 | // check for NULL before writing to it. In some cases, a ScanParam overload |
| 46 | // may set this to NULL when it can determine that there are no parameters |
| 47 | // that need conversion. (See the ResourceMessageReplyParams overload.) |
dcheng | ced9224 | 2016-04-07 00:00:12 | [diff] [blame] | 48 | std::unique_ptr<IPC::Message> new_msg; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 49 | // Resource id for resource messages. Save this when scanning resource replies |
| 50 | // so when we audit the nested message, we know which resource it is for. |
| 51 | PP_Resource pp_resource; |
| 52 | // Callback to receive the nested message in a resource message or reply. |
| 53 | base::Callback<void(PP_Resource, const IPC::Message&, SerializedHandle*)> |
| 54 | nested_msg_callback; |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 55 | }; |
| 56 | |
| 57 | void WriteHandle(int handle_index, |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 58 | const SerializedHandle& handle, |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 59 | base::Pickle* msg) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 60 | SerializedHandle::WriteHeader(handle.header(), msg); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 61 | |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 62 | if (handle.type() == SerializedHandle::SHARED_MEMORY) { |
Justin TerAvest | cffdd03 | 2014-09-10 19:21:56 | [diff] [blame] | 63 | // Now write the handle itself in POSIX style. |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 64 | // This serialization must be kept in sync with |
Alexandr Ilin | ebab9da | 2018-06-01 02:37:47 | [diff] [blame^] | 65 | // ParamTraits<SharedMemoryHandle>::Write. |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 66 | if (handle.shmem().IsValid()) { |
| 67 | msg->WriteBool(true); // valid == true |
| 68 | msg->WriteInt(handle_index); |
Alexandr Ilin | ebab9da | 2018-06-01 02:37:47 | [diff] [blame^] | 69 | IPC::WriteParam(msg, handle.shmem().GetGUID()); |
erikchen | 9d6afd71 | 2017-05-18 17:49:06 | [diff] [blame] | 70 | msg->WriteUInt64(handle.shmem().GetSize()); |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 71 | } else { |
| 72 | msg->WriteBool(false); // valid == false |
| 73 | } |
Alexandr Ilin | ebab9da | 2018-06-01 02:37:47 | [diff] [blame^] | 74 | } else if (handle.type() == SerializedHandle::SHARED_MEMORY_REGION) { |
| 75 | // Write the region in POSIX style. |
| 76 | // This serialization must be kept in sync with |
| 77 | // ParamTraits<PlatformSharedMemoryRegion>::Write. |
| 78 | const auto& region = handle.shmem_region(); |
| 79 | if (region.IsValid()) { |
| 80 | IPC::WriteParam(msg, true); // valid == true |
| 81 | IPC::WriteParam(msg, region.GetMode()); |
| 82 | IPC::WriteParam(msg, static_cast<uint64_t>(region.GetSize())); |
| 83 | IPC::WriteParam(msg, region.GetGUID()); |
| 84 | // Writable regions are not supported, so write only one handle index. |
| 85 | DCHECK_NE(region.GetMode(), |
| 86 | base::subtle::PlatformSharedMemoryRegion::Mode::kWritable); |
| 87 | IPC::WriteParam(msg, handle_index); |
| 88 | } else { |
| 89 | msg->WriteBool(false); // valid == false |
| 90 | } |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 91 | } else if (handle.type() != SerializedHandle::INVALID) { |
| 92 | // Now write the handle itself in POSIX style. |
| 93 | // This serialization must be kept in sync with |
| 94 | // ParamTraits<FileDescriptor>::Write. |
Justin TerAvest | cffdd03 | 2014-09-10 19:21:56 | [diff] [blame] | 95 | msg->WriteBool(true); // valid == true |
| 96 | msg->WriteInt(handle_index); |
| 97 | } |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | // Define overloads for each kind of message parameter that requires special |
| 101 | // handling. See ScanTuple for how these get used. |
| 102 | |
| 103 | // Overload to match SerializedHandle. |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 104 | void ScanParam(SerializedHandle&& handle, ScanningResults* results) { |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 105 | if (results->new_msg) |
| 106 | WriteHandle(results->handle_index++, handle, results->new_msg.get()); |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 107 | results->handles.push_back(std::move(handle)); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | void HandleWriter(int* handle_index, |
rockot | 502c94f | 2016-02-03 20:20:16 | [diff] [blame] | 111 | base::Pickle* m, |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 112 | const SerializedHandle& handle) { |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 113 | WriteHandle((*handle_index)++, handle, m); |
| 114 | } |
| 115 | |
| 116 | // Overload to match SerializedVar, which can contain handles. |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 117 | void ScanParam(SerializedVar&& var, ScanningResults* results) { |
| 118 | // Rewrite the message and then copy any handles. |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 119 | if (results->new_msg) |
| 120 | var.WriteDataToMessage(results->new_msg.get(), |
| 121 | base::Bind(&HandleWriter, &results->handle_index)); |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 122 | for (SerializedHandle* var_handle : var.GetHandles()) |
| 123 | results->handles.push_back(std::move(*var_handle)); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | // For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall, |
| 127 | // the handles are carried inside the ResourceMessageReplyParams. |
| 128 | // NOTE: We only intercept handles from host->NaCl. The only kind of |
| 129 | // ResourceMessageParams that travels this direction is |
| 130 | // ResourceMessageReplyParams, so that's the only one we need to handle. |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 131 | void ScanParam(ResourceMessageReplyParams&& params, ScanningResults* results) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 132 | results->pp_resource = params.pp_resource(); |
[email protected] | e74d2d1 | 2013-11-02 16:17:37 | [diff] [blame] | 133 | // If the resource reply params don't contain handles, NULL the new message |
| 134 | // pointer to cancel further rewriting. |
| 135 | // NOTE: This works because only handles currently need rewriting, and we |
| 136 | // know at this point that this message has none. |
| 137 | if (params.handles().empty()) { |
| 138 | results->new_msg.reset(NULL); |
| 139 | return; |
| 140 | } |
| 141 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 142 | // If we need to rewrite the message, write everything before the handles |
| 143 | // (there's nothing after the handles). |
| 144 | if (results->new_msg) { |
| 145 | params.WriteReplyHeader(results->new_msg.get()); |
| 146 | // IPC writes the vector length as an int before the contents of the |
| 147 | // vector. |
| 148 | results->new_msg->WriteInt(static_cast<int>(params.handles().size())); |
| 149 | } |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 150 | std::vector<SerializedHandle> handles; |
| 151 | params.TakeAllHandles(&handles); |
| 152 | for (SerializedHandle& handle : handles) { |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 153 | // ScanParam will write each handle to the new message, if necessary. |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 154 | ScanParam(std::move(handle), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 155 | } |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 156 | } |
| 157 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 158 | // Overload to match nested messages. If we need to rewrite the message, write |
| 159 | // the parameter. |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 160 | void ScanParam(IPC::Message&& param, ScanningResults* results) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 161 | if (results->pp_resource && !results->nested_msg_callback.is_null()) { |
| 162 | SerializedHandle* handle = NULL; |
| 163 | if (results->handles.size() == 1) |
| 164 | handle = &results->handles[0]; |
| 165 | results->nested_msg_callback.Run(results->pp_resource, param, handle); |
| 166 | } |
| 167 | if (results->new_msg) |
| 168 | IPC::WriteParam(results->new_msg.get(), param); |
| 169 | } |
| 170 | |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 171 | template <class T> |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 172 | void ScanParam(std::vector<T>&& vec, ScanningResults* results) { |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 173 | if (results->new_msg) |
| 174 | IPC::WriteParam(results->new_msg.get(), static_cast<int>(vec.size())); |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 175 | for (T& element : vec) |
| 176 | ScanParam(std::move(element), results); |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 177 | } |
| 178 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 179 | // Overload to match all other types. If we need to rewrite the message, write |
| 180 | // the parameter. |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 181 | template <class T> |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 182 | void ScanParam(T&& param, ScanningResults* results) { |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 183 | if (results->new_msg) |
| 184 | IPC::WriteParam(results->new_msg.get(), param); |
| 185 | } |
| 186 | |
| 187 | // These just break apart the given tuple and run ScanParam over each param. |
| 188 | // The idea is to scan elements in the tuple which require special handling, |
| 189 | // and write them into the |results| struct. |
| 190 | template <class A> |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 191 | void ScanTuple(std::tuple<A>&& t1, ScanningResults* results) { |
| 192 | ScanParam(std::move(std::get<0>(t1)), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 193 | } |
| 194 | template <class A, class B> |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 195 | void ScanTuple(std::tuple<A, B>&& t1, ScanningResults* results) { |
| 196 | ScanParam(std::move(std::get<0>(t1)), results); |
| 197 | ScanParam(std::move(std::get<1>(t1)), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 198 | } |
| 199 | template <class A, class B, class C> |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 200 | void ScanTuple(std::tuple<A, B, C>&& t1, ScanningResults* results) { |
| 201 | ScanParam(std::move(std::get<0>(t1)), results); |
| 202 | ScanParam(std::move(std::get<1>(t1)), results); |
| 203 | ScanParam(std::move(std::get<2>(t1)), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 204 | } |
| 205 | template <class A, class B, class C, class D> |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 206 | void ScanTuple(std::tuple<A, B, C, D>&& t1, ScanningResults* results) { |
| 207 | ScanParam(std::move(std::get<0>(t1)), results); |
| 208 | ScanParam(std::move(std::get<1>(t1)), results); |
| 209 | ScanParam(std::move(std::get<2>(t1)), results); |
| 210 | ScanParam(std::move(std::get<3>(t1)), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | template <class MessageType> |
| 214 | class MessageScannerImpl { |
| 215 | public: |
| 216 | explicit MessageScannerImpl(const IPC::Message* msg) |
krasin | 86a5a18 | 2016-02-23 09:59:09 | [diff] [blame] | 217 | // The cast below is invalid. See https://crbug.com/520760. |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 218 | : msg_(static_cast<const MessageType*>(msg)) { |
| 219 | } |
| 220 | bool ScanMessage(ScanningResults* results) { |
mdempsky | 390ab1e | 2016-03-07 22:18:35 | [diff] [blame] | 221 | typename MessageType::Param params; |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 222 | if (!MessageType::Read(msg_, ¶ms)) |
| 223 | return false; |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 224 | ScanTuple(std::move(params), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 225 | return true; |
| 226 | } |
| 227 | |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 228 | bool ScanSyncMessage(ScanningResults* results) { |
mdempsky | 390ab1e | 2016-03-07 22:18:35 | [diff] [blame] | 229 | typename MessageType::SendParam params; |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 230 | if (!MessageType::ReadSendParam(msg_, ¶ms)) |
| 231 | return false; |
| 232 | // If we need to rewrite the message, write the message id first. |
| 233 | if (results->new_msg) { |
| 234 | results->new_msg->set_sync(); |
| 235 | int id = IPC::SyncMessage::GetMessageId(*msg_); |
| 236 | results->new_msg->WriteInt(id); |
| 237 | } |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 238 | ScanTuple(std::move(params), results); |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 239 | return true; |
| 240 | } |
| 241 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 242 | bool ScanReply(ScanningResults* results) { |
mdempsky | 390ab1e | 2016-03-07 22:18:35 | [diff] [blame] | 243 | typename MessageType::ReplyParam params; |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 244 | if (!MessageType::ReadReplyParam(msg_, ¶ms)) |
| 245 | return false; |
| 246 | // If we need to rewrite the message, write the message id first. |
| 247 | if (results->new_msg) { |
| 248 | results->new_msg->set_reply(); |
| 249 | int id = IPC::SyncMessage::GetMessageId(*msg_); |
| 250 | results->new_msg->WriteInt(id); |
| 251 | } |
Alexandr Ilin | 1d00410 | 2018-05-30 10:55:32 | [diff] [blame] | 252 | ScanTuple(std::move(params), results); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 253 | return true; |
| 254 | } |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 255 | |
| 256 | private: |
| 257 | const MessageType* msg_; |
| 258 | }; |
| 259 | |
| 260 | } // namespace |
| 261 | |
| 262 | #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ |
| 263 | case MESSAGE_TYPE::ID: { \ |
| 264 | MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \ |
| 265 | if (rewrite_msg) \ |
| 266 | results.new_msg.reset( \ |
[email protected] | 753bb25 | 2013-11-04 22:28:12 | [diff] [blame] | 267 | new IPC::Message(msg.routing_id(), msg.type(), \ |
| 268 | IPC::Message::PRIORITY_NORMAL)); \ |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 269 | if (!scanner.ScanMessage(&results)) \ |
| 270 | return false; \ |
| 271 | break; \ |
| 272 | } |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 273 | #define CASE_FOR_SYNC_MESSAGE(MESSAGE_TYPE) \ |
| 274 | case MESSAGE_TYPE::ID: { \ |
| 275 | MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \ |
| 276 | if (rewrite_msg) \ |
| 277 | results.new_msg.reset( \ |
| 278 | new IPC::Message(msg.routing_id(), msg.type(), \ |
| 279 | IPC::Message::PRIORITY_NORMAL)); \ |
| 280 | if (!scanner.ScanSyncMessage(&results)) \ |
| 281 | return false; \ |
| 282 | break; \ |
| 283 | } |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 284 | #define CASE_FOR_REPLY(MESSAGE_TYPE) \ |
| 285 | case MESSAGE_TYPE::ID: { \ |
| 286 | MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \ |
| 287 | if (rewrite_msg) \ |
| 288 | results.new_msg.reset( \ |
[email protected] | 753bb25 | 2013-11-04 22:28:12 | [diff] [blame] | 289 | new IPC::Message(msg.routing_id(), msg.type(), \ |
| 290 | IPC::Message::PRIORITY_NORMAL)); \ |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 291 | if (!scanner.ScanReply(&results)) \ |
| 292 | return false; \ |
| 293 | break; \ |
| 294 | } |
| 295 | |
| 296 | namespace ppapi { |
| 297 | namespace proxy { |
| 298 | |
| 299 | class SerializedHandle; |
| 300 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 301 | NaClMessageScanner::FileSystem::FileSystem() |
| 302 | : reserved_quota_(0) { |
| 303 | } |
| 304 | |
| 305 | NaClMessageScanner::FileSystem::~FileSystem() { |
| 306 | } |
| 307 | |
| 308 | bool NaClMessageScanner::FileSystem::UpdateReservedQuota(int64_t delta) { |
| 309 | base::AutoLock lock(lock_); |
| 310 | if (std::numeric_limits<int64_t>::max() - reserved_quota_ < delta) |
| 311 | return false; // reserved_quota_ + delta would overflow. |
| 312 | if (reserved_quota_ + delta < 0) |
| 313 | return false; |
| 314 | reserved_quota_ += delta; |
| 315 | return true; |
| 316 | } |
| 317 | |
| 318 | NaClMessageScanner::FileIO::FileIO(FileSystem* file_system, |
| 319 | int64_t max_written_offset) |
| 320 | : file_system_(file_system), |
| 321 | max_written_offset_(max_written_offset) { |
| 322 | } |
| 323 | |
| 324 | NaClMessageScanner::FileIO::~FileIO() { |
| 325 | } |
| 326 | |
| 327 | void NaClMessageScanner::FileIO::SetMaxWrittenOffset( |
| 328 | int64_t max_written_offset) { |
| 329 | base::AutoLock lock(lock_); |
| 330 | max_written_offset_ = max_written_offset; |
| 331 | } |
| 332 | |
| 333 | bool NaClMessageScanner::FileIO::Grow(int64_t amount) { |
| 334 | base::AutoLock lock(lock_); |
| 335 | DCHECK(amount > 0); |
| 336 | if (!file_system_->UpdateReservedQuota(-amount)) |
| 337 | return false; |
| 338 | max_written_offset_ += amount; |
| 339 | return true; |
| 340 | } |
| 341 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 342 | NaClMessageScanner::NaClMessageScanner() { |
| 343 | } |
| 344 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 345 | NaClMessageScanner::~NaClMessageScanner() { |
| 346 | for (FileSystemMap::iterator it = file_systems_.begin(); |
| 347 | it != file_systems_.end(); ++it) |
| 348 | delete it->second; |
| 349 | for (FileIOMap::iterator it = files_.begin(); it != files_.end(); ++it) |
| 350 | delete it->second; |
| 351 | } |
| 352 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 353 | // Windows IPC differs from POSIX in that native handles are serialized in the |
| 354 | // message body, rather than passed in a separate FileDescriptorSet. Therefore, |
| 355 | // on Windows, any message containing handles must be rewritten in the POSIX |
| 356 | // format before we can send it to the NaCl plugin. |
scottmg | d19b4f7 | 2015-06-19 22:51:00 | [diff] [blame] | 357 | // On Mac, base::SharedMemoryHandle has a different serialization than |
| 358 | // base::FileDescriptor (which base::SharedMemoryHandle is typedef-ed to in |
| 359 | // OS_NACL). |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 360 | bool NaClMessageScanner::ScanMessage( |
| 361 | const IPC::Message& msg, |
[email protected] | c8f326a | 2014-08-21 23:19:07 | [diff] [blame] | 362 | uint32_t type, |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 363 | std::vector<SerializedHandle>* handles, |
dcheng | ced9224 | 2016-04-07 00:00:12 | [diff] [blame] | 364 | std::unique_ptr<IPC::Message>* new_msg_ptr) { |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 365 | DCHECK(handles); |
| 366 | DCHECK(handles->empty()); |
| 367 | DCHECK(new_msg_ptr); |
| 368 | DCHECK(!new_msg_ptr->get()); |
| 369 | |
| 370 | bool rewrite_msg = |
scottmg | d19b4f7 | 2015-06-19 22:51:00 | [diff] [blame] | 371 | #if defined(OS_WIN) || defined(OS_MACOSX) |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 372 | true; |
| 373 | #else |
[email protected] | 73af633 | 2014-02-06 23:28:10 | [diff] [blame] | 374 | false; |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 375 | #endif |
| 376 | |
| 377 | // We can't always tell from the message ID if rewriting is needed. Therefore, |
[email protected] | e74d2d1 | 2013-11-02 16:17:37 | [diff] [blame] | 378 | // scan any message types that might contain a handle. If we later determine |
| 379 | // that there are no handles, we can cancel the rewriting by clearing the |
| 380 | // results.new_msg pointer. |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 381 | ScanningResults results; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 382 | results.nested_msg_callback = |
| 383 | base::Bind(&NaClMessageScanner::AuditNestedMessage, |
| 384 | base::Unretained(this)); |
[email protected] | c8f326a | 2014-08-21 23:19:07 | [diff] [blame] | 385 | switch (type) { |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 386 | CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) |
| 387 | CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage) |
| 388 | CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) |
dmichael | 822ba8f | 2016-01-11 17:54:52 | [diff] [blame] | 389 | CASE_FOR_SYNC_MESSAGE(PpapiMsg_PPPMessageHandler_HandleBlockingMessage) |
mseaborn | 98d206ca | 2016-01-08 11:43:28 | [diff] [blame] | 390 | CASE_FOR_SYNC_MESSAGE(PpapiMsg_PnaclTranslatorCompileInit) |
mseaborn | 3bedcdc | 2016-01-04 21:14:13 | [diff] [blame] | 391 | CASE_FOR_SYNC_MESSAGE(PpapiMsg_PnaclTranslatorLink) |
Justin TerAvest | cffdd03 | 2014-09-10 19:21:56 | [diff] [blame] | 392 | CASE_FOR_REPLY(PpapiHostMsg_OpenResource) |
penghuang | a206fb49 | 2014-09-09 21:27:32 | [diff] [blame] | 393 | CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_Create) |
[email protected] | c8f326a | 2014-08-21 23:19:07 | [diff] [blame] | 394 | CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer) |
| 395 | CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple) |
| 396 | CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) |
| 397 | CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory) |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 398 | default: |
| 399 | // Do nothing for messages we don't know. |
| 400 | break; |
| 401 | } |
| 402 | |
| 403 | // Only messages containing handles need to be rewritten. If no handles are |
| 404 | // found, don't return the rewritten message either. This must be changed if |
| 405 | // we ever add new param types that also require rewriting. |
| 406 | if (!results.handles.empty()) { |
| 407 | handles->swap(results.handles); |
dcheng | d2b9f61 | 2015-12-18 19:08:51 | [diff] [blame] | 408 | *new_msg_ptr = std::move(results.new_msg); |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 409 | } |
| 410 | return true; |
| 411 | } |
| 412 | |
[email protected] | c586216c | 2013-12-18 21:59:17 | [diff] [blame] | 413 | void NaClMessageScanner::ScanUntrustedMessage( |
| 414 | const IPC::Message& untrusted_msg, |
dcheng | ced9224 | 2016-04-07 00:00:12 | [diff] [blame] | 415 | std::unique_ptr<IPC::Message>* new_msg_ptr) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 416 | // Audit FileIO and FileSystem messages to ensure that the plugin doesn't |
| 417 | // exceed its file quota. If we find the message is malformed, just pass it |
| 418 | // through - we only care about well formed messages to the host. |
| 419 | if (untrusted_msg.type() == PpapiHostMsg_ResourceCall::ID) { |
| 420 | ResourceMessageCallParams params; |
| 421 | IPC::Message nested_msg; |
| 422 | if (!UnpackMessage<PpapiHostMsg_ResourceCall>( |
| 423 | untrusted_msg, ¶ms, &nested_msg)) |
| 424 | return; |
| 425 | |
| 426 | switch (nested_msg.type()) { |
| 427 | case PpapiHostMsg_FileIO_Close::ID: { |
| 428 | FileIOMap::iterator it = files_.find(params.pp_resource()); |
| 429 | if (it == files_.end()) |
| 430 | return; |
| 431 | // Audit FileIO Close messages to make sure the plugin reports an |
| 432 | // accurate file size. |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 433 | FileGrowth file_growth; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 434 | if (!UnpackMessage<PpapiHostMsg_FileIO_Close>( |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 435 | nested_msg, &file_growth)) |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 436 | return; |
| 437 | |
| 438 | int64_t trusted_max_written_offset = it->second->max_written_offset(); |
| 439 | delete it->second; |
| 440 | files_.erase(it); |
| 441 | // If the plugin is under-reporting, rewrite the message with the |
| 442 | // trusted value. |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 443 | if (trusted_max_written_offset > file_growth.max_written_offset) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 444 | new_msg_ptr->reset( |
| 445 | new PpapiHostMsg_ResourceCall( |
| 446 | params, |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 447 | PpapiHostMsg_FileIO_Close( |
| 448 | FileGrowth(trusted_max_written_offset, 0)))); |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 449 | } |
[email protected] | 2d585cbd | 2014-06-03 02:13:22 | [diff] [blame] | 450 | break; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 451 | } |
| 452 | case PpapiHostMsg_FileIO_SetLength::ID: { |
| 453 | FileIOMap::iterator it = files_.find(params.pp_resource()); |
| 454 | if (it == files_.end()) |
| 455 | return; |
| 456 | // Audit FileIO SetLength messages to make sure the plugin is within |
| 457 | // the current quota reservation. In addition, deduct the file size |
| 458 | // increase from the quota reservation. |
| 459 | int64_t length = 0; |
| 460 | if (!UnpackMessage<PpapiHostMsg_FileIO_SetLength>( |
| 461 | nested_msg, &length)) |
| 462 | return; |
| 463 | |
| 464 | // Calculate file size increase, taking care to avoid overflows. |
| 465 | if (length < 0) |
| 466 | return; |
| 467 | int64_t trusted_max_written_offset = it->second->max_written_offset(); |
| 468 | int64_t increase = length - trusted_max_written_offset; |
| 469 | if (increase <= 0) |
| 470 | return; |
| 471 | if (!it->second->Grow(increase)) { |
| 472 | new_msg_ptr->reset( |
| 473 | new PpapiHostMsg_ResourceCall( |
| 474 | params, |
| 475 | PpapiHostMsg_FileIO_SetLength(-1))); |
| 476 | } |
| 477 | break; |
| 478 | } |
| 479 | case PpapiHostMsg_FileSystem_ReserveQuota::ID: { |
| 480 | // Audit FileSystem ReserveQuota messages to make sure the plugin |
| 481 | // reports accurate file sizes. |
| 482 | int64_t amount = 0; |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 483 | FileGrowthMap file_growths; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 484 | if (!UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>( |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 485 | nested_msg, &amount, &file_growths)) |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 486 | return; |
| 487 | |
| 488 | bool audit_failed = false; |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 489 | for (FileGrowthMap::iterator it = file_growths.begin(); |
| 490 | it != file_growths.end(); ++it) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 491 | FileIOMap::iterator file_it = files_.find(it->first); |
| 492 | if (file_it == files_.end()) |
| 493 | continue; |
| 494 | int64_t trusted_max_written_offset = |
| 495 | file_it->second->max_written_offset(); |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 496 | if (trusted_max_written_offset > it->second.max_written_offset) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 497 | audit_failed = true; |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 498 | it->second.max_written_offset = trusted_max_written_offset; |
| 499 | } |
| 500 | if (it->second.append_mode_write_amount < 0) { |
| 501 | audit_failed = true; |
| 502 | it->second.append_mode_write_amount = 0; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 503 | } |
| 504 | } |
| 505 | if (audit_failed) { |
| 506 | new_msg_ptr->reset( |
| 507 | new PpapiHostMsg_ResourceCall( |
| 508 | params, |
| 509 | PpapiHostMsg_FileSystem_ReserveQuota( |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 510 | amount, file_growths))); |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 511 | } |
| 512 | break; |
| 513 | } |
| 514 | case PpapiHostMsg_ResourceDestroyed::ID: { |
| 515 | // Audit resource destroyed messages to release FileSystems. |
| 516 | PP_Resource resource; |
| 517 | if (!UnpackMessage<PpapiHostMsg_ResourceDestroyed>( |
| 518 | nested_msg, &resource)) |
| 519 | return; |
| 520 | FileSystemMap::iterator fs_it = file_systems_.find(resource); |
| 521 | if (fs_it != file_systems_.end()) { |
| 522 | delete fs_it->second; |
| 523 | file_systems_.erase(fs_it); |
| 524 | } |
[email protected] | 2d585cbd | 2014-06-03 02:13:22 | [diff] [blame] | 525 | break; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 526 | } |
| 527 | } |
| 528 | } |
[email protected] | c586216c | 2013-12-18 21:59:17 | [diff] [blame] | 529 | } |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 530 | |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 531 | NaClMessageScanner::FileIO* NaClMessageScanner::GetFile( |
| 532 | PP_Resource file_io) { |
| 533 | FileIOMap::iterator it = files_.find(file_io); |
| 534 | DCHECK(it != files_.end()); |
| 535 | return it->second; |
| 536 | } |
| 537 | |
| 538 | void NaClMessageScanner::AuditNestedMessage(PP_Resource resource, |
| 539 | const IPC::Message& msg, |
| 540 | SerializedHandle* handle) { |
| 541 | switch (msg.type()) { |
| 542 | case PpapiPluginMsg_FileIO_OpenReply::ID: { |
| 543 | // A file that requires quota checking was opened. |
| 544 | PP_Resource quota_file_system; |
| 545 | int64_t max_written_offset = 0; |
| 546 | if (ppapi::UnpackMessage<PpapiPluginMsg_FileIO_OpenReply>( |
| 547 | msg, "a_file_system, &max_written_offset)) { |
| 548 | if (quota_file_system) { |
| 549 | // Look up the FileSystem by inserting a new one. If it was already |
| 550 | // present, get the existing one, otherwise construct it. |
| 551 | FileSystem* file_system = NULL; |
| 552 | std::pair<FileSystemMap::iterator, bool> insert_result = |
| 553 | file_systems_.insert(std::make_pair(quota_file_system, |
| 554 | file_system)); |
| 555 | if (insert_result.second) |
| 556 | insert_result.first->second = new FileSystem(); |
| 557 | file_system = insert_result.first->second; |
| 558 | // Create the FileIO. |
| 559 | DCHECK(files_.find(resource) == files_.end()); |
| 560 | files_.insert(std::make_pair( |
| 561 | resource, |
| 562 | new FileIO(file_system, max_written_offset))); |
| 563 | } |
| 564 | } |
| 565 | break; |
| 566 | } |
| 567 | case PpapiPluginMsg_FileSystem_ReserveQuotaReply::ID: { |
| 568 | // The amount of reserved quota for a FileSystem was refreshed. |
| 569 | int64_t amount = 0; |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 570 | FileSizeMap file_sizes; |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 571 | if (ppapi::UnpackMessage<PpapiPluginMsg_FileSystem_ReserveQuotaReply>( |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 572 | msg, &amount, &file_sizes)) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 573 | FileSystemMap::iterator it = file_systems_.find(resource); |
| 574 | DCHECK(it != file_systems_.end()); |
| 575 | it->second->UpdateReservedQuota(amount); |
| 576 | |
[email protected] | 540d6af4 | 2014-01-28 21:19:03 | [diff] [blame] | 577 | FileSizeMap::const_iterator offset_it = file_sizes.begin(); |
| 578 | for (; offset_it != file_sizes.end(); ++offset_it) { |
[email protected] | 7a90b85 | 2013-12-28 17:54:27 | [diff] [blame] | 579 | FileIOMap::iterator fio_it = files_.find(offset_it->first); |
| 580 | DCHECK(fio_it != files_.end()); |
| 581 | if (fio_it != files_.end()) |
| 582 | fio_it->second->SetMaxWrittenOffset(offset_it->second); |
| 583 | } |
| 584 | } |
| 585 | break; |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | |
[email protected] | 6276b49 | 2013-11-02 13:38:31 | [diff] [blame] | 590 | } // namespace proxy |
| 591 | } // namespace ppapi |