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
19using namespace nacl_io;
20
21namespace {
22
23class 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
33class 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
46TEST(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
180TEST(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
203TEST(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
209TEST(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
231TEST(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
260TEST(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
306TEST(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