kernel_proxy_test.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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
74static int ki_fcntl_wrapper(int fd, int request, ...) {
75  va_list ap;
76  va_start(ap, request);
77  int rtn = ki_fcntl(fd, request, ap);
78  va_end(ap);
79  return rtn;
80}
81
82/**
83 * Test for fcntl commands F_SETFD and F_GETFD.  This
84 * is tested here rather than in the mount_node tests
85 * since the fd flags are not stored in the kernel_handle
86 * or the mount node but directly in the FD mapping.
87 */
88TEST_F(KernelProxyTest, Fcntl_GETFD) {
89  int fd = ki_open("/test", O_RDWR | O_CREAT);
90  ASSERT_NE(-1, fd);
91
92  // FD flags should start as zero.
93  ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
94
95  // Check that setting FD_CLOEXEC works
96  int flags = FD_CLOEXEC;
97  ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
98    << "fcntl failed with: " << strerror(errno);
99  ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
100
101  // Check that setting invalid flag causes EINVAL
102  flags = FD_CLOEXEC + 1;
103  ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
104  ASSERT_EQ(EINVAL, errno);
105}
106
107TEST_F(KernelProxyTest, FileLeak) {
108  const size_t buffer_size = 1024;
109  char filename[128];
110  int garbage[buffer_size];
111
112  MountMem* mount = (MountMem*)kp_.RootMount();
113  ScopedMountNode root;
114
115  ASSERT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
116  ASSERT_EQ(0, root->ChildCount());
117
118  for (int file_num = 0; file_num < 4096; file_num++) {
119    sprintf(filename, "/foo%i.tmp", file_num++);
120    FILE* f = fopen(filename, "w");
121    ASSERT_NE((FILE*)NULL, f);
122    ASSERT_EQ(1, root->ChildCount());
123    ASSERT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
124    fclose(f);
125    ASSERT_EQ(0, remove(filename));
126  }
127  ASSERT_EQ(0, root->ChildCount());
128}
129
130TEST_F(KernelProxyTest, WorkingDirectory) {
131  char text[1024];
132
133  text[0] = 0;
134  ki_getcwd(text, sizeof(text));
135  EXPECT_STREQ("/", text);
136
137  char* alloc = ki_getwd(NULL);
138  EXPECT_EQ((char*)NULL, alloc);
139  EXPECT_EQ(EFAULT, errno);
140
141  text[0] = 0;
142  alloc = ki_getwd(text);
143  EXPECT_STREQ("/", alloc);
144
145  EXPECT_EQ(-1, ki_chdir("/foo"));
146  EXPECT_EQ(ENOENT, errno);
147
148  EXPECT_EQ(0, ki_chdir("/"));
149
150  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
151  EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
152  EXPECT_EQ(EEXIST, errno);
153
154  memset(text, 0, sizeof(text));
155  EXPECT_EQ(0, ki_chdir("foo"));
156  EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
157  EXPECT_STREQ("/foo", text);
158
159  memset(text, 0, sizeof(text));
160  EXPECT_EQ(-1, ki_chdir("foo"));
161  EXPECT_EQ(ENOENT, errno);
162  EXPECT_EQ(0, ki_chdir(".."));
163  EXPECT_EQ(0, ki_chdir("/foo"));
164  EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
165  EXPECT_STREQ("/foo", text);
166}
167
168TEST_F(KernelProxyTest, MemMountIO) {
169  char text[1024];
170  int fd1, fd2, fd3;
171  int len;
172
173  // Fail to delete non existant "/foo"
174  EXPECT_EQ(-1, ki_rmdir("/foo"));
175  EXPECT_EQ(ENOENT, errno);
176
177  // Create "/foo"
178  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
179  EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
180  EXPECT_EQ(EEXIST, errno);
181
182  // Delete "/foo"
183  EXPECT_EQ(0, ki_rmdir("/foo"));
184
185  // Recreate "/foo"
186  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
187
188  // Fail to open "/foo/bar"
189  EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
190  EXPECT_EQ(ENOENT, errno);
191
192  // Create bar "/foo/bar"
193  fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT);
194  ASSERT_NE(-1, fd1);
195
196  // Open (optionally create) bar "/foo/bar"
197  fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT);
198  ASSERT_NE(-1, fd2);
199
200  // Fail to exclusively create bar "/foo/bar"
201  EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
202  EXPECT_EQ(EEXIST, errno);
203
204  // Write hello and world to same node with different descriptors
205  // so that we overwrite each other
206  EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
207  EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
208
209  fd3 = ki_open("/foo/bar", O_RDONLY);
210  ASSERT_NE(-1, fd3);
211
212  len = ki_read(fd3, text, sizeof(text));
213  ASSERT_EQ(5, len);
214  text[len] = 0;
215  EXPECT_STREQ("HELLO", text);
216  EXPECT_EQ(0, ki_close(fd1));
217  EXPECT_EQ(0, ki_close(fd2));
218
219  fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
220  ASSERT_NE(-1, fd1);
221  EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
222
223  len = ki_read(fd3, text, sizeof(text));
224  ASSERT_EQ(5, len);
225  text[len] = 0;
226  EXPECT_STREQ("WORLD", text);
227
228  fd2 = ki_open("/foo/bar", O_RDONLY);
229  ASSERT_NE(-1, fd2);
230  len = ki_read(fd2, text, sizeof(text));
231  if (len > 0)
232    text[len] = 0;
233  EXPECT_EQ(10, len);
234  EXPECT_STREQ("HELLOWORLD", text);
235}
236
237TEST_F(KernelProxyTest, MemMountLseek) {
238  int fd = ki_open("/foo", O_CREAT | O_RDWR);
239  ASSERT_GT(fd, -1);
240  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
241
242  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
243  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
244  EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
245  EXPECT_EQ(EINVAL, errno);
246
247  // Seek past end of file.
248  EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
249  char buffer[4];
250  memset(&buffer[0], 0xfe, 4);
251  EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
252  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
253  EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
254  EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
255}
256
257TEST_F(KernelProxyTest, CloseTwice) {
258  int fd = ki_open("/foo", O_CREAT | O_RDWR);
259  ASSERT_GT(fd, -1);
260
261  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
262
263  int fd2 = ki_dup(fd);
264  ASSERT_GT(fd2, -1);
265
266  EXPECT_EQ(0, ki_close(fd));
267  EXPECT_EQ(0, ki_close(fd2));
268}
269
270TEST_F(KernelProxyTest, MemMountDup) {
271  int fd = ki_open("/foo", O_CREAT | O_RDWR);
272  ASSERT_GT(fd, -1);
273
274  int dup_fd = ki_dup(fd);
275  ASSERT_NE(-1, dup_fd);
276
277  ASSERT_EQ(9, ki_write(fd, "Some text", 9));
278  ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
279  ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
280
281  int dup2_fd = 123;
282  ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
283  ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
284
285  int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
286
287  ASSERT_EQ(fd, ki_dup2(new_fd, fd));
288  // fd, new_fd -> "/bar"
289  // dup_fd, dup2_fd -> "/foo"
290
291  // We should still be able to write to dup_fd (i.e. it should not be closed).
292  ASSERT_EQ(4, ki_write(dup_fd, "more", 4));
293
294  ASSERT_EQ(0, ki_close(dup2_fd));
295  // fd, new_fd -> "/bar"
296  // dup_fd -> "/foo"
297
298  ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd));
299  // fd, new_fd, dup_fd -> "/bar"
300}
301
302namespace {
303
304StringMap_t g_StringMap;
305
306class MountMockInit : public MountMem {
307 public:
308  virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
309    g_StringMap = args;
310    if (args.find("false") != args.end())
311      return EINVAL;
312    return 0;
313  }
314
315  friend class TypedMountFactory<MountMockInit>;
316};
317
318class KernelProxyMountMock : public KernelProxy {
319  virtual Error Init(PepperInterface* ppapi) {
320    KernelProxy::Init(NULL);
321    factories_["initfs"] = new TypedMountFactory<MountMockInit>;
322    return 0;
323  }
324};
325
326class KernelProxyMountTest : public ::testing::Test {
327 public:
328  KernelProxyMountTest() {}
329
330  void SetUp() {
331    ki_init(&kp_);
332  }
333
334  void TearDown() {
335    ki_uninit();
336  }
337
338 private:
339  KernelProxyMountMock kp_;
340};
341
342}  // namespace
343
344TEST_F(KernelProxyMountTest, MountInit) {
345  int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
346
347  EXPECT_EQ("bar", g_StringMap["foo"]);
348  EXPECT_EQ(-1, res1);
349  EXPECT_EQ(EINVAL, errno);
350
351  int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
352  EXPECT_NE(-1, res2);
353  EXPECT_EQ("y", g_StringMap["x"]);
354}
355
356namespace {
357
358int g_MMapCount = 0;
359
360class MountNodeMockMMap : public MountNode {
361 public:
362  MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
363    EXPECT_EQ(0, Init(0));
364  }
365
366  virtual Error MMap(void* addr,
367                     size_t length,
368                     int prot,
369                     int flags,
370                     size_t offset,
371                     void** out_addr) {
372    node_mmap_count_++;
373    switch (g_MMapCount++) {
374      case 0:
375        *out_addr = reinterpret_cast<void*>(0x1000);
376        break;
377      case 1:
378        *out_addr = reinterpret_cast<void*>(0x2000);
379        break;
380      case 2:
381        *out_addr = reinterpret_cast<void*>(0x3000);
382        break;
383      default:
384        return EPERM;
385    }
386
387    return 0;
388  }
389
390 private:
391  int node_mmap_count_;
392};
393
394class MountMockMMap : public Mount {
395 public:
396  virtual Error Access(const Path& path, int a_mode) { return 0; }
397  virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
398    out_node->reset(new MountNodeMockMMap(this));
399    return 0;
400  }
401
402  virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
403    out_node->reset(NULL);
404    return ENOSYS;
405  }
406  virtual Error Unlink(const Path& path) { return ENOSYS; }
407  virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
408  virtual Error Rmdir(const Path& path) { return ENOSYS; }
409  virtual Error Remove(const Path& path) { return ENOSYS; }
410
411  friend class TypedMountFactory<MountMockMMap>;
412};
413
414class KernelProxyMockMMap : public KernelProxy {
415  virtual Error Init(PepperInterface* ppapi) {
416    KernelProxy::Init(NULL);
417    factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
418    return 0;
419  }
420};
421
422class KernelProxyMMapTest : public ::testing::Test {
423 public:
424  KernelProxyMMapTest() {}
425
426  void SetUp() {
427    ki_init(&kp_);
428  }
429
430  void TearDown() {
431    ki_uninit();
432  }
433
434 private:
435  KernelProxyMockMMap kp_;
436};
437
438}  // namespace
439
440TEST_F(KernelProxyMMapTest, MMap) {
441  ASSERT_EQ(0, ki_umount("/"));
442  ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
443  int fd = ki_open("/file", O_RDWR | O_CREAT);
444  ASSERT_NE(-1, fd);
445
446  void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
447  ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
448  ASSERT_EQ(1, g_MMapCount);
449
450  void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
451  ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
452  ASSERT_EQ(2, g_MMapCount);
453
454  void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
455  ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
456  ASSERT_EQ(3, g_MMapCount);
457
458  ki_close(fd);
459
460  // We no longer track mmap'd regions, so munmap is a no-op.
461  ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
462  // We don't track regions, so the mmap count hasn't changed.
463  ASSERT_EQ(3, g_MMapCount);
464}
465
466namespace {
467
468class SingletonMountFactory : public MountFactory {
469 public:
470  SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
471
472  virtual Error CreateMount(int dev,
473                            StringMap_t& args,
474                            PepperInterface* ppapi,
475                            ScopedMount* out_mount) {
476    *out_mount = mount_;
477    return 0;
478  }
479
480 private:
481  ScopedMount mount_;
482};
483
484class KernelProxyError : public KernelProxy {
485 public:
486  KernelProxyError() : mnt_(new MountMock) {}
487
488  virtual Error Init(PepperInterface* ppapi) {
489    KernelProxy::Init(ppapi);
490    factories_["testfs"] = new SingletonMountFactory(mnt_);
491
492    EXPECT_CALL(*mnt_, Destroy()).Times(1);
493    return 0;
494  }
495
496  ScopedRef<MountMock> mnt() { return mnt_; }
497
498 private:
499  ScopedRef<MountMock> mnt_;
500};
501
502class KernelProxyErrorTest : public ::testing::Test {
503 public:
504  KernelProxyErrorTest() {}
505
506  void SetUp() {
507    ki_init(&kp_);
508    // Unmount the passthrough FS and mount a testfs.
509    EXPECT_EQ(0, kp_.umount("/"));
510    EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
511  }
512
513  void TearDown() {
514    ki_uninit();
515  }
516
517  ScopedRef<MountMock> mnt() { return kp_.mnt(); }
518
519 private:
520  KernelProxyError kp_;
521};
522
523}  // namespace
524
525TEST_F(KernelProxyErrorTest, WriteError) {
526  ScopedRef<MountMock> mock_mnt(mnt());
527  ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
528  EXPECT_CALL(*mock_mnt, Open(_, _, _))
529      .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
530
531  EXPECT_CALL(*mock_node, Write(_, _, _, _))
532      .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
533                      Return(1234)));       // Returned error 1234.
534
535  EXPECT_CALL(*mock_node, Destroy()).Times(1);
536
537  int fd = ki_open("/dummy", O_WRONLY);
538  EXPECT_NE(0, fd);
539
540  char buf[20];
541  EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
542  // The Mount should be able to return whatever error it wants and have it
543  // propagate through.
544  EXPECT_EQ(1234, errno);
545}
546
547TEST_F(KernelProxyErrorTest, ReadError) {
548  ScopedRef<MountMock> mock_mnt(mnt());
549  ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
550  EXPECT_CALL(*mock_mnt, Open(_, _, _))
551      .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
552
553  EXPECT_CALL(*mock_node, Read(_, _, _, _))
554      .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
555                      Return(1234)));       // Returned error 1234.
556
557  EXPECT_CALL(*mock_node, Destroy()).Times(1);
558
559  int fd = ki_open("/dummy", O_RDONLY);
560  EXPECT_NE(0, fd);
561
562  char buf[20];
563  EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
564  // The Mount should be able to return whatever error it wants and have it
565  // propagate through.
566  EXPECT_EQ(1234, errno);
567}
568
569