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