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