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 "ipc/ipc_message.h" 6#include "ppapi/proxy/nacl_message_scanner.h" 7#include "ppapi/proxy/ppapi_messages.h" 8#include "ppapi/proxy/ppapi_proxy_test.h" 9#include "ppapi/proxy/serialized_handle.h" 10#include "ppapi/shared_impl/host_resource.h" 11 12namespace ppapi { 13namespace proxy { 14 15namespace { 16const PP_Resource kInvalidResource = 0; 17const PP_Resource kFileSystem = 1; 18const PP_Resource kFileIO = 2; 19const int64_t kQuotaReservationAmount = 100; 20} 21 22class NaClMessageScannerTest : public PluginProxyTest { 23 public: 24 NaClMessageScannerTest() {} 25 26 uint32 FindPendingSyncMessage( 27 const NaClMessageScanner& scanner, 28 const IPC::Message& msg) { 29 int msg_id = IPC::SyncMessage::GetMessageId(msg); 30 std::map<int, uint32>::const_iterator it = 31 scanner.pending_sync_msgs_.find(msg_id); 32 // O can signal that no message was found. 33 return (it != scanner.pending_sync_msgs_.end()) ? it->second : 0; 34 } 35 36 NaClMessageScanner::FileSystem* FindFileSystem( 37 const NaClMessageScanner& scanner, 38 PP_Resource file_system) { 39 NaClMessageScanner::FileSystemMap::const_iterator it = 40 scanner.file_systems_.find(file_system); 41 return (it != scanner.file_systems_.end()) ? it->second : NULL; 42 } 43 44 NaClMessageScanner::FileIO* FindFileIO( 45 const NaClMessageScanner& scanner, 46 PP_Resource file_io) { 47 NaClMessageScanner::FileIOMap::const_iterator it = 48 scanner.files_.find(file_io); 49 return (it != scanner.files_.end()) ? it->second : NULL; 50 } 51 52 void OpenQuotaFile(NaClMessageScanner* scanner, 53 PP_Resource file_io, 54 PP_Resource file_system) { 55 std::vector<SerializedHandle> unused_handles; 56 ResourceMessageReplyParams fio_reply_params(file_io, 0); 57 scoped_ptr<IPC::Message> new_msg_ptr; 58 scanner->ScanMessage( 59 PpapiPluginMsg_ResourceReply( 60 fio_reply_params, 61 PpapiPluginMsg_FileIO_OpenReply(file_system, 0)), 62 &unused_handles, 63 &new_msg_ptr); 64 EXPECT_FALSE(new_msg_ptr); 65 } 66}; 67 68TEST_F(NaClMessageScannerTest, SyncMessageAndReply) { 69 NaClMessageScanner test; 70 ppapi::proxy::SerializedHandle handle( 71 ppapi::proxy::SerializedHandle::SHARED_MEMORY); 72 int id = -1; 73 IPC::Message msg = 74 PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer( 75 ppapi::API_ID_PPB_GRAPHICS_3D, 76 HostResource(), 77 4096, // size 78 &id, 79 &handle); 80 scoped_ptr<IPC::Message> new_msg_ptr; 81 EXPECT_NE(msg.type(), FindPendingSyncMessage(test, msg)); 82 test.ScanUntrustedMessage(msg, &new_msg_ptr); 83 EXPECT_FALSE(new_msg_ptr); 84 EXPECT_EQ(msg.type(), FindPendingSyncMessage(test, msg)); 85 86 // TODO(bbudge) Figure out how to put together a sync reply message. 87} 88 89TEST_F(NaClMessageScannerTest, FileOpenClose) { 90 NaClMessageScanner test; 91 std::vector<SerializedHandle> unused_handles; 92 ResourceMessageCallParams fio_call_params(kFileIO, 0); 93 ResourceMessageCallParams fs_call_params(kFileSystem, 0); 94 ResourceMessageReplyParams fio_reply_params(kFileIO, 0); 95 ResourceMessageReplyParams fs_reply_params(kFileSystem, 0); 96 scoped_ptr<IPC::Message> new_msg_ptr; 97 98 EXPECT_EQ(NULL, FindFileSystem(test, kFileSystem)); 99 EXPECT_EQ(NULL, FindFileIO(test, kFileIO)); 100 101 // Open a file, not in a quota file system. 102 test.ScanMessage( 103 PpapiPluginMsg_ResourceReply( 104 fio_reply_params, 105 PpapiPluginMsg_FileIO_OpenReply(kInvalidResource, 0)), 106 &unused_handles, 107 &new_msg_ptr); 108 EXPECT_FALSE(new_msg_ptr); 109 EXPECT_FALSE(FindFileSystem(test, kFileSystem)); 110 EXPECT_FALSE(FindFileIO(test, kFileIO)); 111 112 // Open a file in a quota file system; info objects for it and its file system 113 // should be created. 114 OpenQuotaFile(&test, kFileIO, kFileSystem); 115 NaClMessageScanner::FileSystem* fs = FindFileSystem(test, kFileSystem); 116 NaClMessageScanner::FileIO* fio = FindFileIO(test, kFileIO); 117 EXPECT_TRUE(fs); 118 EXPECT_EQ(0, fs->reserved_quota()); 119 EXPECT_TRUE(fio); 120 EXPECT_EQ(0, fio->max_written_offset()); 121 122 const int64_t kNewFileSize = 10; 123 fio->SetMaxWrittenOffset(kNewFileSize); 124 125 // We should not be able to under-report max_written_offset when closing. 126 test.ScanUntrustedMessage( 127 PpapiHostMsg_ResourceCall( 128 fio_call_params, 129 PpapiHostMsg_FileIO_Close(FileGrowth(0, 0))), 130 &new_msg_ptr); 131 EXPECT_TRUE(new_msg_ptr); 132 ResourceMessageCallParams call_params; 133 IPC::Message nested_msg; 134 FileGrowth file_growth; 135 EXPECT_TRUE(UnpackMessage<PpapiHostMsg_ResourceCall>( 136 *new_msg_ptr, &call_params, &nested_msg) && 137 UnpackMessage<PpapiHostMsg_FileIO_Close>( 138 nested_msg, &file_growth)); 139 new_msg_ptr.reset(); 140 EXPECT_EQ(kNewFileSize, file_growth.max_written_offset); 141 EXPECT_FALSE(FindFileIO(test, kFileIO)); 142 143 // Reopen the file. 144 OpenQuotaFile(&test, kFileIO, kFileSystem); 145 fio = FindFileIO(test, kFileIO); 146 fio->SetMaxWrittenOffset(kNewFileSize); 147 148 // Close with correct max_written_offset. 149 test.ScanUntrustedMessage( 150 PpapiHostMsg_ResourceCall( 151 fio_call_params, 152 PpapiHostMsg_FileIO_Close(FileGrowth(kNewFileSize, 0))), 153 &new_msg_ptr); 154 EXPECT_FALSE(new_msg_ptr); 155 EXPECT_FALSE(FindFileIO(test, kFileIO)); 156 157 // Destroy file system. 158 test.ScanUntrustedMessage( 159 PpapiHostMsg_ResourceCall( 160 fs_call_params, 161 PpapiHostMsg_ResourceDestroyed(kFileSystem)), 162 &new_msg_ptr); 163 EXPECT_FALSE(FindFileSystem(test, kFileSystem)); 164} 165 166TEST_F(NaClMessageScannerTest, QuotaAuditing) { 167 NaClMessageScanner test; 168 std::vector<SerializedHandle> unused_handles; 169 ResourceMessageCallParams fio_call_params(kFileIO, 0); 170 ResourceMessageCallParams fs_call_params(kFileSystem, 0); 171 ResourceMessageReplyParams fio_reply_params(kFileIO, 0); 172 ResourceMessageReplyParams fs_reply_params(kFileSystem, 0); 173 scoped_ptr<IPC::Message> new_msg_ptr; 174 175 OpenQuotaFile(&test, kFileIO, kFileSystem); 176 NaClMessageScanner::FileSystem* fs = FindFileSystem(test, kFileSystem); 177 NaClMessageScanner::FileIO* fio = FindFileIO(test, kFileIO); 178 EXPECT_TRUE(fs); 179 EXPECT_EQ(0, fs->reserved_quota()); 180 EXPECT_TRUE(fio); 181 EXPECT_EQ(0, fio->max_written_offset()); 182 183 // Without reserving quota, we should not be able to grow the file. 184 EXPECT_FALSE(fio->Grow(1)); 185 EXPECT_EQ(0, fs->reserved_quota()); 186 EXPECT_EQ(0, fio->max_written_offset()); 187 188 // Receive reserved quota, and updated file sizes. 189 const int64_t kNewFileSize = 10; 190 FileSizeMap file_sizes; 191 file_sizes[kFileIO] = kNewFileSize; 192 test.ScanMessage( 193 PpapiPluginMsg_ResourceReply( 194 fs_reply_params, 195 PpapiPluginMsg_FileSystem_ReserveQuotaReply( 196 kQuotaReservationAmount, 197 file_sizes)), 198 &unused_handles, 199 &new_msg_ptr); 200 EXPECT_FALSE(new_msg_ptr); 201 EXPECT_EQ(kQuotaReservationAmount, fs->reserved_quota()); 202 EXPECT_EQ(kNewFileSize, fio->max_written_offset()); 203 204 // We should be able to grow the file within quota. 205 EXPECT_TRUE(fio->Grow(1)); 206 EXPECT_EQ(kQuotaReservationAmount - 1, fs->reserved_quota()); 207 EXPECT_EQ(kNewFileSize + 1, fio->max_written_offset()); 208 209 // We should not be able to grow the file over quota. 210 EXPECT_FALSE(fio->Grow(kQuotaReservationAmount)); 211 EXPECT_EQ(kQuotaReservationAmount - 1, fs->reserved_quota()); 212 EXPECT_EQ(kNewFileSize + 1, fio->max_written_offset()); 213 214 // Plugin should not under-report max written offsets when reserving quota. 215 file_sizes[kFileIO] = 0; // should be kNewFileSize + 1. 216 test.ScanUntrustedMessage( 217 PpapiHostMsg_ResourceCall( 218 fio_call_params, 219 PpapiHostMsg_FileSystem_ReserveQuota( 220 kQuotaReservationAmount, 221 FileSizeMapToFileGrowthMapForTesting(file_sizes))), 222 &new_msg_ptr); 223 EXPECT_TRUE(new_msg_ptr); 224 ResourceMessageCallParams call_params; 225 IPC::Message nested_msg; 226 int64_t amount = 0; 227 FileGrowthMap new_file_growths; 228 EXPECT_TRUE(UnpackMessage<PpapiHostMsg_ResourceCall>( 229 *new_msg_ptr, &call_params, &nested_msg) && 230 UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>( 231 nested_msg, &amount, &new_file_growths)); 232 new_msg_ptr.reset(); 233 EXPECT_EQ(kQuotaReservationAmount, amount); 234 EXPECT_EQ(kNewFileSize + 1, new_file_growths[kFileIO].max_written_offset); 235} 236 237TEST_F(NaClMessageScannerTest, SetLength) { 238 NaClMessageScanner test; 239 std::vector<SerializedHandle> unused_handles; 240 ResourceMessageCallParams fio_call_params(kFileIO, 0); 241 ResourceMessageCallParams fs_call_params(kFileSystem, 0); 242 ResourceMessageReplyParams fio_reply_params(kFileIO, 0); 243 ResourceMessageReplyParams fs_reply_params(kFileSystem, 0); 244 scoped_ptr<IPC::Message> new_msg_ptr; 245 246 OpenQuotaFile(&test, kFileIO, kFileSystem); 247 NaClMessageScanner::FileSystem* fs = FindFileSystem(test, kFileSystem); 248 NaClMessageScanner::FileIO* fio = FindFileIO(test, kFileIO); 249 250 // Receive reserved quota, and updated file sizes. 251 const int64_t kNewFileSize = 10; 252 FileSizeMap file_sizes; 253 file_sizes[kFileIO] = 0; 254 test.ScanMessage( 255 PpapiPluginMsg_ResourceReply( 256 fs_reply_params, 257 PpapiPluginMsg_FileSystem_ReserveQuotaReply( 258 kQuotaReservationAmount, 259 file_sizes)), 260 &unused_handles, 261 &new_msg_ptr); 262 263 // We should be able to SetLength within quota. 264 test.ScanUntrustedMessage( 265 PpapiHostMsg_ResourceCall( 266 fio_call_params, 267 PpapiHostMsg_FileIO_SetLength(kNewFileSize)), 268 &new_msg_ptr); 269 EXPECT_FALSE(new_msg_ptr); 270 EXPECT_EQ(kQuotaReservationAmount - kNewFileSize, fs->reserved_quota()); 271 EXPECT_EQ(kNewFileSize, fio->max_written_offset()); 272 273 // We shouldn't be able to SetLength beyond quota. The message should be 274 // rewritten to fail with length == -1. 275 test.ScanUntrustedMessage( 276 PpapiHostMsg_ResourceCall( 277 fio_call_params, 278 PpapiHostMsg_FileIO_SetLength(kQuotaReservationAmount + 1)), 279 &new_msg_ptr); 280 EXPECT_TRUE(new_msg_ptr); 281 ResourceMessageCallParams call_params; 282 IPC::Message nested_msg; 283 int64_t length = 0; 284 EXPECT_TRUE(UnpackMessage<PpapiHostMsg_ResourceCall>( 285 *new_msg_ptr, &call_params, &nested_msg) && 286 UnpackMessage<PpapiHostMsg_FileIO_SetLength>( 287 nested_msg, &length)); 288 new_msg_ptr.reset(); 289 EXPECT_EQ(-1, length); 290 EXPECT_EQ(kQuotaReservationAmount - kNewFileSize, fs->reserved_quota()); 291 EXPECT_EQ(kNewFileSize, fio->max_written_offset()); 292} 293 294} // namespace proxy 295} // namespace ppapi 296