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