a1f38df3ae95ac580be65b207020aa3249ce3256
[platform/framework/web/crosswalk.git] / src / sandbox / linux / services / broker_process_unittest.cc
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 "sandbox/linux/services/broker_process.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/resource.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <unistd.h>
14
15 #include <algorithm>
16 #include <string>
17 #include <vector>
18
19 #include "base/basictypes.h"
20 #include "base/bind.h"
21 #include "base/file_util.h"
22 #include "base/files/scoped_file.h"
23 #include "base/logging.h"
24 #include "base/memory/scoped_ptr.h"
25 #include "base/posix/eintr_wrapper.h"
26 #include "base/posix/unix_domain_socket_linux.h"
27 #include "sandbox/linux/tests/test_utils.h"
28 #include "sandbox/linux/tests/unit_tests.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 namespace sandbox {
32
33 class BrokerProcessTestHelper {
34  public:
35   static int get_ipc_socketpair(const BrokerProcess* broker) {
36     return broker->ipc_socketpair_;
37   }
38 };
39
40 namespace {
41
42 // Creates and open a temporary file on creation and closes
43 // and removes it on destruction.
44 // Unlike base/ helpers, this does not require JNI on Android.
45 class ScopedTemporaryFile {
46  public:
47   ScopedTemporaryFile()
48       : fd_(-1) {
49 #if defined(OS_ANDROID)
50     static const char file_template[] = "/data/local/tmp/ScopedTempFileXXXXXX";
51 #else
52     static const char file_template[] = "/tmp/ScopedTempFileXXXXXX";
53 #endif  // defined(OS_ANDROID)
54     COMPILE_ASSERT(sizeof(full_file_name_) >= sizeof(file_template),
55                    full_file_name_is_large_enough);
56     memcpy(full_file_name_, file_template, sizeof(file_template));
57     fd_ = mkstemp(full_file_name_);
58     CHECK_LE(0, fd_);
59   }
60   ~ScopedTemporaryFile() {
61     CHECK_EQ(0, unlink(full_file_name_));
62     CHECK_EQ(0, IGNORE_EINTR(close(fd_)));
63   }
64
65   int fd() const { return fd_; }
66   const char* full_file_name() const { return full_file_name_; }
67
68  private:
69   int fd_;
70   char full_file_name_[128];
71   DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile);
72 };
73
74 bool NoOpCallback() { return true; }
75
76 }  // namespace
77
78 TEST(BrokerProcess, CreateAndDestroy) {
79   std::vector<std::string> read_whitelist;
80   read_whitelist.push_back("/proc/cpuinfo");
81
82   scoped_ptr<BrokerProcess> open_broker(
83       new BrokerProcess(EPERM, read_whitelist, std::vector<std::string>()));
84   ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
85
86   ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
87   // Destroy the broker and check it has exited properly.
88   open_broker.reset();
89   ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
90 }
91
92 TEST(BrokerProcess, TestOpenAccessNull) {
93   const std::vector<std::string> empty;
94   BrokerProcess open_broker(EPERM, empty, empty);
95   ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
96
97   int fd = open_broker.Open(NULL, O_RDONLY);
98   ASSERT_EQ(fd, -EFAULT);
99
100   int ret = open_broker.Access(NULL, F_OK);
101   ASSERT_EQ(ret, -EFAULT);
102 }
103
104 void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) {
105   const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1";
106   // We can't debug the init process, and shouldn't be able to access
107   // its auxv file.
108   const char kR_WhiteListedButDenied[] = "/proc/1/auxv";
109   const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2";
110   const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3";
111   const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4";
112
113   std::vector<std::string> read_whitelist;
114   read_whitelist.push_back(kR_WhiteListed);
115   read_whitelist.push_back(kR_WhiteListedButDenied);
116   read_whitelist.push_back(kRW_WhiteListed);
117
118   std::vector<std::string> write_whitelist;
119   write_whitelist.push_back(kW_WhiteListed);
120   write_whitelist.push_back(kRW_WhiteListed);
121
122   BrokerProcess open_broker(denied_errno,
123                             read_whitelist,
124                             write_whitelist,
125                             fast_check_in_client);
126   ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
127
128   int fd = -1;
129   fd = open_broker.Open(kR_WhiteListed, O_RDONLY);
130   ASSERT_EQ(fd, -ENOENT);
131   fd = open_broker.Open(kR_WhiteListed, O_WRONLY);
132   ASSERT_EQ(fd, -denied_errno);
133   fd = open_broker.Open(kR_WhiteListed, O_RDWR);
134   ASSERT_EQ(fd, -denied_errno);
135   int ret = -1;
136   ret = open_broker.Access(kR_WhiteListed, F_OK);
137   ASSERT_EQ(ret, -ENOENT);
138   ret = open_broker.Access(kR_WhiteListed, R_OK);
139   ASSERT_EQ(ret, -ENOENT);
140   ret = open_broker.Access(kR_WhiteListed, W_OK);
141   ASSERT_EQ(ret, -denied_errno);
142   ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK);
143   ASSERT_EQ(ret, -denied_errno);
144   ret = open_broker.Access(kR_WhiteListed, X_OK);
145   ASSERT_EQ(ret, -denied_errno);
146   ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK);
147   ASSERT_EQ(ret, -denied_errno);
148
149   // Android sometimes runs tests as root.
150   // This part of the test requires a process that doesn't have
151   // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
152   if (geteuid()) {
153     fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY);
154     // The broker process will allow this, but the normal permission system
155     // won't.
156     ASSERT_EQ(fd, -EACCES);
157     fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY);
158     ASSERT_EQ(fd, -denied_errno);
159     fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR);
160     ASSERT_EQ(fd, -denied_errno);
161     ret = open_broker.Access(kR_WhiteListedButDenied, F_OK);
162     // The normal permission system will let us check that the file exists.
163     ASSERT_EQ(ret, 0);
164     ret = open_broker.Access(kR_WhiteListedButDenied, R_OK);
165     ASSERT_EQ(ret, -EACCES);
166     ret = open_broker.Access(kR_WhiteListedButDenied, W_OK);
167     ASSERT_EQ(ret, -denied_errno);
168     ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK);
169     ASSERT_EQ(ret, -denied_errno);
170     ret = open_broker.Access(kR_WhiteListedButDenied, X_OK);
171     ASSERT_EQ(ret, -denied_errno);
172     ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK);
173     ASSERT_EQ(ret, -denied_errno);
174   }
175
176   fd = open_broker.Open(kW_WhiteListed, O_RDONLY);
177   ASSERT_EQ(fd, -denied_errno);
178   fd = open_broker.Open(kW_WhiteListed, O_WRONLY);
179   ASSERT_EQ(fd, -ENOENT);
180   fd = open_broker.Open(kW_WhiteListed, O_RDWR);
181   ASSERT_EQ(fd, -denied_errno);
182   ret = open_broker.Access(kW_WhiteListed, F_OK);
183   ASSERT_EQ(ret, -ENOENT);
184   ret = open_broker.Access(kW_WhiteListed, R_OK);
185   ASSERT_EQ(ret, -denied_errno);
186   ret = open_broker.Access(kW_WhiteListed, W_OK);
187   ASSERT_EQ(ret, -ENOENT);
188   ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK);
189   ASSERT_EQ(ret, -denied_errno);
190   ret = open_broker.Access(kW_WhiteListed, X_OK);
191   ASSERT_EQ(ret, -denied_errno);
192   ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK);
193   ASSERT_EQ(ret, -denied_errno);
194
195   fd = open_broker.Open(kRW_WhiteListed, O_RDONLY);
196   ASSERT_EQ(fd, -ENOENT);
197   fd = open_broker.Open(kRW_WhiteListed, O_WRONLY);
198   ASSERT_EQ(fd, -ENOENT);
199   fd = open_broker.Open(kRW_WhiteListed, O_RDWR);
200   ASSERT_EQ(fd, -ENOENT);
201   ret = open_broker.Access(kRW_WhiteListed, F_OK);
202   ASSERT_EQ(ret, -ENOENT);
203   ret = open_broker.Access(kRW_WhiteListed, R_OK);
204   ASSERT_EQ(ret, -ENOENT);
205   ret = open_broker.Access(kRW_WhiteListed, W_OK);
206   ASSERT_EQ(ret, -ENOENT);
207   ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK);
208   ASSERT_EQ(ret, -ENOENT);
209   ret = open_broker.Access(kRW_WhiteListed, X_OK);
210   ASSERT_EQ(ret, -denied_errno);
211   ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK);
212   ASSERT_EQ(ret, -denied_errno);
213
214   fd = open_broker.Open(k_NotWhitelisted, O_RDONLY);
215   ASSERT_EQ(fd, -denied_errno);
216   fd = open_broker.Open(k_NotWhitelisted, O_WRONLY);
217   ASSERT_EQ(fd, -denied_errno);
218   fd = open_broker.Open(k_NotWhitelisted, O_RDWR);
219   ASSERT_EQ(fd, -denied_errno);
220   ret = open_broker.Access(k_NotWhitelisted, F_OK);
221   ASSERT_EQ(ret, -denied_errno);
222   ret = open_broker.Access(k_NotWhitelisted, R_OK);
223   ASSERT_EQ(ret, -denied_errno);
224   ret = open_broker.Access(k_NotWhitelisted, W_OK);
225   ASSERT_EQ(ret, -denied_errno);
226   ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK);
227   ASSERT_EQ(ret, -denied_errno);
228   ret = open_broker.Access(k_NotWhitelisted, X_OK);
229   ASSERT_EQ(ret, -denied_errno);
230   ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK);
231   ASSERT_EQ(ret, -denied_errno);
232
233   // We have some extra sanity check for clearly wrong values.
234   fd = open_broker.Open(kRW_WhiteListed, O_RDONLY | O_WRONLY | O_RDWR);
235   ASSERT_EQ(fd, -denied_errno);
236
237   // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
238   // is denied.
239   fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT);
240   ASSERT_EQ(fd, -denied_errno);
241 }
242
243 // Run the same thing twice. The second time, we make sure that no security
244 // check is performed on the client.
245 TEST(BrokerProcess, OpenFilePermsWithClientCheck) {
246   TestOpenFilePerms(true /* fast_check_in_client */, EPERM);
247   // Don't do anything here, so that ASSERT works in the subfunction as
248   // expected.
249 }
250
251 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) {
252   TestOpenFilePerms(false /* fast_check_in_client */, EPERM);
253   // Don't do anything here, so that ASSERT works in the subfunction as
254   // expected.
255 }
256
257 // Run the same twice again, but with ENOENT instead of EPERM.
258 TEST(BrokerProcess, OpenFilePermsWithClientCheckNoEnt) {
259   TestOpenFilePerms(true /* fast_check_in_client */, ENOENT);
260   // Don't do anything here, so that ASSERT works in the subfunction as
261   // expected.
262 }
263
264 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) {
265   TestOpenFilePerms(false /* fast_check_in_client */, ENOENT);
266   // Don't do anything here, so that ASSERT works in the subfunction as
267   // expected.
268 }
269
270 void TestOpenCpuinfo(bool fast_check_in_client) {
271   const char kFileCpuInfo[] = "/proc/cpuinfo";
272   std::vector<std::string> read_whitelist;
273   read_whitelist.push_back(kFileCpuInfo);
274
275   scoped_ptr<BrokerProcess> open_broker(new BrokerProcess(
276       EPERM, read_whitelist, std::vector<std::string>(), fast_check_in_client));
277   ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
278
279   int fd = -1;
280   fd = open_broker->Open(kFileCpuInfo, O_RDWR);
281   base::ScopedFD fd_closer(fd);
282   ASSERT_EQ(fd, -EPERM);
283
284   // Check we can read /proc/cpuinfo.
285   int can_access = open_broker->Access(kFileCpuInfo, R_OK);
286   ASSERT_EQ(can_access, 0);
287   can_access = open_broker->Access(kFileCpuInfo, W_OK);
288   ASSERT_EQ(can_access, -EPERM);
289   // Check we can not write /proc/cpuinfo.
290
291   // Open cpuinfo via the broker.
292   int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
293   base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd);
294   ASSERT_GE(cpuinfo_fd, 0);
295   char buf[3];
296   memset(buf, 0, sizeof(buf));
297   int read_len1 = read(cpuinfo_fd, buf, sizeof(buf));
298   ASSERT_GT(read_len1, 0);
299
300   // Open cpuinfo directly.
301   int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY);
302   base::ScopedFD cpuinfo_fd2_closer(cpuinfo_fd2);
303   ASSERT_GE(cpuinfo_fd2, 0);
304   char buf2[3];
305   memset(buf2, 1, sizeof(buf2));
306   int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2));
307   ASSERT_GT(read_len1, 0);
308
309   // The following is not guaranteed true, but will be in practice.
310   ASSERT_EQ(read_len1, read_len2);
311   // Compare the cpuinfo as returned by the broker with the one we opened
312   // ourselves.
313   ASSERT_EQ(memcmp(buf, buf2, read_len1), 0);
314
315   ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
316   open_broker.reset();
317   ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
318 }
319
320 // Run the same thing twice. The second time, we make sure that no security
321 // check is performed on the client.
322 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) {
323   TestOpenCpuinfo(true /* fast_check_in_client */);
324   // Don't do anything here, so that ASSERT works in the subfunction as
325   // expected.
326 }
327
328 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) {
329   TestOpenCpuinfo(false /* fast_check_in_client */);
330   // Don't do anything here, so that ASSERT works in the subfunction as
331   // expected.
332 }
333
334 TEST(BrokerProcess, OpenFileRW) {
335   ScopedTemporaryFile tempfile;
336   const char* tempfile_name = tempfile.full_file_name();
337
338   std::vector<std::string> whitelist;
339   whitelist.push_back(tempfile_name);
340
341   BrokerProcess open_broker(EPERM, whitelist, whitelist);
342   ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
343
344   // Check we can access that file with read or write.
345   int can_access = open_broker.Access(tempfile_name, R_OK | W_OK);
346   ASSERT_EQ(can_access, 0);
347
348   int tempfile2 = -1;
349   tempfile2 = open_broker.Open(tempfile_name, O_RDWR);
350   ASSERT_GE(tempfile2, 0);
351
352   // Write to the descriptor opened by the broker.
353   char test_text[] = "TESTTESTTEST";
354   ssize_t len = write(tempfile2, test_text, sizeof(test_text));
355   ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
356
357   // Read back from the original file descriptor what we wrote through
358   // the descriptor provided by the broker.
359   char buf[1024];
360   len = read(tempfile.fd(), buf, sizeof(buf));
361
362   ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
363   ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0);
364
365   ASSERT_EQ(close(tempfile2), 0);
366 }
367
368 // SANDBOX_TEST because the process could die with a SIGPIPE
369 // and we want this to happen in a subprocess.
370 SANDBOX_TEST(BrokerProcess, BrokerDied) {
371   std::vector<std::string> read_whitelist;
372   read_whitelist.push_back("/proc/cpuinfo");
373
374   BrokerProcess open_broker(EPERM,
375                             read_whitelist,
376                             std::vector<std::string>(),
377                             true /* fast_check_in_client */,
378                             true /* quiet_failures_for_tests */);
379   SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
380   const pid_t broker_pid = open_broker.broker_pid();
381   SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0);
382
383   // Now we check that the broker has been signaled, but do not reap it.
384   siginfo_t process_info;
385   SANDBOX_ASSERT(HANDLE_EINTR(waitid(
386                      P_PID, broker_pid, &process_info, WEXITED | WNOWAIT)) ==
387                  0);
388   SANDBOX_ASSERT(broker_pid == process_info.si_pid);
389   SANDBOX_ASSERT(CLD_KILLED == process_info.si_code);
390   SANDBOX_ASSERT(SIGKILL == process_info.si_status);
391
392   // Check that doing Open with a dead broker won't SIGPIPE us.
393   SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM);
394   SANDBOX_ASSERT(open_broker.Access("/proc/cpuinfo", O_RDONLY) == -ENOMEM);
395 }
396
397 void TestOpenComplexFlags(bool fast_check_in_client) {
398   const char kCpuInfo[] = "/proc/cpuinfo";
399   std::vector<std::string> whitelist;
400   whitelist.push_back(kCpuInfo);
401
402   BrokerProcess open_broker(EPERM,
403                             whitelist,
404                             whitelist,
405                             fast_check_in_client);
406   ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
407   // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
408   int fd = -1;
409   int ret = 0;
410   fd = open_broker.Open(kCpuInfo, O_RDONLY);
411   ASSERT_GE(fd, 0);
412   ret = fcntl(fd, F_GETFL);
413   ASSERT_NE(-1, ret);
414   // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
415   ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK));
416   ASSERT_EQ(0, close(fd));
417
418   fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC);
419   ASSERT_GE(fd, 0);
420   ret = fcntl(fd, F_GETFD);
421   ASSERT_NE(-1, ret);
422   // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
423   // is actually not used by the kernel.
424   ASSERT_TRUE(FD_CLOEXEC & ret);
425   ASSERT_EQ(0, close(fd));
426
427   fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK);
428   ASSERT_GE(fd, 0);
429   ret = fcntl(fd, F_GETFL);
430   ASSERT_NE(-1, ret);
431   ASSERT_TRUE(O_NONBLOCK & ret);
432   ASSERT_EQ(0, close(fd));
433 }
434
435 TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) {
436   TestOpenComplexFlags(true /* fast_check_in_client */);
437   // Don't do anything here, so that ASSERT works in the subfunction as
438   // expected.
439 }
440
441 TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) {
442   TestOpenComplexFlags(false /* fast_check_in_client */);
443   // Don't do anything here, so that ASSERT works in the subfunction as
444   // expected.
445 }
446
447 // We need to allow noise because the broker will log when it receives our
448 // bogus IPCs.
449 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, RecvMsgDescriptorLeak) {
450   // Find the four lowest available file descriptors.
451   int available_fds[4];
452   SANDBOX_ASSERT(0 == pipe(available_fds));
453   SANDBOX_ASSERT(0 == pipe(available_fds + 2));
454
455   // Save one FD to send to the broker later, and close the others.
456   base::ScopedFD message_fd(available_fds[0]);
457   for (size_t i = 1; i < arraysize(available_fds); i++) {
458     SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds[i])));
459   }
460
461   // Lower our file descriptor limit to just allow three more file descriptors
462   // to be allocated.  (N.B., RLIMIT_NOFILE doesn't limit the number of file
463   // descriptors a process can have: it only limits the highest value that can
464   // be assigned to newly-created descriptors allocated by the process.)
465   const rlim_t fd_limit =
466       1 + *std::max_element(available_fds,
467                             available_fds + arraysize(available_fds));
468
469   // Valgrind doesn't allow changing the hard descriptor limit, so we only
470   // change the soft descriptor limit here.
471   struct rlimit rlim;
472   SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim));
473   SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur);
474   rlim.rlim_cur = fd_limit;
475   SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim));
476
477   static const char kCpuInfo[] = "/proc/cpuinfo";
478   std::vector<std::string> read_whitelist;
479   read_whitelist.push_back(kCpuInfo);
480
481   BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>());
482   SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
483
484   const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker);
485   SANDBOX_ASSERT(ipc_fd >= 0);
486
487   static const char kBogus[] = "not a pickle";
488   std::vector<int> fds;
489   fds.push_back(message_fd.get());
490
491   // The broker process should only have a couple spare file descriptors
492   // available, but for good measure we send it fd_limit bogus IPCs anyway.
493   for (rlim_t i = 0; i < fd_limit; ++i) {
494     SANDBOX_ASSERT(
495         UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds));
496   }
497
498   const int fd = open_broker.Open(kCpuInfo, O_RDONLY);
499   SANDBOX_ASSERT(fd >= 0);
500   SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd)));
501 }
502
503 }  // namespace sandbox