Home | History | Annotate | Download | only in nacl_io_test
      1 // Copyright (c) 2013 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 <string.h>
      8 #include <sys/stat.h>
      9 #include <string>
     10 
     11 #include "gtest/gtest.h"
     12 #include "nacl_io/ioctl.h"
     13 #include "nacl_io/mount.h"
     14 #include "nacl_io/mount_dev.h"
     15 #include "nacl_io/mount_mem.h"
     16 #include "nacl_io/osdirent.h"
     17 #include "nacl_io/osunistd.h"
     18 
     19 using namespace nacl_io;
     20 
     21 namespace {
     22 
     23 class MountMemMock : public MountMem {
     24  public:
     25   MountMemMock() {
     26     StringMap_t map;
     27     EXPECT_EQ(0, Init(1, map, NULL));
     28   }
     29 
     30   int num_nodes() { return (int) inode_pool_.size(); }
     31 };
     32 
     33 class MountDevMock : public MountDev {
     34  public:
     35   MountDevMock() {
     36     StringMap_t map;
     37     Init(1, map, NULL);
     38   }
     39   int num_nodes() { return (int) inode_pool_.size(); }
     40 };
     41 
     42 }  // namespace
     43 
     44 #define NULL_NODE ((MountNode*) NULL)
     45 
     46 TEST(MountTest, Sanity) {
     47   MountMemMock* mnt = new MountMemMock();
     48 
     49   ScopedMountNode file;
     50   ScopedMountNode root;
     51   ScopedMountNode result_node;
     52 
     53   size_t result_size = 0;
     54   int result_bytes = 0;
     55   char buf1[1024];
     56 
     57   // A memory mount starts with one directory node: the root.
     58   EXPECT_EQ(1, mnt->num_nodes());
     59 
     60   // Fail to open non existent file
     61   EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), R_OK | W_OK));
     62   EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node));
     63   EXPECT_EQ(NULL, result_node.get());
     64   EXPECT_EQ(1, mnt->num_nodes());
     65 
     66   // Create a file
     67   EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file));
     68   EXPECT_NE(NULL_NODE, file.get());
     69   if (file == NULL)
     70     return;
     71 
     72   // We now have a directory and a file.  The file has a two references
     73   // one returned to the test, one for the name->inode map.
     74   EXPECT_EQ(2, mnt->num_nodes());
     75   EXPECT_EQ(2, file->RefCount());
     76   EXPECT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK));
     77   EXPECT_EQ(EACCES, mnt->Access(Path("/foo"), X_OK));
     78 
     79   // Write access should be allowed on the root directory.
     80   EXPECT_EQ(0, mnt->Access(Path("/"), R_OK | W_OK));
     81   EXPECT_EQ(EACCES, mnt->Access(Path("/"), X_OK));
     82   // Open the root directory for write should fail.
     83   EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root));
     84   EXPECT_EQ(2, mnt->num_nodes());
     85 
     86   // Open the root directory, should not create a new file
     87   EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
     88   EXPECT_EQ(2, mnt->num_nodes());
     89   EXPECT_NE(NULL_NODE, root.get());
     90   if (NULL != root) {
     91     struct dirent dirs[2];
     92     int len;
     93     EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
     94     EXPECT_EQ(sizeof(struct dirent), len);
     95   }
     96 
     97   // Fail to re-create the same file
     98   EXPECT_EQ(EEXIST,
     99             mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
    100   EXPECT_EQ(NULL_NODE, result_node.get());
    101   EXPECT_EQ(2, mnt->num_nodes());
    102 
    103   // Fail to create a directory with the same name
    104   EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR));
    105   EXPECT_EQ(2, mnt->num_nodes());
    106 
    107   // Attempt to READ/WRITE
    108   EXPECT_EQ(0, file->GetSize(&result_size));
    109   EXPECT_EQ(0, result_size);
    110   EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
    111   EXPECT_EQ(sizeof(buf1), result_bytes);
    112   EXPECT_EQ(0, file->GetSize(&result_size));
    113   EXPECT_EQ(sizeof(buf1), result_size);
    114   EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
    115   EXPECT_EQ(sizeof(buf1), result_bytes);
    116   EXPECT_EQ(2, mnt->num_nodes());
    117   EXPECT_EQ(2, file->RefCount());
    118 
    119   // Attempt to open the same file, create another ref to it, but does not
    120   // create a new file.
    121   EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
    122   EXPECT_EQ(3, file->RefCount());
    123   EXPECT_EQ(2, mnt->num_nodes());
    124   EXPECT_EQ(file.get(), result_node.get());
    125   EXPECT_EQ(0, file->GetSize(&result_size));
    126   EXPECT_EQ(sizeof(buf1), result_size);
    127 
    128   // Remove our references so that only the Mount holds it
    129   file.reset();
    130   result_node.reset();
    131   EXPECT_EQ(2, mnt->num_nodes());
    132 
    133   // This should have deleted the object
    134   EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
    135   EXPECT_EQ(1, mnt->num_nodes());
    136 
    137   // We should fail to find it
    138   EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo")));
    139   EXPECT_EQ(1, mnt->num_nodes());
    140 
    141   // Recreate foo as a directory
    142   EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
    143   EXPECT_EQ(2, mnt->num_nodes());
    144 
    145   // Create a file (exclusively)
    146   EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
    147   EXPECT_NE(NULL_NODE, file.get());
    148   if (NULL == file)
    149     return;
    150   EXPECT_EQ(2, file->RefCount());
    151   EXPECT_EQ(3, mnt->num_nodes());
    152 
    153   // Attempt to delete the directory and fail
    154   EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo")));
    155   EXPECT_EQ(2, root->RefCount());
    156   EXPECT_EQ(2, file->RefCount());
    157   EXPECT_EQ(3, mnt->num_nodes());
    158 
    159   // Unlink the file, we should have the only file ref at this point.
    160   EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
    161   EXPECT_EQ(2, root->RefCount());
    162   EXPECT_EQ(1, file->RefCount());
    163   EXPECT_EQ(3, mnt->num_nodes());
    164 
    165 
    166   // Deref the file, to make it go away
    167   file.reset();
    168   EXPECT_EQ(2, mnt->num_nodes());
    169 
    170   // Deref the directory
    171   EXPECT_EQ(0, mnt->Rmdir(Path("/foo")));
    172   EXPECT_EQ(1, mnt->num_nodes());
    173 
    174   // Verify the directory is gone
    175   EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
    176   EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file));
    177   EXPECT_EQ(NULL_NODE, file.get());
    178 }
    179 
    180 TEST(MountTest, MemMountRemove) {
    181   MountMemMock* mnt = new MountMemMock();
    182   ScopedMountNode file;
    183   ScopedMountNode result_node;
    184 
    185   EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
    186   EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
    187   EXPECT_NE(NULL_NODE, file.get());
    188   EXPECT_EQ(3, mnt->num_nodes());
    189   file.reset();
    190 
    191   EXPECT_EQ(0, mnt->Remove(Path("/dir")));
    192   EXPECT_EQ(2, mnt->num_nodes());
    193   EXPECT_EQ(0, mnt->Remove(Path("/file")));
    194   EXPECT_EQ(1, mnt->num_nodes());
    195 
    196   EXPECT_EQ(ENOENT,
    197             mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
    198   EXPECT_EQ(NULL_NODE, result_node.get());
    199   EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node));
    200   EXPECT_EQ(NULL_NODE, result_node.get());
    201 }
    202 
    203 TEST(MountTest, DevAccess) {
    204   // Should not be able to open non-existent file.
    205   MountDevMock* mnt = new MountDevMock();
    206   ASSERT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
    207 }
    208 
    209 TEST(MountTest, DevNull) {
    210   MountDevMock* mnt = new MountDevMock();
    211   ScopedMountNode dev_null;
    212   int result_bytes = 0;
    213 
    214   ASSERT_EQ(0, mnt->Access(Path("/null"), R_OK | W_OK));
    215   ASSERT_EQ(EACCES, mnt->Access(Path("/null"), X_OK));
    216   ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null));
    217   ASSERT_NE(NULL_NODE, dev_null.get());
    218 
    219   // Writing to /dev/null should write everything.
    220   const char msg[] = "Dummy test message.";
    221   EXPECT_EQ(0, dev_null->Write(0, &msg[0], strlen(msg), &result_bytes));
    222   EXPECT_EQ(strlen(msg), result_bytes);
    223 
    224   // Reading from /dev/null should read nothing.
    225   const int kBufferLength = 100;
    226   char buffer[kBufferLength];
    227   EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength, &result_bytes));
    228   EXPECT_EQ(0, result_bytes);
    229 }
    230 
    231 TEST(MountTest, DevZero) {
    232   MountDevMock* mnt = new MountDevMock();
    233   ScopedMountNode dev_zero;
    234   int result_bytes = 0;
    235 
    236   ASSERT_EQ(0, mnt->Access(Path("/zero"), R_OK | W_OK));
    237   ASSERT_EQ(EACCES, mnt->Access(Path("/zero"), X_OK));
    238   ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero));
    239   ASSERT_NE(NULL_NODE, dev_zero.get());
    240 
    241   // Writing to /dev/zero should write everything.
    242   const char msg[] = "Dummy test message.";
    243   EXPECT_EQ(0, dev_zero->Write(0, &msg[0], strlen(msg), &result_bytes));
    244   EXPECT_EQ(strlen(msg), result_bytes);
    245 
    246   // Reading from /dev/zero should read all zeroes.
    247   const int kBufferLength = 100;
    248   char buffer[kBufferLength];
    249   // First fill with all 1s.
    250   memset(&buffer[0], 0x1, kBufferLength);
    251   EXPECT_EQ(0, dev_zero->Read(0, &buffer[0], kBufferLength, &result_bytes));
    252   EXPECT_EQ(kBufferLength, result_bytes);
    253 
    254   char zero_buffer[kBufferLength];
    255   memset(&zero_buffer[0], 0, kBufferLength);
    256   EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
    257 }
    258 
    259 // Disabled due to intermittent failures on linux: http://crbug.com/257257
    260 TEST(MountTest, DISABLED_DevUrandom) {
    261   MountDevMock* mnt = new MountDevMock();
    262   ScopedMountNode dev_urandom;
    263   int result_bytes = 0;
    264 
    265   ASSERT_EQ(0, mnt->Access(Path("/urandom"), R_OK | W_OK));
    266   ASSERT_EQ(EACCES, mnt->Access(Path("/urandom"), X_OK));
    267   ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom));
    268   ASSERT_NE(NULL_NODE, dev_urandom.get());
    269 
    270   // Writing to /dev/urandom should write everything.
    271   const char msg[] = "Dummy test message.";
    272   EXPECT_EQ(0, dev_urandom->Write(0, &msg[0], strlen(msg), &result_bytes));
    273   EXPECT_EQ(strlen(msg), result_bytes);
    274 
    275   // Reading from /dev/urandom should read random bytes.
    276   const int kSampleBatches = 1000;
    277   const int kSampleBatchSize = 1000;
    278   const int kTotalSamples = kSampleBatches * kSampleBatchSize;
    279 
    280   int byte_count[256] = {0};
    281 
    282   unsigned char buffer[kSampleBatchSize];
    283   for (int batch = 0; batch < kSampleBatches; ++batch) {
    284     int bytes_read = 0;
    285     EXPECT_EQ(0,
    286               dev_urandom->Read(0, &buffer[0], kSampleBatchSize, &bytes_read));
    287     EXPECT_EQ(kSampleBatchSize, bytes_read);
    288 
    289     for (int i = 0; i < bytes_read; ++i) {
    290       byte_count[buffer[i]]++;
    291     }
    292   }
    293 
    294   double expected_count = kTotalSamples / 256.;
    295   double chi_squared = 0;
    296   for (int i = 0; i < 256; ++i) {
    297     double difference = byte_count[i] - expected_count;
    298     chi_squared += difference * difference / expected_count;
    299   }
    300 
    301   // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
    302   EXPECT_LE(chi_squared, 293.24);
    303 }
    304 
    305 
    306 TEST(MountTest, DevTty) {
    307   MountDevMock* mnt = new MountDevMock();
    308   ScopedMountNode dev_tty;
    309 
    310   ASSERT_EQ(0, mnt->Access(Path("/tty"), R_OK | W_OK));
    311   ASSERT_EQ(EACCES, mnt->Access(Path("/tty"), X_OK));
    312   ASSERT_EQ(0, mnt->Open(Path("/tty"), O_RDWR, &dev_tty));
    313   ASSERT_NE(NULL_NODE, dev_tty.get());
    314 
    315   // 123 is not a valid ioctl request.
    316   EXPECT_EQ(EINVAL, dev_tty->Ioctl(123, NULL));
    317 
    318   // TIOCNACLPREFIX is, it should set the prefix.
    319   std::string prefix("__my_awesome_prefix__");
    320   EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLPREFIX,
    321                               const_cast<char*>(prefix.c_str())));
    322 
    323   // Now let's try sending some data over.
    324   // First we create the message.
    325   std::string content("hello, how are you?\n");
    326   std::string message = prefix.append(content);
    327   struct tioc_nacl_input_string packaged_message;
    328   packaged_message.length = message.size();
    329   packaged_message.buffer = message.data();
    330 
    331   // Now we make buffer we'll read into.
    332   // We fill the buffer and a backup buffer with arbitrary data
    333   // and compare them after reading to make sure read doesn't
    334   // clobber parts of the buffer it shouldn't.
    335   int bytes_read;
    336   char buffer[100];
    337   char backup_buffer[100];
    338   memset(buffer, 'a', 100);
    339   memset(backup_buffer, 'a', 100);
    340 
    341   // Now we actually send the data
    342   EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLINPUT,
    343                               reinterpret_cast<char*>(&packaged_message)));
    344 
    345   // We read a small chunk first to ensure it doesn't give us
    346   // more than we ask for.
    347   EXPECT_EQ(0, dev_tty->Read(0, buffer, 5, &bytes_read));
    348   EXPECT_EQ(bytes_read, 5);
    349   EXPECT_EQ(0, memcmp(content.data(), buffer, 5));
    350   EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
    351 
    352   // Now we ask for more data than is left in the tty, to ensure
    353   // it doesn't give us more than is there.
    354   EXPECT_EQ(0, dev_tty->Read(0, buffer + 5, 95, &bytes_read));
    355   EXPECT_EQ(bytes_read, content.size() - 5);
    356   EXPECT_EQ(0, memcmp(content.data(), buffer, content.size()));
    357   EXPECT_EQ(0, memcmp(buffer + content.size(),
    358                       backup_buffer + content.size(),
    359                        100 - content.size()));
    360 
    361   // Now we try to send something with an invalid prefix
    362   std::string bogus_message("Woah there, this message has no valid prefix");
    363   struct tioc_nacl_input_string bogus_pack;
    364   bogus_pack.length = bogus_message.size();
    365   bogus_pack.buffer = bogus_message.data();
    366   EXPECT_EQ(ENOTTY, dev_tty->Ioctl(TIOCNACLINPUT,
    367                                    reinterpret_cast<char*>(&bogus_pack)));
    368 }
    369