kernel_proxy_test.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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 file_num; 78 int garbage[buffer_size]; 79 80 MountMem* mount = (MountMem*)kp_.RootMount(); 81 ScopedMountNode root; 82 83 EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root)); 84 EXPECT_EQ(0, root->ChildCount()); 85 86 for (file_num = 0; file_num < 4096; file_num++) { 87 sprintf(filename, "/foo%i.tmp", file_num++); 88 FILE* f = fopen(filename, "w"); 89 EXPECT_NE((FILE*)0, f); 90 EXPECT_EQ(1, root->ChildCount()); 91 EXPECT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f)); 92 fclose(f); 93 EXPECT_EQ(0, remove(filename)); 94 } 95 EXPECT_EQ(0, root->ChildCount()); 96} 97 98TEST_F(KernelProxyTest, WorkingDirectory) { 99 char text[1024]; 100 101 text[0] = 0; 102 ki_getcwd(text, sizeof(text)); 103 EXPECT_STREQ("/", text); 104 105 char* alloc = ki_getwd(NULL); 106 EXPECT_EQ((char*)NULL, alloc); 107 EXPECT_EQ(EFAULT, errno); 108 109 text[0] = 0; 110 alloc = ki_getwd(text); 111 EXPECT_STREQ("/", alloc); 112 113 EXPECT_EQ(-1, ki_chdir("/foo")); 114 EXPECT_EQ(ENOENT, errno); 115 116 EXPECT_EQ(0, ki_chdir("/")); 117 118 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 119 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 120 EXPECT_EQ(EEXIST, errno); 121 122 memset(text, 0, sizeof(text)); 123 EXPECT_EQ(0, ki_chdir("foo")); 124 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 125 EXPECT_STREQ("/foo", text); 126 127 memset(text, 0, sizeof(text)); 128 EXPECT_EQ(-1, ki_chdir("foo")); 129 EXPECT_EQ(ENOENT, errno); 130 EXPECT_EQ(0, ki_chdir("..")); 131 EXPECT_EQ(0, ki_chdir("/foo")); 132 EXPECT_EQ(text, ki_getcwd(text, sizeof(text))); 133 EXPECT_STREQ("/foo", text); 134} 135 136TEST_F(KernelProxyTest, MemMountIO) { 137 char text[1024]; 138 int fd1, fd2, fd3; 139 int len; 140 141 // Fail to delete non existant "/foo" 142 EXPECT_EQ(-1, ki_rmdir("/foo")); 143 EXPECT_EQ(ENOENT, errno); 144 145 // Create "/foo" 146 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 147 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 148 EXPECT_EQ(EEXIST, errno); 149 150 // Delete "/foo" 151 EXPECT_EQ(0, ki_rmdir("/foo")); 152 153 // Recreate "/foo" 154 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); 155 156 // Fail to open "/foo/bar" 157 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY)); 158 EXPECT_EQ(ENOENT, errno); 159 160 // Create bar "/foo/bar" 161 fd1 = ki_open("/foo/bar", O_RDONLY | O_CREAT); 162 EXPECT_NE(-1, fd1); 163 164 // Open (optionally create) bar "/foo/bar" 165 fd2 = ki_open("/foo/bar", O_RDONLY | O_CREAT); 166 EXPECT_NE(-1, fd2); 167 168 // Fail to exclusively create bar "/foo/bar" 169 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL)); 170 EXPECT_EQ(EEXIST, errno); 171 172 // Write hello and world to same node with different descriptors 173 // so that we overwrite each other 174 EXPECT_EQ(5, ki_write(fd2, "WORLD", 5)); 175 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5)); 176 177 fd3 = ki_open("/foo/bar", O_WRONLY); 178 EXPECT_NE(-1, fd3); 179 180 len = ki_read(fd3, text, sizeof(text)); 181 if (len > 0) 182 text[len] = 0; 183 EXPECT_EQ(5, len); 184 EXPECT_STREQ("HELLO", text); 185 EXPECT_EQ(0, ki_close(fd1)); 186 EXPECT_EQ(0, ki_close(fd2)); 187 188 fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND); 189 EXPECT_NE(-1, fd1); 190 EXPECT_EQ(5, ki_write(fd1, "WORLD", 5)); 191 192 len = ki_read(fd3, text, sizeof(text)); 193 if (len >= 0) 194 text[len] = 0; 195 196 EXPECT_EQ(5, len); 197 EXPECT_STREQ("WORLD", text); 198 199 fd2 = ki_open("/foo/bar", O_RDONLY); 200 EXPECT_NE(-1, fd2); 201 len = ki_read(fd2, text, sizeof(text)); 202 if (len > 0) 203 text[len] = 0; 204 EXPECT_EQ(10, len); 205 EXPECT_STREQ("HELLOWORLD", text); 206} 207 208TEST_F(KernelProxyTest, MemMountLseek) { 209 int fd = ki_open("/foo", O_CREAT | O_RDWR); 210 EXPECT_EQ(9, ki_write(fd, "Some text", 9)); 211 212 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 213 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END)); 214 EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET)); 215 EXPECT_EQ(EINVAL, errno); 216 217 // Seek past end of file. 218 EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET)); 219 char buffer[4]; 220 memset(&buffer[0], 0xfe, 4); 221 EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END)); 222 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 223 EXPECT_EQ(4, ki_read(fd, &buffer[0], 4)); 224 EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4)); 225} 226 227TEST_F(KernelProxyTest, CloseTwice) { 228 int fd = ki_open("/foo", O_CREAT | O_RDWR); 229 EXPECT_EQ(9, ki_write(fd, "Some text", 9)); 230 231 int fd2 = ki_dup(fd); 232 EXPECT_NE(-1, fd2); 233 234 EXPECT_EQ(0, ki_close(fd)); 235 EXPECT_EQ(0, ki_close(fd2)); 236} 237 238TEST_F(KernelProxyTest, MemMountDup) { 239 int fd = ki_open("/foo", O_CREAT | O_RDWR); 240 241 int dup_fd = ki_dup(fd); 242 EXPECT_NE(-1, dup_fd); 243 244 EXPECT_EQ(9, ki_write(fd, "Some text", 9)); 245 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); 246 EXPECT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR)); 247 248 int dup2_fd = 123; 249 EXPECT_EQ(dup2_fd, ki_dup2(fd, dup2_fd)); 250 EXPECT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR)); 251 252 int new_fd = ki_open("/bar", O_CREAT | O_RDWR); 253 254 EXPECT_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 EXPECT_EQ(4, ki_write(dup_fd, "more", 4)); 260 261 EXPECT_EQ(0, ki_close(dup2_fd)); 262 // fd, new_fd -> "/bar" 263 // dup_fd -> "/foo" 264 265 EXPECT_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 EXPECT_EQ(0, ki_umount("/")); 409 EXPECT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL)); 410 int fd = ki_open("/file", O_RDWR | O_CREAT); 411 EXPECT_NE(-1, fd); 412 413 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 414 EXPECT_EQ(reinterpret_cast<void*>(0x1000), addr1); 415 EXPECT_EQ(1, g_MMapCount); 416 417 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 418 EXPECT_EQ(reinterpret_cast<void*>(0x2000), addr2); 419 EXPECT_EQ(2, g_MMapCount); 420 421 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0); 422 EXPECT_EQ(reinterpret_cast<void*>(0x3000), addr3); 423 EXPECT_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 EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800)); 429 // We don't track regions, so the mmap count hasn't changed. 430 EXPECT_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