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