kernel_proxy_test.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 "mount_mock.h" 18#include "mount_node_mock.h" 19 20#include "nacl_io/kernel_intercept.h" 21#include "nacl_io/kernel_proxy.h" 22#include "nacl_io/mount.h" 23#include "nacl_io/mount_mem.h" 24#include "nacl_io/osmman.h" 25#include "nacl_io/path.h" 26#include "nacl_io/typed_mount_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 KernelProxyFriend : public KernelProxy { 43 public: 44 Mount* RootMount() { 45 ScopedMount mnt; 46 Path path; 47 48 AcquireMountAndRelPath("/", &mnt, &path); 49 return mnt.get(); 50 } 51}; 52 53class KernelProxyTest : public ::testing::Test { 54 public: 55 KernelProxyTest() {} 56 57 void SetUp() { 58 ki_init(&kp_); 59 // Unmount the passthrough FS and mount a memfs. 60 EXPECT_EQ(0, kp_.umount("/")); 61 EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL)); 62 } 63 64 void TearDown() { 65 ki_uninit(); 66 } 67 68 protected: 69 KernelProxyFriend kp_; 70}; 71 72} // namespace 73 74static int ki_fcntl_wrapper(int fd, int request, ...) { 75 va_list ap; 76 va_start(ap, request); 77 int rtn = ki_fcntl(fd, request, ap); 78 va_end(ap); 79 return rtn; 80} 81 82/** 83 * Test for fcntl commands F_SETFD and F_GETFD. This 84 * is tested here rather than in the mount_node tests 85 * since the fd flags are not stored in the kernel_handle 86 * or the mount node but directly in the FD mapping. 87 */ 88TEST_F(KernelProxyTest, Fcntl_GETFD) { 89 int fd = ki_open("/test", O_RDWR | O_CREAT); 90 ASSERT_NE(-1, fd); 91 92 // FD flags should start as zero. 93 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD)); 94 95 // Check that setting FD_CLOEXEC works 96 int flags = FD_CLOEXEC; 97 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags)) 98 << "fcntl failed with: " << strerror(errno); 99 ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD)); 100 101 // Check that setting invalid flag causes EINVAL 102 flags = FD_CLOEXEC + 1; 103 ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags)); 104 ASSERT_EQ(EINVAL, errno); 105} 106 107TEST_F(KernelProxyTest, FileLeak) { 108 const size_t buffer_size = 1024; 109 char filename[128]; 110 int garbage[buffer_size]; 111 112 MountMem* mount = (MountMem*)kp_.RootMount(); 113 ScopedMountNode root; 114 115 ASSERT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root)); 116 ASSERT_EQ(0, root->ChildCount()); 117 118 for (int file_num = 0; file_num < 4096; file_num++) { 119 sprintf(filename, "/foo%i.tmp", file_num++); 120 FILE* f = fopen(filename, "w"); 121 ASSERT_NE((FILE*)NULL, f); 122 ASSERT_EQ(1, root->ChildCount()); 123 ASSERT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f)); 124 fclose(f); 125 ASSERT_EQ(0, remove(filename)); 126 } 127 ASSERT_EQ(0, root->ChildCount()); 128} 129 130TEST_F(KernelProxyTest, WorkingDirectory) { 131 char text[1024]; 132 133 text[0] = 0; 134 ki_getcwd(text, sizeof(text)); 135 EXPECT_STREQ("/", text); 136 137 char* alloc = ki_getwd(NULL); 138 EXPECT_EQ((char*)NULL, alloc); 139 EXPECT_EQ(EFAULT, errno); 140 141 text[0] = 0; 142 alloc = ki_getwd(text); 143 EXPECT_STREQ("/", alloc); 144 145 EXPECT_EQ(-1, ki_chdir("/foo")); 146 EXPECT_EQ(ENOENT, errno); 147 148 EXPECT_EQ(0, ki_chdir("/")); 149 150 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 151 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 152 EXPECT_EQ(EEXIST, errno); 153 154 memset(text, 0, sizeof(text)); 155 EXPECT_EQ(0, ki_chdir("foo")); 156 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 157 EXPECT_STREQ("/foo", text); 158 159 memset(text, 0, sizeof(text)); 160 EXPECT_EQ(-1, ki_chdir("foo")); 161 EXPECT_EQ(ENOENT, errno); 162 EXPECT_EQ(0, ki_chdir("..")); 163 EXPECT_EQ(0, ki_chdir("/foo")); 164 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 165 EXPECT_STREQ("/foo", text); 166} 167 168TEST_F(KernelProxyTest, MemMountIO) { 169 char text[1024]; 170 int fd1, fd2, fd3; 171 int len; 172 173 // Fail to delete non existant "/foo" 174 EXPECT_EQ(-1, ki_rmdir("/foo")); 175 EXPECT_EQ(ENOENT, errno); 176 177 // Create "/foo" 178 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 179 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 180 EXPECT_EQ(EEXIST, errno); 181 182 // Delete "/foo" 183 EXPECT_EQ(0, ki_rmdir("/foo")); 184 185 // Recreate "/foo" 186 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 187 188 // Fail to open "/foo/bar" 189 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY)); 190 EXPECT_EQ(ENOENT, errno); 191 192 // Create bar "/foo/bar" 193 fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT); 194 ASSERT_NE(-1, fd1); 195 196 // Open (optionally create) bar "/foo/bar" 197 fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT); 198 ASSERT_NE(-1, fd2); 199 200 // Fail to exclusively create bar "/foo/bar" 201 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL)); 202 EXPECT_EQ(EEXIST, errno); 203 204 // Write hello and world to same node with different descriptors 205 // so that we overwrite each other 206 EXPECT_EQ(5, ki_write(fd2, "WORLD", 5)); 207 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5)); 208 209 fd3 = ki_open("/foo/bar", O_RDONLY); 210 ASSERT_NE(-1, fd3); 211 212 len = ki_read(fd3, text, sizeof(text)); 213 ASSERT_EQ(5, len); 214 text[len] = 0; 215 EXPECT_STREQ("HELLO", text); 216 EXPECT_EQ(0, ki_close(fd1)); 217 EXPECT_EQ(0, ki_close(fd2)); 218 219 fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND); 220 ASSERT_NE(-1, fd1); 221 EXPECT_EQ(5, ki_write(fd1, "WORLD", 5)); 222 223 len = ki_read(fd3, text, sizeof(text)); 224 ASSERT_EQ(5, len); 225 text[len] = 0; 226 EXPECT_STREQ("WORLD", text); 227 228 fd2 = ki_open("/foo/bar", O_RDONLY); 229 ASSERT_NE(-1, fd2); 230 len = ki_read(fd2, text, sizeof(text)); 231 if (len > 0) 232 text[len] = 0; 233 EXPECT_EQ(10, len); 234 EXPECT_STREQ("HELLOWORLD", text); 235} 236 237TEST_F(KernelProxyTest, MemMountLseek) { 238 int fd = ki_open("/foo", O_CREAT | O_RDWR); 239 ASSERT_GT(fd, -1); 240 EXPECT_EQ(9, ki_write(fd, "Some text", 9)); 241 242 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 243 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END)); 244 EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET)); 245 EXPECT_EQ(EINVAL, errno); 246 247 // Seek past end of file. 248 EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET)); 249 char buffer[4]; 250 memset(&buffer[0], 0xfe, 4); 251 EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END)); 252 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 253 EXPECT_EQ(4, ki_read(fd, &buffer[0], 4)); 254 EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4)); 255} 256 257TEST_F(KernelProxyTest, CloseTwice) { 258 int fd = ki_open("/foo", O_CREAT | O_RDWR); 259 ASSERT_GT(fd, -1); 260 261 EXPECT_EQ(9, ki_write(fd, "Some text", 9)); 262 263 int fd2 = ki_dup(fd); 264 ASSERT_GT(fd2, -1); 265 266 EXPECT_EQ(0, ki_close(fd)); 267 EXPECT_EQ(0, ki_close(fd2)); 268} 269 270TEST_F(KernelProxyTest, MemMountDup) { 271 int fd = ki_open("/foo", O_CREAT | O_RDWR); 272 ASSERT_GT(fd, -1); 273 274 int dup_fd = ki_dup(fd); 275 ASSERT_NE(-1, dup_fd); 276 277 ASSERT_EQ(9, ki_write(fd, "Some text", 9)); 278 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 279 ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR)); 280 281 int dup2_fd = 123; 282 ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd)); 283 ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR)); 284 285 int new_fd = ki_open("/bar", O_CREAT | O_RDWR); 286 287 ASSERT_EQ(fd, ki_dup2(new_fd, fd)); 288 // fd, new_fd -> "/bar" 289 // dup_fd, dup2_fd -> "/foo" 290 291 // We should still be able to write to dup_fd (i.e. it should not be closed). 292 ASSERT_EQ(4, ki_write(dup_fd, "more", 4)); 293 294 ASSERT_EQ(0, ki_close(dup2_fd)); 295 // fd, new_fd -> "/bar" 296 // dup_fd -> "/foo" 297 298 ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd)); 299 // fd, new_fd, dup_fd -> "/bar" 300} 301 302namespace { 303 304StringMap_t g_StringMap; 305 306class MountMockInit : public MountMem { 307 public: 308 virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) { 309 g_StringMap = args; 310 if (args.find("false") != args.end()) 311 return EINVAL; 312 return 0; 313 } 314 315 friend class TypedMountFactory<MountMockInit>; 316}; 317 318class KernelProxyMountMock : public KernelProxy { 319 virtual Error Init(PepperInterface* ppapi) { 320 KernelProxy::Init(NULL); 321 factories_["initfs"] = new TypedMountFactory<MountMockInit>; 322 return 0; 323 } 324}; 325 326class KernelProxyMountTest : public ::testing::Test { 327 public: 328 KernelProxyMountTest() {} 329 330 void SetUp() { 331 ki_init(&kp_); 332 } 333 334 void TearDown() { 335 ki_uninit(); 336 } 337 338 private: 339 KernelProxyMountMock kp_; 340}; 341 342} // namespace 343 344TEST_F(KernelProxyMountTest, MountInit) { 345 int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar"); 346 347 EXPECT_EQ("bar", g_StringMap["foo"]); 348 EXPECT_EQ(-1, res1); 349 EXPECT_EQ(EINVAL, errno); 350 351 int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y"); 352 EXPECT_NE(-1, res2); 353 EXPECT_EQ("y", g_StringMap["x"]); 354} 355 356namespace { 357 358int g_MMapCount = 0; 359 360class MountNodeMockMMap : public MountNode { 361 public: 362 MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) { 363 EXPECT_EQ(0, Init(0)); 364 } 365 366 virtual Error MMap(void* addr, 367 size_t length, 368 int prot, 369 int flags, 370 size_t offset, 371 void** out_addr) { 372 node_mmap_count_++; 373 switch (g_MMapCount++) { 374 case 0: 375 *out_addr = reinterpret_cast<void*>(0x1000); 376 break; 377 case 1: 378 *out_addr = reinterpret_cast<void*>(0x2000); 379 break; 380 case 2: 381 *out_addr = reinterpret_cast<void*>(0x3000); 382 break; 383 default: 384 return EPERM; 385 } 386 387 return 0; 388 } 389 390 private: 391 int node_mmap_count_; 392}; 393 394class MountMockMMap : public Mount { 395 public: 396 virtual Error Access(const Path& path, int a_mode) { return 0; } 397 virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) { 398 out_node->reset(new MountNodeMockMMap(this)); 399 return 0; 400 } 401 402 virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) { 403 out_node->reset(NULL); 404 return ENOSYS; 405 } 406 virtual Error Unlink(const Path& path) { return ENOSYS; } 407 virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; } 408 virtual Error Rmdir(const Path& path) { return ENOSYS; } 409 virtual Error Remove(const Path& path) { return ENOSYS; } 410 411 friend class TypedMountFactory<MountMockMMap>; 412}; 413 414class KernelProxyMockMMap : public KernelProxy { 415 virtual Error Init(PepperInterface* ppapi) { 416 KernelProxy::Init(NULL); 417 factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>; 418 return 0; 419 } 420}; 421 422class KernelProxyMMapTest : public ::testing::Test { 423 public: 424 KernelProxyMMapTest() {} 425 426 void SetUp() { 427 ki_init(&kp_); 428 } 429 430 void TearDown() { 431 ki_uninit(); 432 } 433 434 private: 435 KernelProxyMockMMap kp_; 436}; 437 438} // namespace 439 440TEST_F(KernelProxyMMapTest, MMap) { 441 ASSERT_EQ(0, ki_umount("/")); 442 ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL)); 443 int fd = ki_open("/file", O_RDWR | O_CREAT); 444 ASSERT_NE(-1, fd); 445 446 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 447 ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1); 448 ASSERT_EQ(1, g_MMapCount); 449 450 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 451 ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2); 452 ASSERT_EQ(2, g_MMapCount); 453 454 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 455 ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3); 456 ASSERT_EQ(3, g_MMapCount); 457 458 ki_close(fd); 459 460 // We no longer track mmap'd regions, so munmap is a no-op. 461 ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800)); 462 // We don't track regions, so the mmap count hasn't changed. 463 ASSERT_EQ(3, g_MMapCount); 464} 465 466namespace { 467 468class SingletonMountFactory : public MountFactory { 469 public: 470 SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {} 471 472 virtual Error CreateMount(int dev, 473 StringMap_t& args, 474 PepperInterface* ppapi, 475 ScopedMount* out_mount) { 476 *out_mount = mount_; 477 return 0; 478 } 479 480 private: 481 ScopedMount mount_; 482}; 483 484class KernelProxyError : public KernelProxy { 485 public: 486 KernelProxyError() : mnt_(new MountMock) {} 487 488 virtual Error Init(PepperInterface* ppapi) { 489 KernelProxy::Init(ppapi); 490 factories_["testfs"] = new SingletonMountFactory(mnt_); 491 492 EXPECT_CALL(*mnt_, Destroy()).Times(1); 493 return 0; 494 } 495 496 ScopedRef<MountMock> mnt() { return mnt_; } 497 498 private: 499 ScopedRef<MountMock> mnt_; 500}; 501 502class KernelProxyErrorTest : public ::testing::Test { 503 public: 504 KernelProxyErrorTest() {} 505 506 void SetUp() { 507 ki_init(&kp_); 508 // Unmount the passthrough FS and mount a testfs. 509 EXPECT_EQ(0, kp_.umount("/")); 510 EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL)); 511 } 512 513 void TearDown() { 514 ki_uninit(); 515 } 516 517 ScopedRef<MountMock> mnt() { return kp_.mnt(); } 518 519 private: 520 KernelProxyError kp_; 521}; 522 523} // namespace 524 525TEST_F(KernelProxyErrorTest, WriteError) { 526 ScopedRef<MountMock> mock_mnt(mnt()); 527 ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt)); 528 EXPECT_CALL(*mock_mnt, Open(_, _, _)) 529 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0))); 530 531 EXPECT_CALL(*mock_node, Write(_, _, _, _)) 532 .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes. 533 Return(1234))); // Returned error 1234. 534 535 EXPECT_CALL(*mock_node, Destroy()).Times(1); 536 537 int fd = ki_open("/dummy", O_WRONLY); 538 EXPECT_NE(0, fd); 539 540 char buf[20]; 541 EXPECT_EQ(-1, ki_write(fd, &buf[0], 20)); 542 // The Mount should be able to return whatever error it wants and have it 543 // propagate through. 544 EXPECT_EQ(1234, errno); 545} 546 547TEST_F(KernelProxyErrorTest, ReadError) { 548 ScopedRef<MountMock> mock_mnt(mnt()); 549 ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt)); 550 EXPECT_CALL(*mock_mnt, Open(_, _, _)) 551 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0))); 552 553 EXPECT_CALL(*mock_node, Read(_, _, _, _)) 554 .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes. 555 Return(1234))); // Returned error 1234. 556 557 EXPECT_CALL(*mock_node, Destroy()).Times(1); 558 559 int fd = ki_open("/dummy", O_RDONLY); 560 EXPECT_NE(0, fd); 561 562 char buf[20]; 563 EXPECT_EQ(-1, ki_read(fd, &buf[0], 20)); 564 // The Mount should be able to return whatever error it wants and have it 565 // propagate through. 566 EXPECT_EQ(1234, errno); 567} 568 569