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