1 // Copyright (c) 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 <errno.h> 6 #include <fcntl.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <string> 10 11 #include "gtest/gtest.h" 12 #include "nacl_io/ioctl.h" 13 #include "nacl_io/mount.h" 14 #include "nacl_io/mount_dev.h" 15 #include "nacl_io/mount_mem.h" 16 #include "nacl_io/osdirent.h" 17 #include "nacl_io/osunistd.h" 18 19 using namespace nacl_io; 20 21 namespace { 22 23 class MountMemMock : public MountMem { 24 public: 25 MountMemMock() { 26 StringMap_t map; 27 EXPECT_EQ(0, Init(1, map, NULL)); 28 } 29 30 int num_nodes() { return (int) inode_pool_.size(); } 31 }; 32 33 class MountDevMock : public MountDev { 34 public: 35 MountDevMock() { 36 StringMap_t map; 37 Init(1, map, NULL); 38 } 39 int num_nodes() { return (int) inode_pool_.size(); } 40 }; 41 42 } // namespace 43 44 #define NULL_NODE ((MountNode*) NULL) 45 46 TEST(MountTest, Sanity) { 47 MountMemMock* mnt = new MountMemMock(); 48 49 ScopedMountNode file; 50 ScopedMountNode root; 51 ScopedMountNode result_node; 52 53 size_t result_size = 0; 54 int result_bytes = 0; 55 char buf1[1024]; 56 57 // A memory mount starts with one directory node: the root. 58 EXPECT_EQ(1, mnt->num_nodes()); 59 60 // Fail to open non existent file 61 EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), R_OK | W_OK)); 62 EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node)); 63 EXPECT_EQ(NULL, result_node.get()); 64 EXPECT_EQ(1, mnt->num_nodes()); 65 66 // Create a file 67 EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file)); 68 EXPECT_NE(NULL_NODE, file.get()); 69 if (file == NULL) 70 return; 71 72 // We now have a directory and a file. The file has a two references 73 // one returned to the test, one for the name->inode map. 74 EXPECT_EQ(2, mnt->num_nodes()); 75 EXPECT_EQ(2, file->RefCount()); 76 EXPECT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK)); 77 EXPECT_EQ(EACCES, mnt->Access(Path("/foo"), X_OK)); 78 79 // Write access should be allowed on the root directory. 80 EXPECT_EQ(0, mnt->Access(Path("/"), R_OK | W_OK)); 81 EXPECT_EQ(EACCES, mnt->Access(Path("/"), X_OK)); 82 // Open the root directory for write should fail. 83 EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root)); 84 EXPECT_EQ(2, mnt->num_nodes()); 85 86 // Open the root directory, should not create a new file 87 EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root)); 88 EXPECT_EQ(2, mnt->num_nodes()); 89 EXPECT_NE(NULL_NODE, root.get()); 90 if (NULL != root) { 91 struct dirent dirs[2]; 92 int len; 93 EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len)); 94 EXPECT_EQ(sizeof(struct dirent), len); 95 } 96 97 // Fail to re-create the same file 98 EXPECT_EQ(EEXIST, 99 mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node)); 100 EXPECT_EQ(NULL_NODE, result_node.get()); 101 EXPECT_EQ(2, mnt->num_nodes()); 102 103 // Fail to create a directory with the same name 104 EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR)); 105 EXPECT_EQ(2, mnt->num_nodes()); 106 107 // Attempt to READ/WRITE 108 EXPECT_EQ(0, file->GetSize(&result_size)); 109 EXPECT_EQ(0, result_size); 110 EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes)); 111 EXPECT_EQ(sizeof(buf1), result_bytes); 112 EXPECT_EQ(0, file->GetSize(&result_size)); 113 EXPECT_EQ(sizeof(buf1), result_size); 114 EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes)); 115 EXPECT_EQ(sizeof(buf1), result_bytes); 116 EXPECT_EQ(2, mnt->num_nodes()); 117 EXPECT_EQ(2, file->RefCount()); 118 119 // Attempt to open the same file, create another ref to it, but does not 120 // create a new file. 121 EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &result_node)); 122 EXPECT_EQ(3, file->RefCount()); 123 EXPECT_EQ(2, mnt->num_nodes()); 124 EXPECT_EQ(file.get(), result_node.get()); 125 EXPECT_EQ(0, file->GetSize(&result_size)); 126 EXPECT_EQ(sizeof(buf1), result_size); 127 128 // Remove our references so that only the Mount holds it 129 file.reset(); 130 result_node.reset(); 131 EXPECT_EQ(2, mnt->num_nodes()); 132 133 // This should have deleted the object 134 EXPECT_EQ(0, mnt->Unlink(Path("/foo"))); 135 EXPECT_EQ(1, mnt->num_nodes()); 136 137 // We should fail to find it 138 EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo"))); 139 EXPECT_EQ(1, mnt->num_nodes()); 140 141 // Recreate foo as a directory 142 EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR)); 143 EXPECT_EQ(2, mnt->num_nodes()); 144 145 // Create a file (exclusively) 146 EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file)); 147 EXPECT_NE(NULL_NODE, file.get()); 148 if (NULL == file) 149 return; 150 EXPECT_EQ(2, file->RefCount()); 151 EXPECT_EQ(3, mnt->num_nodes()); 152 153 // Attempt to delete the directory and fail 154 EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo"))); 155 EXPECT_EQ(2, root->RefCount()); 156 EXPECT_EQ(2, file->RefCount()); 157 EXPECT_EQ(3, mnt->num_nodes()); 158 159 // Unlink the file, we should have the only file ref at this point. 160 EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar"))); 161 EXPECT_EQ(2, root->RefCount()); 162 EXPECT_EQ(1, file->RefCount()); 163 EXPECT_EQ(3, mnt->num_nodes()); 164 165 166 // Deref the file, to make it go away 167 file.reset(); 168 EXPECT_EQ(2, mnt->num_nodes()); 169 170 // Deref the directory 171 EXPECT_EQ(0, mnt->Rmdir(Path("/foo"))); 172 EXPECT_EQ(1, mnt->num_nodes()); 173 174 // Verify the directory is gone 175 EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK)); 176 EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file)); 177 EXPECT_EQ(NULL_NODE, file.get()); 178 } 179 180 TEST(MountTest, MemMountRemove) { 181 MountMemMock* mnt = new MountMemMock(); 182 ScopedMountNode file; 183 ScopedMountNode result_node; 184 185 EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR)); 186 EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file)); 187 EXPECT_NE(NULL_NODE, file.get()); 188 EXPECT_EQ(3, mnt->num_nodes()); 189 file.reset(); 190 191 EXPECT_EQ(0, mnt->Remove(Path("/dir"))); 192 EXPECT_EQ(2, mnt->num_nodes()); 193 EXPECT_EQ(0, mnt->Remove(Path("/file"))); 194 EXPECT_EQ(1, mnt->num_nodes()); 195 196 EXPECT_EQ(ENOENT, 197 mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node)); 198 EXPECT_EQ(NULL_NODE, result_node.get()); 199 EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node)); 200 EXPECT_EQ(NULL_NODE, result_node.get()); 201 } 202 203 TEST(MountTest, DevAccess) { 204 // Should not be able to open non-existent file. 205 MountDevMock* mnt = new MountDevMock(); 206 ASSERT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK)); 207 } 208 209 TEST(MountTest, DevNull) { 210 MountDevMock* mnt = new MountDevMock(); 211 ScopedMountNode dev_null; 212 int result_bytes = 0; 213 214 ASSERT_EQ(0, mnt->Access(Path("/null"), R_OK | W_OK)); 215 ASSERT_EQ(EACCES, mnt->Access(Path("/null"), X_OK)); 216 ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null)); 217 ASSERT_NE(NULL_NODE, dev_null.get()); 218 219 // Writing to /dev/null should write everything. 220 const char msg[] = "Dummy test message."; 221 EXPECT_EQ(0, dev_null->Write(0, &msg[0], strlen(msg), &result_bytes)); 222 EXPECT_EQ(strlen(msg), result_bytes); 223 224 // Reading from /dev/null should read nothing. 225 const int kBufferLength = 100; 226 char buffer[kBufferLength]; 227 EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength, &result_bytes)); 228 EXPECT_EQ(0, result_bytes); 229 } 230 231 TEST(MountTest, DevZero) { 232 MountDevMock* mnt = new MountDevMock(); 233 ScopedMountNode dev_zero; 234 int result_bytes = 0; 235 236 ASSERT_EQ(0, mnt->Access(Path("/zero"), R_OK | W_OK)); 237 ASSERT_EQ(EACCES, mnt->Access(Path("/zero"), X_OK)); 238 ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero)); 239 ASSERT_NE(NULL_NODE, dev_zero.get()); 240 241 // Writing to /dev/zero should write everything. 242 const char msg[] = "Dummy test message."; 243 EXPECT_EQ(0, dev_zero->Write(0, &msg[0], strlen(msg), &result_bytes)); 244 EXPECT_EQ(strlen(msg), result_bytes); 245 246 // Reading from /dev/zero should read all zeroes. 247 const int kBufferLength = 100; 248 char buffer[kBufferLength]; 249 // First fill with all 1s. 250 memset(&buffer[0], 0x1, kBufferLength); 251 EXPECT_EQ(0, dev_zero->Read(0, &buffer[0], kBufferLength, &result_bytes)); 252 EXPECT_EQ(kBufferLength, result_bytes); 253 254 char zero_buffer[kBufferLength]; 255 memset(&zero_buffer[0], 0, kBufferLength); 256 EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength)); 257 } 258 259 // Disabled due to intermittent failures on linux: http://crbug.com/257257 260 TEST(MountTest, DISABLED_DevUrandom) { 261 MountDevMock* mnt = new MountDevMock(); 262 ScopedMountNode dev_urandom; 263 int result_bytes = 0; 264 265 ASSERT_EQ(0, mnt->Access(Path("/urandom"), R_OK | W_OK)); 266 ASSERT_EQ(EACCES, mnt->Access(Path("/urandom"), X_OK)); 267 ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom)); 268 ASSERT_NE(NULL_NODE, dev_urandom.get()); 269 270 // Writing to /dev/urandom should write everything. 271 const char msg[] = "Dummy test message."; 272 EXPECT_EQ(0, dev_urandom->Write(0, &msg[0], strlen(msg), &result_bytes)); 273 EXPECT_EQ(strlen(msg), result_bytes); 274 275 // Reading from /dev/urandom should read random bytes. 276 const int kSampleBatches = 1000; 277 const int kSampleBatchSize = 1000; 278 const int kTotalSamples = kSampleBatches * kSampleBatchSize; 279 280 int byte_count[256] = {0}; 281 282 unsigned char buffer[kSampleBatchSize]; 283 for (int batch = 0; batch < kSampleBatches; ++batch) { 284 int bytes_read = 0; 285 EXPECT_EQ(0, 286 dev_urandom->Read(0, &buffer[0], kSampleBatchSize, &bytes_read)); 287 EXPECT_EQ(kSampleBatchSize, bytes_read); 288 289 for (int i = 0; i < bytes_read; ++i) { 290 byte_count[buffer[i]]++; 291 } 292 } 293 294 double expected_count = kTotalSamples / 256.; 295 double chi_squared = 0; 296 for (int i = 0; i < 256; ++i) { 297 double difference = byte_count[i] - expected_count; 298 chi_squared += difference * difference / expected_count; 299 } 300 301 // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom. 302 EXPECT_LE(chi_squared, 293.24); 303 } 304 305 306 TEST(MountTest, DevTty) { 307 MountDevMock* mnt = new MountDevMock(); 308 ScopedMountNode dev_tty; 309 310 ASSERT_EQ(0, mnt->Access(Path("/tty"), R_OK | W_OK)); 311 ASSERT_EQ(EACCES, mnt->Access(Path("/tty"), X_OK)); 312 ASSERT_EQ(0, mnt->Open(Path("/tty"), O_RDWR, &dev_tty)); 313 ASSERT_NE(NULL_NODE, dev_tty.get()); 314 315 // 123 is not a valid ioctl request. 316 EXPECT_EQ(EINVAL, dev_tty->Ioctl(123, NULL)); 317 318 // TIOCNACLPREFIX is, it should set the prefix. 319 std::string prefix("__my_awesome_prefix__"); 320 EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLPREFIX, 321 const_cast<char*>(prefix.c_str()))); 322 323 // Now let's try sending some data over. 324 // First we create the message. 325 std::string content("hello, how are you?\n"); 326 std::string message = prefix.append(content); 327 struct tioc_nacl_input_string packaged_message; 328 packaged_message.length = message.size(); 329 packaged_message.buffer = message.data(); 330 331 // Now we make buffer we'll read into. 332 // We fill the buffer and a backup buffer with arbitrary data 333 // and compare them after reading to make sure read doesn't 334 // clobber parts of the buffer it shouldn't. 335 int bytes_read; 336 char buffer[100]; 337 char backup_buffer[100]; 338 memset(buffer, 'a', 100); 339 memset(backup_buffer, 'a', 100); 340 341 // Now we actually send the data 342 EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLINPUT, 343 reinterpret_cast<char*>(&packaged_message))); 344 345 // We read a small chunk first to ensure it doesn't give us 346 // more than we ask for. 347 EXPECT_EQ(0, dev_tty->Read(0, buffer, 5, &bytes_read)); 348 EXPECT_EQ(bytes_read, 5); 349 EXPECT_EQ(0, memcmp(content.data(), buffer, 5)); 350 EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95)); 351 352 // Now we ask for more data than is left in the tty, to ensure 353 // it doesn't give us more than is there. 354 EXPECT_EQ(0, dev_tty->Read(0, buffer + 5, 95, &bytes_read)); 355 EXPECT_EQ(bytes_read, content.size() - 5); 356 EXPECT_EQ(0, memcmp(content.data(), buffer, content.size())); 357 EXPECT_EQ(0, memcmp(buffer + content.size(), 358 backup_buffer + content.size(), 359 100 - content.size())); 360 361 // Now we try to send something with an invalid prefix 362 std::string bogus_message("Woah there, this message has no valid prefix"); 363 struct tioc_nacl_input_string bogus_pack; 364 bogus_pack.length = bogus_message.size(); 365 bogus_pack.buffer = bogus_message.data(); 366 EXPECT_EQ(ENOTTY, dev_tty->Ioctl(TIOCNACLINPUT, 367 reinterpret_cast<char*>(&bogus_pack))); 368 } 369