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