Home | History | Annotate | Download | only in nacl_io_test
      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 
     28 using namespace nacl_io;
     29 using namespace sdk_util;
     30 
     31 using ::testing::_;
     32 using ::testing::DoAll;
     33 using ::testing::Invoke;
     34 using ::testing::Return;
     35 using ::testing::SaveArg;
     36 using ::testing::SetArgPointee;
     37 using ::testing::StrEq;
     38 using ::testing::WithArgs;
     39 
     40 namespace {
     41 
     42 class 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 
     53 class KernelProxyTest : public ::testing::Test {
     54  public:
     55   KernelProxyTest() : kp_(new KernelProxyFriend) {
     56     ki_init(kp_);
     57     // Unmount the passthrough FS and mount a memfs.
     58     EXPECT_EQ(0, kp_->umount("/"));
     59     EXPECT_EQ(0, kp_->mount("", "/", "memfs", 0, NULL));
     60   }
     61 
     62   ~KernelProxyTest() {
     63     ki_uninit();
     64     delete kp_;
     65   }
     66 
     67  protected:
     68   KernelProxyFriend* kp_;
     69 };
     70 
     71 }  // namespace
     72 
     73 TEST_F(KernelProxyTest, FileLeak) {
     74   const size_t buffer_size = 1024;
     75   char filename[128];
     76   int file_num;
     77   int garbage[buffer_size];
     78 
     79   MountMem* mount = (MountMem*)kp_->RootMount();
     80   ScopedMountNode root;
     81 
     82   EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
     83   EXPECT_EQ(0, root->ChildCount());
     84 
     85   for (file_num = 0; file_num < 4096; file_num++) {
     86     sprintf(filename, "/foo%i.tmp", file_num++);
     87     FILE* f = fopen(filename, "w");
     88     EXPECT_NE((FILE*)0, f);
     89     EXPECT_EQ(1, root->ChildCount());
     90     EXPECT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
     91     fclose(f);
     92     EXPECT_EQ(0, remove(filename));
     93   }
     94   EXPECT_EQ(0, root->ChildCount());
     95 }
     96 
     97 TEST_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 
    135 TEST_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_RDONLY | O_CREAT);
    161   EXPECT_NE(-1, fd1);
    162 
    163   // Open (optionally create) bar "/foo/bar"
    164   fd2 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
    165   EXPECT_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_WRONLY);
    177   EXPECT_NE(-1, fd3);
    178 
    179   len = ki_read(fd3, text, sizeof(text));
    180   if (len > 0)
    181     text[len] = 0;
    182   EXPECT_EQ(5, len);
    183   EXPECT_STREQ("HELLO", text);
    184   EXPECT_EQ(0, ki_close(fd1));
    185   EXPECT_EQ(0, ki_close(fd2));
    186 
    187   fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
    188   EXPECT_NE(-1, fd1);
    189   EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
    190 
    191   len = ki_read(fd3, text, sizeof(text));
    192   if (len >= 0)
    193     text[len] = 0;
    194 
    195   EXPECT_EQ(5, len);
    196   EXPECT_STREQ("WORLD", text);
    197 
    198   fd2 = ki_open("/foo/bar", O_RDONLY);
    199   EXPECT_NE(-1, fd2);
    200   len = ki_read(fd2, text, sizeof(text));
    201   if (len > 0)
    202     text[len] = 0;
    203   EXPECT_EQ(10, len);
    204   EXPECT_STREQ("HELLOWORLD", text);
    205 }
    206 
    207 TEST_F(KernelProxyTest, MemMountLseek) {
    208   int fd = ki_open("/foo", O_CREAT | O_RDWR);
    209   EXPECT_EQ(9, ki_write(fd, "Some text", 9));
    210 
    211   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
    212   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
    213   EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
    214   EXPECT_EQ(EINVAL, errno);
    215 
    216   // Seek past end of file.
    217   EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
    218   char buffer[4];
    219   memset(&buffer[0], 0xfe, 4);
    220   EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
    221   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
    222   EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
    223   EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
    224 }
    225 
    226 TEST_F(KernelProxyTest, CloseTwice) {
    227   int fd = ki_open("/foo", O_CREAT | O_RDWR);
    228   EXPECT_EQ(9, ki_write(fd, "Some text", 9));
    229 
    230   int fd2 = ki_dup(fd);
    231   EXPECT_NE(-1, fd2);
    232 
    233   EXPECT_EQ(0, ki_close(fd));
    234   EXPECT_EQ(0, ki_close(fd2));
    235 }
    236 
    237 TEST_F(KernelProxyTest, MemMountDup) {
    238   int fd = ki_open("/foo", O_CREAT | O_RDWR);
    239 
    240   int dup_fd = ki_dup(fd);
    241   EXPECT_NE(-1, dup_fd);
    242 
    243   EXPECT_EQ(9, ki_write(fd, "Some text", 9));
    244   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
    245   EXPECT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
    246 
    247   int dup2_fd = 123;
    248   EXPECT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
    249   EXPECT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
    250 
    251   int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
    252 
    253   EXPECT_EQ(fd, ki_dup2(new_fd, fd));
    254   // fd, new_fd -> "/bar"
    255   // dup_fd, dup2_fd -> "/foo"
    256 
    257   // We should still be able to write to dup_fd (i.e. it should not be closed).
    258   EXPECT_EQ(4, ki_write(dup_fd, "more", 4));
    259 
    260   EXPECT_EQ(0, ki_close(dup2_fd));
    261   // fd, new_fd -> "/bar"
    262   // dup_fd -> "/foo"
    263 
    264   EXPECT_EQ(dup_fd, ki_dup2(fd, dup_fd));
    265   // fd, new_fd, dup_fd -> "/bar"
    266 }
    267 
    268 namespace {
    269 
    270 StringMap_t g_StringMap;
    271 
    272 class MountMockInit : public MountMem {
    273  public:
    274   virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
    275     g_StringMap = args;
    276     if (args.find("false") != args.end())
    277       return EINVAL;
    278     return 0;
    279   }
    280 
    281   friend class TypedMountFactory<MountMockInit>;
    282 };
    283 
    284 class KernelProxyMountMock : public KernelProxy {
    285   virtual void Init(PepperInterface* ppapi) {
    286     KernelProxy::Init(NULL);
    287     factories_["initfs"] = new TypedMountFactory<MountMockInit>;
    288   }
    289 };
    290 
    291 class KernelProxyMountTest : public ::testing::Test {
    292  public:
    293   KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); }
    294 
    295   ~KernelProxyMountTest() {
    296     ki_uninit();
    297     delete kp_;
    298   }
    299 
    300  private:
    301   KernelProxy* kp_;
    302 };
    303 
    304 }  // namespace
    305 
    306 TEST_F(KernelProxyMountTest, MountInit) {
    307   int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
    308 
    309   EXPECT_EQ("bar", g_StringMap["foo"]);
    310   EXPECT_EQ(-1, res1);
    311   EXPECT_EQ(EINVAL, errno);
    312 
    313   int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
    314   EXPECT_NE(-1, res2);
    315   EXPECT_EQ("y", g_StringMap["x"]);
    316 }
    317 
    318 namespace {
    319 
    320 int g_MMapCount = 0;
    321 
    322 class MountNodeMockMMap : public MountNode {
    323  public:
    324   MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
    325     EXPECT_EQ(0, Init(0));
    326   }
    327 
    328   virtual Error MMap(void* addr,
    329                      size_t length,
    330                      int prot,
    331                      int flags,
    332                      size_t offset,
    333                      void** out_addr) {
    334     node_mmap_count_++;
    335     switch (g_MMapCount++) {
    336       case 0:
    337         *out_addr = reinterpret_cast<void*>(0x1000);
    338         break;
    339       case 1:
    340         *out_addr = reinterpret_cast<void*>(0x2000);
    341         break;
    342       case 2:
    343         *out_addr = reinterpret_cast<void*>(0x3000);
    344         break;
    345       default:
    346         return EPERM;
    347     }
    348 
    349     return 0;
    350   }
    351 
    352  private:
    353   int node_mmap_count_;
    354 };
    355 
    356 class MountMockMMap : public Mount {
    357  public:
    358   virtual Error Access(const Path& path, int a_mode) { return 0; }
    359   virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
    360     out_node->reset(new MountNodeMockMMap(this));
    361     return 0;
    362   }
    363 
    364   virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
    365     out_node->reset(NULL);
    366     return ENOSYS;
    367   }
    368   virtual Error Unlink(const Path& path) { return ENOSYS; }
    369   virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
    370   virtual Error Rmdir(const Path& path) { return ENOSYS; }
    371   virtual Error Remove(const Path& path) { return ENOSYS; }
    372 
    373   friend class TypedMountFactory<MountMockMMap>;
    374 };
    375 
    376 class KernelProxyMockMMap : public KernelProxy {
    377   virtual void Init(PepperInterface* ppapi) {
    378     KernelProxy::Init(NULL);
    379     factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
    380   }
    381 };
    382 
    383 class KernelProxyMMapTest : public ::testing::Test {
    384  public:
    385   KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); }
    386 
    387   ~KernelProxyMMapTest() {
    388     ki_uninit();
    389     delete kp_;
    390   }
    391 
    392  private:
    393   KernelProxy* kp_;
    394 };
    395 
    396 }  // namespace
    397 
    398 TEST_F(KernelProxyMMapTest, MMap) {
    399   EXPECT_EQ(0, ki_umount("/"));
    400   EXPECT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
    401   int fd = ki_open("/file", O_RDWR | O_CREAT);
    402   EXPECT_NE(-1, fd);
    403 
    404   void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    405   EXPECT_EQ(reinterpret_cast<void*>(0x1000), addr1);
    406   EXPECT_EQ(1, g_MMapCount);
    407 
    408   void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    409   EXPECT_EQ(reinterpret_cast<void*>(0x2000), addr2);
    410   EXPECT_EQ(2, g_MMapCount);
    411 
    412   void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    413   EXPECT_EQ(reinterpret_cast<void*>(0x3000), addr3);
    414   EXPECT_EQ(3, g_MMapCount);
    415 
    416   ki_close(fd);
    417 
    418   // We no longer track mmap'd regions, so munmap is a no-op.
    419   EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
    420   // We don't track regions, so the mmap count hasn't changed.
    421   EXPECT_EQ(3, g_MMapCount);
    422 }
    423 
    424 namespace {
    425 
    426 class SingletonMountFactory : public MountFactory {
    427  public:
    428   SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
    429 
    430   virtual Error CreateMount(int dev,
    431                             StringMap_t& args,
    432                             PepperInterface* ppapi,
    433                             ScopedMount* out_mount) {
    434     *out_mount = mount_;
    435     return 0;
    436   }
    437 
    438  private:
    439   ScopedMount mount_;
    440 };
    441 
    442 class KernelProxyError : public KernelProxy {
    443  public:
    444   KernelProxyError() : mnt_(new MountMock) {}
    445 
    446   virtual void Init(PepperInterface* ppapi) {
    447     KernelProxy::Init(ppapi);
    448     factories_["testfs"] = new SingletonMountFactory(mnt_);
    449 
    450     EXPECT_CALL(*mnt_, Destroy()).Times(1);
    451   }
    452 
    453   ScopedRef<MountMock> mnt() { return mnt_; }
    454 
    455  private:
    456   ScopedRef<MountMock> mnt_;
    457 };
    458 
    459 class KernelProxyErrorTest : public ::testing::Test {
    460  public:
    461   KernelProxyErrorTest() : kp_(new KernelProxyError) {
    462     ki_init(kp_);
    463     // Unmount the passthrough FS and mount a testfs.
    464     EXPECT_EQ(0, kp_->umount("/"));
    465     EXPECT_EQ(0, kp_->mount("", "/", "testfs", 0, NULL));
    466   }
    467 
    468   ~KernelProxyErrorTest() {
    469     ki_uninit();
    470     delete kp_;
    471   }
    472 
    473   ScopedRef<MountMock> mnt() { return kp_->mnt(); }
    474 
    475  private:
    476   KernelProxyError* kp_;
    477 };
    478 
    479 }  // namespace
    480 
    481 TEST_F(KernelProxyErrorTest, WriteError) {
    482   ScopedRef<MountMock> mock_mnt(mnt());
    483   ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
    484   EXPECT_CALL(*mock_mnt, Open(_, _, _))
    485       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
    486 
    487   EXPECT_CALL(*mock_node, Write(_, _, _, _))
    488       .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
    489                       Return(1234)));       // Returned error 1234.
    490 
    491   EXPECT_CALL(*mock_node, Destroy()).Times(1);
    492 
    493   int fd = ki_open("/dummy", O_WRONLY);
    494   EXPECT_NE(0, fd);
    495 
    496   char buf[20];
    497   EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
    498   // The Mount should be able to return whatever error it wants and have it
    499   // propagate through.
    500   EXPECT_EQ(1234, errno);
    501 }
    502 
    503 TEST_F(KernelProxyErrorTest, ReadError) {
    504   ScopedRef<MountMock> mock_mnt(mnt());
    505   ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
    506   EXPECT_CALL(*mock_mnt, Open(_, _, _))
    507       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
    508 
    509   EXPECT_CALL(*mock_node, Read(_, _, _, _))
    510       .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
    511                       Return(1234)));       // Returned error 1234.
    512 
    513   EXPECT_CALL(*mock_node, Destroy()).Times(1);
    514 
    515   int fd = ki_open("/dummy", O_RDONLY);
    516   EXPECT_NE(0, fd);
    517 
    518   char buf[20];
    519   EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
    520   // The Mount should be able to return whatever error it wants and have it
    521   // propagate through.
    522   EXPECT_EQ(1234, errno);
    523 }
    524 
    525