kernel_proxy_test.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 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 <pthread.h> 8#include <stdio.h> 9#include <sys/stat.h> 10 11#include <map> 12#include <string> 13 14#include "gmock/gmock.h" 15#include "gtest/gtest.h" 16 17#include "mock_fs.h" 18#include "mock_node.h" 19 20#include "nacl_io/filesystem.h" 21#include "nacl_io/kernel_intercept.h" 22#include "nacl_io/kernel_proxy.h" 23#include "nacl_io/memfs/mem_fs.h" 24#include "nacl_io/osmman.h" 25#include "nacl_io/path.h" 26#include "nacl_io/typed_fs_factory.h" 27 28using namespace nacl_io; 29using namespace sdk_util; 30 31using ::testing::_; 32using ::testing::DoAll; 33using ::testing::Invoke; 34using ::testing::Return; 35using ::testing::SaveArg; 36using ::testing::SetArgPointee; 37using ::testing::StrEq; 38using ::testing::WithArgs; 39 40namespace { 41 42class KernelProxyTest_KernelProxy : public KernelProxy { 43 public: 44 Filesystem* RootFs() { 45 ScopedFilesystem fs; 46 Path path; 47 48 AcquireFsAndRelPath("/", &fs, &path); 49 return fs.get(); 50 } 51}; 52 53class KernelProxyTest : public ::testing::Test { 54 public: 55 KernelProxyTest() {} 56 57 void SetUp() { 58 ASSERT_EQ(0, ki_push_state_for_testing()); 59 ASSERT_EQ(0, ki_init(&kp_)); 60 // Unmount the passthrough FS and mount a memfs. 61 EXPECT_EQ(0, kp_.umount("/")); 62 EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL)); 63 } 64 65 void TearDown() { ki_uninit(); } 66 67 protected: 68 KernelProxyTest_KernelProxy kp_; 69}; 70 71} // namespace 72 73static int ki_fcntl_wrapper(int fd, int request, ...) { 74 va_list ap; 75 va_start(ap, request); 76 int rtn = ki_fcntl(fd, request, ap); 77 va_end(ap); 78 return rtn; 79} 80 81/** 82 * Test for fcntl commands F_SETFD and F_GETFD. This 83 * is tested here rather than in the mount_node tests 84 * since the fd flags are not stored in the kernel_handle 85 * or the filesystem node but directly in the FD mapping. 86 */ 87TEST_F(KernelProxyTest, Fcntl_GETFD) { 88 int fd = ki_open("/test", O_RDWR | O_CREAT); 89 ASSERT_NE(-1, fd); 90 91 // FD flags should start as zero. 92 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD)); 93 94 // Check that setting FD_CLOEXEC works 95 int flags = FD_CLOEXEC; 96 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags)) 97 << "fcntl failed with: " << strerror(errno); 98 ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD)); 99 100 // Check that setting invalid flag causes EINVAL 101 flags = FD_CLOEXEC + 1; 102 ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags)); 103 ASSERT_EQ(EINVAL, errno); 104} 105 106TEST_F(KernelProxyTest, FileLeak) { 107 const size_t buffer_size = 1024; 108 char filename[128]; 109 int garbage[buffer_size]; 110 111 MemFs* filesystem = (MemFs*)kp_.RootFs(); 112 ScopedNode root; 113 114 ASSERT_EQ(0, filesystem->Open(Path("/"), O_RDONLY, &root)); 115 ASSERT_EQ(0, root->ChildCount()); 116 117 for (int file_num = 0; file_num < 4096; file_num++) { 118 sprintf(filename, "/foo%i.tmp", file_num++); 119 int fd = ki_open(filename, O_WRONLY | O_CREAT); 120 ASSERT_GT(fd, -1); 121 ASSERT_EQ(1, root->ChildCount()); 122 ASSERT_EQ(buffer_size, ki_write(fd, garbage, buffer_size)); 123 ki_close(fd); 124 ASSERT_EQ(0, ki_remove(filename)); 125 } 126 ASSERT_EQ(0, root->ChildCount()); 127} 128 129static bool g_handler_called = false; 130static void sighandler(int) { g_handler_called = true; } 131 132TEST_F(KernelProxyTest, Sigaction) { 133 struct sigaction action; 134 struct sigaction oaction; 135 memset(&action, 0, sizeof(action)); 136 137 // Invalid signum 138 ASSERT_EQ(-1, ki_sigaction(-1, NULL, &oaction)); 139 ASSERT_EQ(-1, ki_sigaction(SIGSTOP, NULL, &oaction)); 140 ASSERT_EQ(EINVAL, errno); 141 142 // Get existing handler 143 memset(&oaction, 0, sizeof(oaction)); 144 ASSERT_EQ(0, ki_sigaction(SIGINT, NULL, &oaction)); 145 ASSERT_EQ(SIG_DFL, oaction.sa_handler); 146 147 // Attempt to set handler for unsupported signum 148 action.sa_handler = sighandler; 149 ASSERT_EQ(-1, ki_sigaction(SIGINT, &action, NULL)); 150 ASSERT_EQ(EINVAL, errno); 151 152 // Attempt to set handler for supported signum 153 action.sa_handler = sighandler; 154 ASSERT_EQ(0, ki_sigaction(SIGWINCH, &action, NULL)); 155 156 memset(&oaction, 0, sizeof(oaction)); 157 ASSERT_EQ(0, ki_sigaction(SIGWINCH, NULL, &oaction)); 158 ASSERT_EQ((sighandler_t*)sighandler, (sighandler_t*)oaction.sa_handler); 159} 160 161TEST_F(KernelProxyTest, KillSignals) { 162 // SIGSEGV can't be sent via kill(2) 163 ASSERT_EQ(-1, ki_kill(0, SIGSEGV)) << "kill(SEGV) failed to return an error"; 164 ASSERT_EQ(EINVAL, errno) << "kill(SEGV) failed to set errno to EINVAL"; 165 166 // Our implemenation should understand SIGWINCH 167 ASSERT_EQ(0, ki_kill(0, SIGWINCH)) << "kill(SIGWINCH) failed: " << errno; 168 169 // And USR1/USR2 170 ASSERT_EQ(0, ki_kill(0, SIGUSR1)) << "kill(SIGUSR1) failed: " << errno; 171 ASSERT_EQ(0, ki_kill(0, SIGUSR2)) << "kill(SIGUSR2) failed: " << errno; 172} 173 174TEST_F(KernelProxyTest, KillPIDValues) { 175 // Any PID other than 0, -1 and getpid() should yield ESRCH 176 // since there is only one valid process under NaCl 177 int mypid = getpid(); 178 ASSERT_EQ(0, ki_kill(0, SIGWINCH)); 179 ASSERT_EQ(0, ki_kill(-1, SIGWINCH)); 180 ASSERT_EQ(0, ki_kill(mypid, SIGWINCH)); 181 182 // Don't use mypid + 1 since getpid() actually returns -1 183 // when the IRT interface is missing (e.g. within chrome), 184 // and 0 is always a valid PID when calling kill(). 185 int invalid_pid = mypid + 10; 186 ASSERT_EQ(-1, ki_kill(invalid_pid, SIGWINCH)); 187 ASSERT_EQ(ESRCH, errno); 188} 189 190TEST_F(KernelProxyTest, SignalValues) { 191 ASSERT_EQ(ki_signal(SIGSEGV, sighandler), SIG_ERR) 192 << "registering SEGV handler didn't fail"; 193 ASSERT_EQ(errno, EINVAL) << "signal(SEGV) failed to set errno to EINVAL"; 194 195 ASSERT_EQ(ki_signal(-1, sighandler), SIG_ERR) 196 << "registering handler for invalid signal didn't fail"; 197 ASSERT_EQ(errno, EINVAL) << "signal(-1) failed to set errno to EINVAL"; 198} 199 200TEST_F(KernelProxyTest, SignalHandlerValues) { 201 // Unsupported signal. 202 ASSERT_NE(SIG_ERR, ki_signal(SIGSEGV, SIG_DFL)); 203 ASSERT_EQ(SIG_ERR, ki_signal(SIGSEGV, SIG_IGN)); 204 ASSERT_EQ(SIG_ERR, ki_signal(SIGSEGV, sighandler)); 205 206 // Supported signal. 207 ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, SIG_DFL)); 208 ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, SIG_IGN)); 209 ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, sighandler)); 210} 211 212TEST_F(KernelProxyTest, SignalSigwinch) { 213 g_handler_called = false; 214 215 // Register WINCH handler 216 sighandler_t newsig = sighandler; 217 sighandler_t oldsig = ki_signal(SIGWINCH, newsig); 218 ASSERT_NE(oldsig, SIG_ERR); 219 220 // Send signal. 221 ki_kill(0, SIGWINCH); 222 223 // Verify that handler was called 224 EXPECT_TRUE(g_handler_called); 225 226 // Restore existing handler 227 oldsig = ki_signal(SIGWINCH, oldsig); 228 229 // Verify the our newsig was returned as previous handler 230 ASSERT_EQ(oldsig, newsig); 231} 232 233TEST_F(KernelProxyTest, Rename) { 234 // Create a dummy file 235 int file1 = ki_open("/test1.txt", O_RDWR | O_CREAT); 236 ASSERT_GT(file1, -1); 237 ASSERT_EQ(0, ki_close(file1)); 238 239 // Test the renaming works 240 ASSERT_EQ(0, ki_rename("/test1.txt", "/test2.txt")); 241 242 // Test that renaming across mount points fails 243 ASSERT_EQ(0, ki_mount("", "/foo", "memfs", 0, "")); 244 ASSERT_EQ(-1, ki_rename("/test2.txt", "/foo/test2.txt")); 245 ASSERT_EQ(EXDEV, errno); 246} 247 248TEST_F(KernelProxyTest, WorkingDirectory) { 249 char text[1024]; 250 251 text[0] = 0; 252 ki_getcwd(text, sizeof(text)); 253 EXPECT_STREQ("/", text); 254 255 char* alloc = ki_getwd(NULL); 256 EXPECT_EQ((char*)NULL, alloc); 257 EXPECT_EQ(EFAULT, errno); 258 259 text[0] = 0; 260 alloc = ki_getwd(text); 261 EXPECT_STREQ("/", alloc); 262 263 EXPECT_EQ(-1, ki_chdir("/foo")); 264 EXPECT_EQ(ENOENT, errno); 265 266 EXPECT_EQ(0, ki_chdir("/")); 267 268 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 269 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 270 EXPECT_EQ(EEXIST, errno); 271 272 memset(text, 0, sizeof(text)); 273 EXPECT_EQ(0, ki_chdir("foo")); 274 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 275 EXPECT_STREQ("/foo", text); 276 277 memset(text, 0, sizeof(text)); 278 EXPECT_EQ(-1, ki_chdir("foo")); 279 EXPECT_EQ(ENOENT, errno); 280 EXPECT_EQ(0, ki_chdir("..")); 281 EXPECT_EQ(0, ki_chdir("/foo")); 282 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 283 EXPECT_STREQ("/foo", text); 284} 285 286TEST_F(KernelProxyTest, FDPathMapping) { 287 char text[1024]; 288 289 int fd1, fd2, fd3, fd4, fd5; 290 291 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 292 EXPECT_EQ(0, ki_mkdir("/foo/bar", S_IREAD | S_IWRITE)); 293 EXPECT_EQ(0, ki_mkdir("/example", S_IREAD | S_IWRITE)); 294 ki_chdir("/foo"); 295 296 fd1 = ki_open("/example", O_RDONLY); 297 EXPECT_NE(-1, fd1); 298 EXPECT_EQ(ki_fchdir(fd1), 0); 299 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 300 EXPECT_STREQ("/example", text); 301 302 EXPECT_EQ(0, ki_chdir("/foo")); 303 fd2 = ki_open("../example", O_RDONLY); 304 EXPECT_NE(-1, fd2); 305 EXPECT_EQ(0, ki_fchdir(fd2)); 306 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 307 EXPECT_STREQ("/example", text); 308 309 EXPECT_EQ(0, ki_chdir("/foo")); 310 fd3 = ki_open("../test", O_CREAT | O_RDWR); 311 EXPECT_NE(-1, fd3); 312 EXPECT_EQ(-1, ki_fchdir(fd3)); 313 EXPECT_EQ(ENOTDIR, errno); 314 315 EXPECT_EQ(0, ki_chdir("/foo")); 316 fd4 = ki_open("bar", O_RDONLY); 317 EXPECT_EQ(0, ki_fchdir(fd4)); 318 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 319 EXPECT_STREQ("/foo/bar", text); 320 EXPECT_EQ(0, ki_chdir("/example")); 321 EXPECT_EQ(0, ki_fchdir(fd4)); 322 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 323 EXPECT_STREQ("/foo/bar", text); 324 325 EXPECT_EQ(0, ki_chdir("/example")); 326 fd5 = ki_dup(fd4); 327 ASSERT_GT(fd5, -1); 328 ASSERT_NE(fd4, fd5); 329 EXPECT_EQ(0, ki_fchdir(fd5)); 330 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 331 EXPECT_STREQ("/foo/bar", text); 332 333 fd5 = 123; 334 335 EXPECT_EQ(0, ki_chdir("/example")); 336 EXPECT_EQ(fd5, ki_dup2(fd4, fd5)); 337 EXPECT_EQ(0, ki_fchdir(fd5)); 338 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 339 EXPECT_STREQ("/foo/bar", text); 340} 341 342TEST_F(KernelProxyTest, MemMountIO) { 343 char text[1024]; 344 int fd1, fd2, fd3; 345 int len; 346 347 // Fail to delete non existant "/foo" 348 EXPECT_EQ(-1, ki_rmdir("/foo")); 349 EXPECT_EQ(ENOENT, errno); 350 351 // Create "/foo" 352 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 353 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 354 EXPECT_EQ(EEXIST, errno); 355 356 // Delete "/foo" 357 EXPECT_EQ(0, ki_rmdir("/foo")); 358 359 // Recreate "/foo" 360 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 361 362 // Fail to open "/foo/bar" 363 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY)); 364 EXPECT_EQ(ENOENT, errno); 365 366 // Create bar "/foo/bar" 367 fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT); 368 ASSERT_NE(-1, fd1); 369 370 // Open (optionally create) bar "/foo/bar" 371 fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT); 372 ASSERT_NE(-1, fd2); 373 374 // Fail to exclusively create bar "/foo/bar" 375 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL)); 376 EXPECT_EQ(EEXIST, errno); 377 378 // Write hello and world to same node with different descriptors 379 // so that we overwrite each other 380 EXPECT_EQ(5, ki_write(fd2, "WORLD", 5)); 381 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5)); 382 383 fd3 = ki_open("/foo/bar", O_RDONLY); 384 ASSERT_NE(-1, fd3); 385 386 len = ki_read(fd3, text, sizeof(text)); 387 ASSERT_EQ(5, len); 388 text[len] = 0; 389 EXPECT_STREQ("HELLO", text); 390 EXPECT_EQ(0, ki_close(fd1)); 391 EXPECT_EQ(0, ki_close(fd2)); 392 393 fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND); 394 ASSERT_NE(-1, fd1); 395 EXPECT_EQ(5, ki_write(fd1, "WORLD", 5)); 396 397 len = ki_read(fd3, text, sizeof(text)); 398 ASSERT_EQ(5, len); 399 text[len] = 0; 400 EXPECT_STREQ("WORLD", text); 401 402 fd2 = ki_open("/foo/bar", O_RDONLY); 403 ASSERT_NE(-1, fd2); 404 len = ki_read(fd2, text, sizeof(text)); 405 if (len > 0) 406 text[len] = 0; 407 EXPECT_EQ(10, len); 408 EXPECT_STREQ("HELLOWORLD", text); 409} 410 411TEST_F(KernelProxyTest, MemMountFTruncate) { 412 char text[1024]; 413 int fd1, fd2; 414 415 // Open a file write only, write some text, then test that using a 416 // separate file descriptor pointing to it that it is correctly 417 // truncated at a specified number of bytes (2). 418 fd1 = ki_open("/trunc", O_WRONLY | O_CREAT); 419 ASSERT_NE(-1, fd1); 420 fd2 = ki_open("/trunc", O_RDONLY); 421 ASSERT_NE(-1, fd2); 422 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5)); 423 EXPECT_EQ(0, ki_ftruncate(fd1, 2)); 424 // Verify the remaining file (using fd2, opened pre-truncation) is 425 // only 2 bytes in length. 426 EXPECT_EQ(2, ki_read(fd2, text, sizeof(text))); 427 EXPECT_EQ(0, ki_close(fd1)); 428 EXPECT_EQ(0, ki_close(fd2)); 429} 430 431TEST_F(KernelProxyTest, MemMountTruncate) { 432 char text[1024]; 433 int fd1; 434 435 // Open a file write only, write some text, then test that by 436 // referring to it by its path and truncating it we correctly truncate 437 // it at a specified number of bytes (2). 438 fd1 = ki_open("/trunc", O_WRONLY | O_CREAT); 439 ASSERT_NE(-1, fd1); 440 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5)); 441 EXPECT_EQ(0, ki_close(fd1)); 442 EXPECT_EQ(0, ki_truncate("/trunc", 2)); 443 // Verify the text is only 2 bytes long with new file descriptor. 444 fd1 = ki_open("/trunc", O_RDONLY); 445 ASSERT_NE(-1, fd1); 446 EXPECT_EQ(2, ki_read(fd1, text, sizeof(text))); 447 EXPECT_EQ(0, ki_close(fd1)); 448} 449 450TEST_F(KernelProxyTest, MemMountLseek) { 451 int fd = ki_open("/foo", O_CREAT | O_RDWR); 452 ASSERT_GT(fd, -1); 453 ASSERT_EQ(9, ki_write(fd, "Some text", 9)); 454 455 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 456 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_END)); 457 ASSERT_EQ(-1, ki_lseek(fd, -1, SEEK_SET)); 458 ASSERT_EQ(EINVAL, errno); 459 460 // Seek past end of file. 461 ASSERT_EQ(13, ki_lseek(fd, 13, SEEK_SET)); 462 char buffer[4]; 463 memset(&buffer[0], 0xfe, 4); 464 ASSERT_EQ(9, ki_lseek(fd, -4, SEEK_END)); 465 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 466 ASSERT_EQ(4, ki_read(fd, &buffer[0], 4)); 467 ASSERT_EQ(0, memcmp("\0\0\0\0", buffer, 4)); 468} 469 470TEST_F(KernelProxyTest, CloseTwice) { 471 int fd = ki_open("/foo", O_CREAT | O_RDWR); 472 ASSERT_GT(fd, -1); 473 474 EXPECT_EQ(9, ki_write(fd, "Some text", 9)); 475 476 int fd2 = ki_dup(fd); 477 ASSERT_GT(fd2, -1); 478 479 EXPECT_EQ(0, ki_close(fd)); 480 EXPECT_EQ(0, ki_close(fd2)); 481} 482 483TEST_F(KernelProxyTest, MemMountDup) { 484 int fd = ki_open("/foo", O_CREAT | O_RDWR); 485 ASSERT_GT(fd, -1); 486 487 int dup_fd = ki_dup(fd); 488 ASSERT_NE(-1, dup_fd); 489 490 ASSERT_EQ(9, ki_write(fd, "Some text", 9)); 491 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 492 ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR)); 493 494 int dup2_fd = 123; 495 ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd)); 496 ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR)); 497 498 int new_fd = ki_open("/bar", O_CREAT | O_RDWR); 499 500 ASSERT_EQ(fd, ki_dup2(new_fd, fd)); 501 // fd, new_fd -> "/bar" 502 // dup_fd, dup2_fd -> "/foo" 503 504 // We should still be able to write to dup_fd (i.e. it should not be closed). 505 ASSERT_EQ(4, ki_write(dup_fd, "more", 4)); 506 507 ASSERT_EQ(0, ki_close(dup2_fd)); 508 // fd, new_fd -> "/bar" 509 // dup_fd -> "/foo" 510 511 ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd)); 512 // fd, new_fd, dup_fd -> "/bar" 513} 514 515TEST_F(KernelProxyTest, Lstat) { 516 int fd = ki_open("/foo", O_CREAT | O_RDWR); 517 ASSERT_GT(fd, -1); 518 ASSERT_EQ(0, ki_mkdir("/bar", S_IREAD | S_IWRITE)); 519 520 struct stat buf; 521 EXPECT_EQ(0, ki_lstat("/foo", &buf)); 522 EXPECT_EQ(0, buf.st_size); 523 EXPECT_TRUE(S_ISREG(buf.st_mode)); 524 525 EXPECT_EQ(0, ki_lstat("/bar", &buf)); 526 EXPECT_EQ(0, buf.st_size); 527 EXPECT_TRUE(S_ISDIR(buf.st_mode)); 528 529 EXPECT_EQ(-1, ki_lstat("/no-such-file", &buf)); 530 EXPECT_EQ(ENOENT, errno); 531} 532 533TEST_F(KernelProxyTest, UseAfterClose) { 534 int fd = ki_open("/dummy", O_CREAT | O_WRONLY); 535 ASSERT_GT(fd, -1); 536 EXPECT_EQ(5, ki_write(fd, "hello", 5)); 537 EXPECT_EQ(0, ki_close(fd)); 538 EXPECT_EQ(-1, ki_write(fd, "hello", 5)); 539 EXPECT_EQ(EBADF, errno); 540} 541 542namespace { 543 544StringMap_t g_string_map; 545bool g_fs_ioctl_called; 546int g_fs_dev; 547 548class KernelProxyMountTest_Filesystem : public MemFs { 549 public: 550 virtual Error Init(const FsInitArgs& args) { 551 MemFs::Init(args); 552 553 g_string_map = args.string_map; 554 g_fs_dev = args.dev; 555 556 if (g_string_map.find("false") != g_string_map.end()) 557 return EINVAL; 558 return 0; 559 } 560 561 virtual Error Filesystem_VIoctl(int request, va_list arglist) { 562 g_fs_ioctl_called = true; 563 return 0; 564 } 565 566 friend class TypedFsFactory<KernelProxyMountTest_Filesystem>; 567}; 568 569class KernelProxyMountTest_KernelProxy : public KernelProxy { 570 virtual Error Init(PepperInterface* ppapi) { 571 KernelProxy::Init(NULL); 572 factories_["initfs"] = new TypedFsFactory<KernelProxyMountTest_Filesystem>; 573 return 0; 574 } 575}; 576 577class KernelProxyMountTest : public ::testing::Test { 578 public: 579 KernelProxyMountTest() {} 580 581 void SetUp() { 582 g_string_map.clear(); 583 g_fs_dev = -1; 584 g_fs_ioctl_called = false; 585 586 ASSERT_EQ(0, ki_push_state_for_testing()); 587 ASSERT_EQ(0, ki_init(&kp_)); 588 } 589 590 void TearDown() { 591 g_string_map.clear(); 592 ki_uninit(); 593 } 594 595 private: 596 KernelProxyMountTest_KernelProxy kp_; 597}; 598 599// Helper function for calling ki_ioctl without having 600// to construct a va_list. 601int ki_ioctl_wrapper(int fd, int request, ...) { 602 va_list ap; 603 va_start(ap, request); 604 int rtn = ki_ioctl(fd, request, ap); 605 va_end(ap); 606 return rtn; 607} 608 609} // namespace 610 611TEST_F(KernelProxyMountTest, MountInit) { 612 int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar"); 613 614 EXPECT_EQ("bar", g_string_map["foo"]); 615 EXPECT_EQ(-1, res1); 616 EXPECT_EQ(EINVAL, errno); 617 618 int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y"); 619 EXPECT_NE(-1, res2); 620 EXPECT_EQ("y", g_string_map["x"]); 621} 622 623TEST_F(KernelProxyMountTest, MountAndIoctl) { 624 ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, "")); 625 ASSERT_NE(-1, g_fs_dev); 626 627 char path[100]; 628 snprintf(path, 100, "dev/fs/%d", g_fs_dev); 629 630 int fd = ki_open(path, O_RDONLY); 631 ASSERT_GT(fd, -1); 632 633 EXPECT_EQ(0, ki_ioctl_wrapper(fd, 0xdeadbeef)); 634 EXPECT_EQ(true, g_fs_ioctl_called); 635} 636 637namespace { 638 639int g_MMapCount = 0; 640 641class KernelProxyMMapTest_Node : public Node { 642 public: 643 KernelProxyMMapTest_Node(Filesystem* filesystem) 644 : Node(filesystem), node_mmap_count_(0) { 645 EXPECT_EQ(0, Init(0)); 646 } 647 648 virtual Error MMap(void* addr, 649 size_t length, 650 int prot, 651 int flags, 652 size_t offset, 653 void** out_addr) { 654 node_mmap_count_++; 655 switch (g_MMapCount++) { 656 case 0: 657 *out_addr = reinterpret_cast<void*>(0x1000); 658 break; 659 case 1: 660 *out_addr = reinterpret_cast<void*>(0x2000); 661 break; 662 case 2: 663 *out_addr = reinterpret_cast<void*>(0x3000); 664 break; 665 default: 666 return EPERM; 667 } 668 669 return 0; 670 } 671 672 private: 673 int node_mmap_count_; 674}; 675 676class KernelProxyMMapTest_Filesystem : public Filesystem { 677 public: 678 virtual Error Access(const Path& path, int a_mode) { return 0; } 679 virtual Error Open(const Path& path, int mode, ScopedNode* out_node) { 680 out_node->reset(new KernelProxyMMapTest_Node(this)); 681 return 0; 682 } 683 684 virtual Error OpenResource(const Path& path, ScopedNode* out_node) { 685 out_node->reset(NULL); 686 return ENOSYS; 687 } 688 virtual Error Unlink(const Path& path) { return ENOSYS; } 689 virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; } 690 virtual Error Rmdir(const Path& path) { return ENOSYS; } 691 virtual Error Remove(const Path& path) { return ENOSYS; } 692 virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; } 693 694 friend class TypedFsFactory<KernelProxyMMapTest_Filesystem>; 695}; 696 697class KernelProxyMMapTest_KernelProxy : public KernelProxy { 698 virtual Error Init(PepperInterface* ppapi) { 699 KernelProxy::Init(NULL); 700 factories_["mmapfs"] = new TypedFsFactory<KernelProxyMMapTest_Filesystem>; 701 return 0; 702 } 703}; 704 705class KernelProxyMMapTest : public ::testing::Test { 706 public: 707 KernelProxyMMapTest() {} 708 709 void SetUp() { 710 ASSERT_EQ(0, ki_push_state_for_testing()); 711 ASSERT_EQ(0, ki_init(&kp_)); 712 } 713 714 void TearDown() { ki_uninit(); } 715 716 private: 717 KernelProxyMMapTest_KernelProxy kp_; 718}; 719 720} // namespace 721 722TEST_F(KernelProxyMMapTest, MMap) { 723 ASSERT_EQ(0, ki_umount("/")); 724 ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL)); 725 int fd = ki_open("/file", O_RDWR | O_CREAT); 726 ASSERT_NE(-1, fd); 727 728 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 729 ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1); 730 ASSERT_EQ(1, g_MMapCount); 731 732 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 733 ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2); 734 ASSERT_EQ(2, g_MMapCount); 735 736 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 737 ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3); 738 ASSERT_EQ(3, g_MMapCount); 739 740 ki_close(fd); 741 742 // We no longer track mmap'd regions, so munmap is a no-op. 743 ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800)); 744 // We don't track regions, so the mmap count hasn't changed. 745 ASSERT_EQ(3, g_MMapCount); 746} 747 748namespace { 749 750class SingletonFsFactory : public FsFactory { 751 public: 752 SingletonFsFactory(const ScopedFilesystem& filesystem) : mount_(filesystem) {} 753 754 virtual Error CreateFilesystem(const FsInitArgs& args, 755 ScopedFilesystem* out_fs) { 756 *out_fs = mount_; 757 return 0; 758 } 759 760 private: 761 ScopedFilesystem mount_; 762}; 763 764class KernelProxyErrorTest_KernelProxy : public KernelProxy { 765 public: 766 KernelProxyErrorTest_KernelProxy() : fs_(new MockFs) {} 767 768 virtual Error Init(PepperInterface* ppapi) { 769 KernelProxy::Init(ppapi); 770 factories_["testfs"] = new SingletonFsFactory(fs_); 771 772 EXPECT_CALL(*fs_, Destroy()).Times(1); 773 return 0; 774 } 775 776 ScopedRef<MockFs> fs() { return fs_; } 777 778 private: 779 ScopedRef<MockFs> fs_; 780}; 781 782class KernelProxyErrorTest : public ::testing::Test { 783 public: 784 KernelProxyErrorTest() {} 785 786 void SetUp() { 787 ASSERT_EQ(0, ki_push_state_for_testing()); 788 ASSERT_EQ(0, ki_init(&kp_)); 789 // Unmount the passthrough FS and mount a testfs. 790 EXPECT_EQ(0, kp_.umount("/")); 791 EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL)); 792 } 793 794 void TearDown() { ki_uninit(); } 795 796 ScopedRef<MockFs> fs() { return kp_.fs(); } 797 798 private: 799 KernelProxyErrorTest_KernelProxy kp_; 800}; 801 802} // namespace 803 804TEST_F(KernelProxyErrorTest, WriteError) { 805 ScopedRef<MockFs> mock_fs(fs()); 806 ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs)); 807 EXPECT_CALL(*mock_fs, Open(_, _, _)) 808 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0))); 809 810 EXPECT_CALL(*mock_node, Write(_, _, _, _)) 811 .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes. 812 Return(1234))); // Returned error 1234. 813 814 EXPECT_CALL(*mock_node, Destroy()).Times(1); 815 816 int fd = ki_open("/dummy", O_WRONLY); 817 EXPECT_NE(0, fd); 818 819 char buf[20]; 820 EXPECT_EQ(-1, ki_write(fd, &buf[0], 20)); 821 // The Filesystem should be able to return whatever error it wants and have it 822 // propagate through. 823 EXPECT_EQ(1234, errno); 824} 825 826TEST_F(KernelProxyErrorTest, ReadError) { 827 ScopedRef<MockFs> mock_fs(fs()); 828 ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs)); 829 EXPECT_CALL(*mock_fs, Open(_, _, _)) 830 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0))); 831 832 EXPECT_CALL(*mock_node, Read(_, _, _, _)) 833 .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes. 834 Return(1234))); // Returned error 1234. 835 836 EXPECT_CALL(*mock_node, Destroy()).Times(1); 837 838 int fd = ki_open("/dummy", O_RDONLY); 839 EXPECT_NE(0, fd); 840 841 char buf[20]; 842 EXPECT_EQ(-1, ki_read(fd, &buf[0], 20)); 843 // The Filesystem should be able to return whatever error it wants and have it 844 // propagate through. 845 EXPECT_EQ(1234, errno); 846} 847