kernel_proxy_test.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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, 0777); 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, 0777); 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, 0777); 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, 0); 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, 0); 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, 0777); 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, 0); 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, 0)); 364 EXPECT_EQ(ENOENT, errno); 365 366 // Create bar "/foo/bar" 367 fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT, 0777); 368 ASSERT_NE(-1, fd1); 369 370 // Open (optionally create) bar "/foo/bar" 371 fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT, 0777); 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, 0777)); 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, 0); 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, 0); 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, 0); 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, 0777); 419 ASSERT_NE(-1, fd1); 420 fd2 = ki_open("/trunc", O_RDONLY, 0); 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, 0777); 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, 0); 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, 0777); 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, 0777); 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, 0777); 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, 0777); 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, 0777); 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, OpenWithMode) { 534 int fd = ki_open("/foo", O_CREAT | O_RDWR, 0723); 535 ASSERT_GT(fd, -1); 536 537 struct stat buf; 538 EXPECT_EQ(0, ki_lstat("/foo", &buf)); 539 EXPECT_EQ(0723, buf.st_mode & ~S_IFMT); 540} 541 542TEST_F(KernelProxyTest, UseAfterClose) { 543 int fd = ki_open("/dummy", O_CREAT | O_WRONLY, 0777); 544 ASSERT_GT(fd, -1); 545 EXPECT_EQ(5, ki_write(fd, "hello", 5)); 546 EXPECT_EQ(0, ki_close(fd)); 547 EXPECT_EQ(-1, ki_write(fd, "hello", 5)); 548 EXPECT_EQ(EBADF, errno); 549} 550 551namespace { 552 553StringMap_t g_string_map; 554bool g_fs_ioctl_called; 555int g_fs_dev; 556 557class KernelProxyMountTest_Filesystem : public MemFs { 558 public: 559 virtual Error Init(const FsInitArgs& args) { 560 MemFs::Init(args); 561 562 g_string_map = args.string_map; 563 g_fs_dev = args.dev; 564 565 if (g_string_map.find("false") != g_string_map.end()) 566 return EINVAL; 567 return 0; 568 } 569 570 virtual Error Filesystem_VIoctl(int request, va_list arglist) { 571 g_fs_ioctl_called = true; 572 return 0; 573 } 574 575 friend class TypedFsFactory<KernelProxyMountTest_Filesystem>; 576}; 577 578class KernelProxyMountTest_KernelProxy : public KernelProxy { 579 virtual Error Init(PepperInterface* ppapi) { 580 KernelProxy::Init(NULL); 581 factories_["initfs"] = new TypedFsFactory<KernelProxyMountTest_Filesystem>; 582 return 0; 583 } 584}; 585 586class KernelProxyMountTest : public ::testing::Test { 587 public: 588 KernelProxyMountTest() {} 589 590 void SetUp() { 591 g_string_map.clear(); 592 g_fs_dev = -1; 593 g_fs_ioctl_called = false; 594 595 ASSERT_EQ(0, ki_push_state_for_testing()); 596 ASSERT_EQ(0, ki_init(&kp_)); 597 } 598 599 void TearDown() { 600 g_string_map.clear(); 601 ki_uninit(); 602 } 603 604 protected: 605 KernelProxyMountTest_KernelProxy kp_; 606}; 607 608// Helper function for calling ki_ioctl without having 609// to construct a va_list. 610int ki_ioctl_wrapper(int fd, int request, ...) { 611 va_list ap; 612 va_start(ap, request); 613 int rtn = ki_ioctl(fd, request, ap); 614 va_end(ap); 615 return rtn; 616} 617 618} // namespace 619 620TEST_F(KernelProxyMountTest, MountInit) { 621 int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar"); 622 623 EXPECT_EQ("bar", g_string_map["foo"]); 624 EXPECT_EQ(-1, res1); 625 EXPECT_EQ(EINVAL, errno); 626 627 int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y"); 628 EXPECT_NE(-1, res2); 629 EXPECT_EQ("y", g_string_map["x"]); 630} 631 632TEST_F(KernelProxyMountTest, MountAndIoctl) { 633 ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, "")); 634 ASSERT_NE(-1, g_fs_dev); 635 636 char path[100]; 637 snprintf(path, 100, "dev/fs/%d", g_fs_dev); 638 639 int fd = ki_open(path, O_RDONLY, 0); 640 ASSERT_GT(fd, -1); 641 642 EXPECT_EQ(0, ki_ioctl_wrapper(fd, 0xdeadbeef)); 643 EXPECT_EQ(true, g_fs_ioctl_called); 644} 645 646static void mount_callback(const char* source, 647 const char* target, 648 const char* filesystemtype, 649 unsigned long mountflags, 650 const void* data, 651 dev_t dev, 652 void* user_data) { 653 EXPECT_STREQ("/", source); 654 EXPECT_STREQ("/mnt1", target); 655 EXPECT_STREQ("initfs", filesystemtype); 656 EXPECT_EQ(0, mountflags); 657 EXPECT_STREQ("", (const char*) data); 658 EXPECT_EQ(g_fs_dev, dev); 659 660 bool* callback_called = static_cast<bool*>(user_data); 661 *callback_called = true; 662} 663 664TEST_F(KernelProxyMountTest, MountCallback) { 665 bool callback_called = false; 666 kp_.SetMountCallback(&mount_callback, &callback_called); 667 ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, "")); 668 ASSERT_NE(-1, g_fs_dev); 669 EXPECT_EQ(true, callback_called); 670} 671 672namespace { 673 674int g_MMapCount = 0; 675 676class KernelProxyMMapTest_Node : public Node { 677 public: 678 KernelProxyMMapTest_Node(Filesystem* filesystem) 679 : Node(filesystem), node_mmap_count_(0) { 680 EXPECT_EQ(0, Init(0)); 681 } 682 683 virtual Error MMap(void* addr, 684 size_t length, 685 int prot, 686 int flags, 687 size_t offset, 688 void** out_addr) { 689 node_mmap_count_++; 690 switch (g_MMapCount++) { 691 case 0: 692 *out_addr = reinterpret_cast<void*>(0x1000); 693 break; 694 case 1: 695 *out_addr = reinterpret_cast<void*>(0x2000); 696 break; 697 case 2: 698 *out_addr = reinterpret_cast<void*>(0x3000); 699 break; 700 default: 701 return EPERM; 702 } 703 704 return 0; 705 } 706 707 private: 708 int node_mmap_count_; 709}; 710 711class KernelProxyMMapTest_Filesystem : public Filesystem { 712 public: 713 virtual Error OpenWithMode(const Path& path, int open_flags, 714 mode_t mode, ScopedNode* out_node) { 715 out_node->reset(new KernelProxyMMapTest_Node(this)); 716 return 0; 717 } 718 719 virtual Error OpenResource(const Path& path, ScopedNode* out_node) { 720 out_node->reset(NULL); 721 return ENOSYS; 722 } 723 virtual Error Unlink(const Path& path) { return ENOSYS; } 724 virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; } 725 virtual Error Rmdir(const Path& path) { return ENOSYS; } 726 virtual Error Remove(const Path& path) { return ENOSYS; } 727 virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; } 728 729 friend class TypedFsFactory<KernelProxyMMapTest_Filesystem>; 730}; 731 732class KernelProxyMMapTest_KernelProxy : public KernelProxy { 733 virtual Error Init(PepperInterface* ppapi) { 734 KernelProxy::Init(NULL); 735 factories_["mmapfs"] = new TypedFsFactory<KernelProxyMMapTest_Filesystem>; 736 return 0; 737 } 738}; 739 740class KernelProxyMMapTest : public ::testing::Test { 741 public: 742 KernelProxyMMapTest() {} 743 744 void SetUp() { 745 ASSERT_EQ(0, ki_push_state_for_testing()); 746 ASSERT_EQ(0, ki_init(&kp_)); 747 } 748 749 void TearDown() { ki_uninit(); } 750 751 private: 752 KernelProxyMMapTest_KernelProxy kp_; 753}; 754 755} // namespace 756 757TEST_F(KernelProxyMMapTest, MMap) { 758 ASSERT_EQ(0, ki_umount("/")); 759 ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL)); 760 int fd = ki_open("/file", O_RDWR | O_CREAT, 0777); 761 ASSERT_NE(-1, fd); 762 763 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 764 ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1); 765 ASSERT_EQ(1, g_MMapCount); 766 767 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 768 ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2); 769 ASSERT_EQ(2, g_MMapCount); 770 771 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 772 ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3); 773 ASSERT_EQ(3, g_MMapCount); 774 775 ki_close(fd); 776 777 // We no longer track mmap'd regions, so munmap is a no-op. 778 ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800)); 779 // We don't track regions, so the mmap count hasn't changed. 780 ASSERT_EQ(3, g_MMapCount); 781} 782 783namespace { 784 785class SingletonFsFactory : public FsFactory { 786 public: 787 SingletonFsFactory(const ScopedFilesystem& filesystem) : mount_(filesystem) {} 788 789 virtual Error CreateFilesystem(const FsInitArgs& args, 790 ScopedFilesystem* out_fs) { 791 *out_fs = mount_; 792 return 0; 793 } 794 795 private: 796 ScopedFilesystem mount_; 797}; 798 799class KernelProxyErrorTest_KernelProxy : public KernelProxy { 800 public: 801 KernelProxyErrorTest_KernelProxy() : fs_(new MockFs) {} 802 803 virtual Error Init(PepperInterface* ppapi) { 804 KernelProxy::Init(ppapi); 805 factories_["testfs"] = new SingletonFsFactory(fs_); 806 807 EXPECT_CALL(*fs_, Destroy()).Times(1); 808 return 0; 809 } 810 811 ScopedRef<MockFs> fs() { return fs_; } 812 813 private: 814 ScopedRef<MockFs> fs_; 815}; 816 817class KernelProxyErrorTest : public ::testing::Test { 818 public: 819 KernelProxyErrorTest() {} 820 821 void SetUp() { 822 ASSERT_EQ(0, ki_push_state_for_testing()); 823 ASSERT_EQ(0, ki_init(&kp_)); 824 // Unmount the passthrough FS and mount a testfs. 825 EXPECT_EQ(0, kp_.umount("/")); 826 EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL)); 827 } 828 829 void TearDown() { ki_uninit(); } 830 831 ScopedRef<MockFs> fs() { return kp_.fs(); } 832 833 private: 834 KernelProxyErrorTest_KernelProxy kp_; 835}; 836 837} // namespace 838 839TEST_F(KernelProxyErrorTest, WriteError) { 840 ScopedRef<MockFs> mock_fs(fs()); 841 ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs)); 842 EXPECT_CALL(*mock_fs, OpenWithMode(_, _, _, _)) 843 .WillOnce(DoAll(SetArgPointee<3>(mock_node), Return(0))); 844 845 EXPECT_CALL(*mock_node, Write(_, _, _, _)) 846 .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes. 847 Return(1234))); // Returned error 1234. 848 849 EXPECT_CALL(*mock_node, Destroy()).Times(1); 850 851 int fd = ki_open("/dummy", O_WRONLY, 0); 852 EXPECT_NE(0, fd); 853 854 char buf[20]; 855 EXPECT_EQ(-1, ki_write(fd, &buf[0], 20)); 856 // The Filesystem should be able to return whatever error it wants and have it 857 // propagate through. 858 EXPECT_EQ(1234, errno); 859} 860 861TEST_F(KernelProxyErrorTest, ReadError) { 862 ScopedRef<MockFs> mock_fs(fs()); 863 ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs)); 864 EXPECT_CALL(*mock_fs, OpenWithMode(_, _, _, _)) 865 .WillOnce(DoAll(SetArgPointee<3>(mock_node), Return(0))); 866 867 EXPECT_CALL(*mock_node, Read(_, _, _, _)) 868 .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes. 869 Return(1234))); // Returned error 1234. 870 871 EXPECT_CALL(*mock_node, Destroy()).Times(1); 872 873 int fd = ki_open("/dummy", O_RDONLY, 0); 874 EXPECT_NE(0, fd); 875 876 char buf[20]; 877 EXPECT_EQ(-1, ki_read(fd, &buf[0], 20)); 878 // The Filesystem should be able to return whatever error it wants and have it 879 // propagate through. 880 EXPECT_EQ(1234, errno); 881} 882