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/stat.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include <string>
15#include <vector>
16
17#include "base/basictypes.h"
18#include "base/logging.h"
19#include "base/posix/eintr_wrapper.h"
20#include "sandbox/linux/tests/unit_tests.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace sandbox {
24
25namespace {
26
27// Creates and open a temporary file on creation and closes
28// and removes it on destruction.
29// Unlike base/ helpers, this does not require JNI on Android.
30class ScopedTemporaryFile {
31 public:
32  ScopedTemporaryFile()
33      : fd_(-1) {
34#if defined(OS_ANDROID)
35    static const char file_template[] = "/data/local/tmp/ScopedTempFileXXXXXX";
36#else
37    static const char file_template[] = "/tmp/ScopedTempFileXXXXXX";
38#endif  // defined(OS_ANDROID)
39    COMPILE_ASSERT(sizeof(full_file_name_) >= sizeof(file_template),
40                   full_file_name_is_large_enough);
41    memcpy(full_file_name_, file_template, sizeof(file_template));
42    fd_ = mkstemp(full_file_name_);
43    CHECK_LE(0, fd_);
44  }
45  ~ScopedTemporaryFile() {
46    CHECK_EQ(0, unlink(full_file_name_));
47    CHECK_EQ(0, HANDLE_EINTR(close(fd_)));
48  }
49
50  int fd() const { return fd_; }
51  const char* full_file_name() const { return full_file_name_; }
52
53 private:
54  int fd_;
55  char full_file_name_[128];
56  DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile);
57};
58
59}  // namespace
60
61#if defined(OS_ANDROID)
62  #define DISABLE_ON_ANDROID(function) DISABLED_##function
63#else
64  #define DISABLE_ON_ANDROID(function) function
65#endif
66
67TEST(BrokerProcess, CreateAndDestroy) {
68  std::vector<std::string> read_whitelist;
69  read_whitelist.push_back("/proc/cpuinfo");
70
71  BrokerProcess* open_broker = new BrokerProcess(read_whitelist,
72                                                 std::vector<std::string>());
73  ASSERT_TRUE(open_broker->Init(NULL));
74  pid_t broker_pid = open_broker->broker_pid();
75  delete(open_broker);
76
77  // Now we check that the broker has exited properly.
78  int status = 0;
79  ASSERT_EQ(waitpid(broker_pid, &status, 0), broker_pid);
80  ASSERT_TRUE(WIFEXITED(status));
81  ASSERT_EQ(WEXITSTATUS(status), 0);
82}
83
84TEST(BrokerProcess, TestOpenAccessNull) {
85  const std::vector<std::string> empty;
86  BrokerProcess open_broker(empty, empty);
87  ASSERT_TRUE(open_broker.Init(NULL));
88
89  int fd = open_broker.Open(NULL, O_RDONLY);
90  ASSERT_EQ(fd, -EFAULT);
91
92  int ret = open_broker.Access(NULL, F_OK);
93  ASSERT_EQ(ret, -EFAULT);
94}
95
96void TestOpenFilePerms(bool fast_check_in_client) {
97  const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1";
98  // We can't debug the init process, and shouldn't be able to access
99  // its auxv file.
100  const char kR_WhiteListedButDenied[] = "/proc/1/auxv";
101  const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2";
102  const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3";
103  const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4";
104
105  std::vector<std::string> read_whitelist;
106  read_whitelist.push_back(kR_WhiteListed);
107  read_whitelist.push_back(kR_WhiteListedButDenied);
108  read_whitelist.push_back(kRW_WhiteListed);
109
110  std::vector<std::string> write_whitelist;
111  write_whitelist.push_back(kW_WhiteListed);
112  write_whitelist.push_back(kRW_WhiteListed);
113
114  BrokerProcess open_broker(read_whitelist,
115                            write_whitelist,
116                            fast_check_in_client);
117  ASSERT_TRUE(open_broker.Init(NULL));
118
119  int fd = -1;
120  fd = open_broker.Open(kR_WhiteListed, O_RDONLY);
121  ASSERT_EQ(fd, -ENOENT);
122  fd = open_broker.Open(kR_WhiteListed, O_WRONLY);
123  ASSERT_EQ(fd, -EPERM);
124  fd = open_broker.Open(kR_WhiteListed, O_RDWR);
125  ASSERT_EQ(fd, -EPERM);
126  int ret = -1;
127  ret = open_broker.Access(kR_WhiteListed, F_OK);
128  ASSERT_EQ(ret, -ENOENT);
129  ret = open_broker.Access(kR_WhiteListed, R_OK);
130  ASSERT_EQ(ret, -ENOENT);
131  ret = open_broker.Access(kR_WhiteListed, W_OK);
132  ASSERT_EQ(ret, -EPERM);
133  ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK);
134  ASSERT_EQ(ret, -EPERM);
135  ret = open_broker.Access(kR_WhiteListed, X_OK);
136  ASSERT_EQ(ret, -EPERM);
137  ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK);
138  ASSERT_EQ(ret, -EPERM);
139
140  // Android sometimes runs tests as root.
141  // This part of the test requires a process that doesn't have
142  // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
143  if (geteuid()) {
144    fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY);
145    // The broker process will allow this, but the normal permission system
146    // won't.
147    ASSERT_EQ(fd, -EACCES);
148    fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY);
149    ASSERT_EQ(fd, -EPERM);
150    fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR);
151    ASSERT_EQ(fd, -EPERM);
152    ret = open_broker.Access(kR_WhiteListedButDenied, F_OK);
153    // The normal permission system will let us check that the file exists.
154    ASSERT_EQ(ret, 0);
155    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK);
156    ASSERT_EQ(ret, -EACCES);
157    ret = open_broker.Access(kR_WhiteListedButDenied, W_OK);
158    ASSERT_EQ(ret, -EPERM);
159    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK);
160    ASSERT_EQ(ret, -EPERM);
161    ret = open_broker.Access(kR_WhiteListedButDenied, X_OK);
162    ASSERT_EQ(ret, -EPERM);
163    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK);
164    ASSERT_EQ(ret, -EPERM);
165  }
166
167  fd = open_broker.Open(kW_WhiteListed, O_RDONLY);
168  ASSERT_EQ(fd, -EPERM);
169  fd = open_broker.Open(kW_WhiteListed, O_WRONLY);
170  ASSERT_EQ(fd, -ENOENT);
171  fd = open_broker.Open(kW_WhiteListed, O_RDWR);
172  ASSERT_EQ(fd, -EPERM);
173  ret = open_broker.Access(kW_WhiteListed, F_OK);
174  ASSERT_EQ(ret, -ENOENT);
175  ret = open_broker.Access(kW_WhiteListed, R_OK);
176  ASSERT_EQ(ret, -EPERM);
177  ret = open_broker.Access(kW_WhiteListed, W_OK);
178  ASSERT_EQ(ret, -ENOENT);
179  ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK);
180  ASSERT_EQ(ret, -EPERM);
181  ret = open_broker.Access(kW_WhiteListed, X_OK);
182  ASSERT_EQ(ret, -EPERM);
183  ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK);
184  ASSERT_EQ(ret, -EPERM);
185
186  fd = open_broker.Open(kRW_WhiteListed, O_RDONLY);
187  ASSERT_EQ(fd, -ENOENT);
188  fd = open_broker.Open(kRW_WhiteListed, O_WRONLY);
189  ASSERT_EQ(fd, -ENOENT);
190  fd = open_broker.Open(kRW_WhiteListed, O_RDWR);
191  ASSERT_EQ(fd, -ENOENT);
192  ret = open_broker.Access(kRW_WhiteListed, F_OK);
193  ASSERT_EQ(ret, -ENOENT);
194  ret = open_broker.Access(kRW_WhiteListed, R_OK);
195  ASSERT_EQ(ret, -ENOENT);
196  ret = open_broker.Access(kRW_WhiteListed, W_OK);
197  ASSERT_EQ(ret, -ENOENT);
198  ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK);
199  ASSERT_EQ(ret, -ENOENT);
200  ret = open_broker.Access(kRW_WhiteListed, X_OK);
201  ASSERT_EQ(ret, -EPERM);
202  ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK);
203  ASSERT_EQ(ret, -EPERM);
204
205  fd = open_broker.Open(k_NotWhitelisted, O_RDONLY);
206  ASSERT_EQ(fd, -EPERM);
207  fd = open_broker.Open(k_NotWhitelisted, O_WRONLY);
208  ASSERT_EQ(fd, -EPERM);
209  fd = open_broker.Open(k_NotWhitelisted, O_RDWR);
210  ASSERT_EQ(fd, -EPERM);
211  ret = open_broker.Access(k_NotWhitelisted, F_OK);
212  ASSERT_EQ(ret, -EPERM);
213  ret = open_broker.Access(k_NotWhitelisted, R_OK);
214  ASSERT_EQ(ret, -EPERM);
215  ret = open_broker.Access(k_NotWhitelisted, W_OK);
216  ASSERT_EQ(ret, -EPERM);
217  ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK);
218  ASSERT_EQ(ret, -EPERM);
219  ret = open_broker.Access(k_NotWhitelisted, X_OK);
220  ASSERT_EQ(ret, -EPERM);
221  ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK);
222  ASSERT_EQ(ret, -EPERM);
223
224
225  // We have some extra sanity check for clearly wrong values.
226  fd = open_broker.Open(kRW_WhiteListed, O_RDONLY|O_WRONLY|O_RDWR);
227  ASSERT_EQ(fd, -EPERM);
228
229  // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
230  // is denied.
231  fd = open_broker.Open(kRW_WhiteListed, O_RDWR|O_CREAT);
232  ASSERT_EQ(fd, -EPERM);
233}
234
235// Run the same thing twice. The second time, we make sure that no security
236// check is performed on the client.
237TEST(BrokerProcess, OpenFilePermsWithClientCheck) {
238  TestOpenFilePerms(true /* fast_check_in_client */);
239  // Don't do anything here, so that ASSERT works in the subfunction as
240  // expected.
241}
242
243TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) {
244  TestOpenFilePerms(false /* fast_check_in_client */);
245  // Don't do anything here, so that ASSERT works in the subfunction as
246  // expected.
247}
248
249
250void TestOpenCpuinfo(bool fast_check_in_client) {
251  const char kFileCpuInfo[] = "/proc/cpuinfo";
252  std::vector<std::string> read_whitelist;
253  read_whitelist.push_back(kFileCpuInfo);
254
255  BrokerProcess* open_broker = new BrokerProcess(read_whitelist,
256                                                 std::vector<std::string>(),
257                                                 fast_check_in_client);
258  ASSERT_TRUE(open_broker->Init(NULL));
259  pid_t broker_pid = open_broker->broker_pid();
260
261  int fd = -1;
262  fd = open_broker->Open(kFileCpuInfo, O_RDWR);
263  ASSERT_EQ(fd, -EPERM);
264
265  // Check we can read /proc/cpuinfo.
266  int can_access = open_broker->Access(kFileCpuInfo, R_OK);
267  ASSERT_EQ(can_access, 0);
268  can_access = open_broker->Access(kFileCpuInfo, W_OK);
269  ASSERT_EQ(can_access, -EPERM);
270  // Check we can not write /proc/cpuinfo.
271
272  // Open cpuinfo via the broker.
273  int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
274  ASSERT_GE(cpuinfo_fd, 0);
275  char buf[3];
276  memset(buf, 0, sizeof(buf));
277  int read_len1 = read(cpuinfo_fd, buf, sizeof(buf));
278  ASSERT_GT(read_len1, 0);
279
280  // Open cpuinfo directly.
281  int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY);
282  ASSERT_GE(cpuinfo_fd2, 0);
283  char buf2[3];
284  memset(buf2, 1, sizeof(buf2));
285  int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2));
286  ASSERT_GT(read_len1, 0);
287
288  // The following is not guaranteed true, but will be in practice.
289  ASSERT_EQ(read_len1, read_len2);
290  // Compare the cpuinfo as returned by the broker with the one we opened
291  // ourselves.
292  ASSERT_EQ(memcmp(buf, buf2, read_len1), 0);
293
294  if (fd >= 0)
295    close(fd);
296  if (cpuinfo_fd >= 0)
297    close(cpuinfo_fd);
298  if (cpuinfo_fd2 >= 0)
299    close(cpuinfo_fd);
300
301  delete(open_broker);
302
303  // Now we check that the broker has exited properly.
304  int status = 0;
305  ASSERT_EQ(waitpid(broker_pid, &status, 0), broker_pid);
306  ASSERT_TRUE(WIFEXITED(status));
307  ASSERT_EQ(WEXITSTATUS(status), 0);
308}
309
310// Run the same thing twice. The second time, we make sure that no security
311// check is performed on the client.
312TEST(BrokerProcess, OpenCpuinfoWithClientCheck) {
313  TestOpenCpuinfo(true /* fast_check_in_client */);
314  // Don't do anything here, so that ASSERT works in the subfunction as
315  // expected.
316}
317
318TEST(BrokerProcess, OpenCpuinfoNoClientCheck) {
319  TestOpenCpuinfo(false /* fast_check_in_client */);
320  // Don't do anything here, so that ASSERT works in the subfunction as
321  // expected.
322}
323
324TEST(BrokerProcess, OpenFileRW) {
325  ScopedTemporaryFile tempfile;
326  const char* tempfile_name = tempfile.full_file_name();
327
328  std::vector<std::string> whitelist;
329  whitelist.push_back(tempfile_name);
330
331  BrokerProcess open_broker(whitelist, whitelist);
332  ASSERT_TRUE(open_broker.Init(NULL));
333
334  // Check we can access that file with read or write.
335  int can_access = open_broker.Access(tempfile_name, R_OK | W_OK);
336  ASSERT_EQ(can_access, 0);
337
338  int tempfile2 = -1;
339  tempfile2 = open_broker.Open(tempfile_name, O_RDWR);
340  ASSERT_GE(tempfile2, 0);
341
342  // Write to the descriptor opened by the broker.
343  char test_text[] = "TESTTESTTEST";
344  ssize_t len = write(tempfile2, test_text, sizeof(test_text));
345  ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
346
347  // Read back from the original file descriptor what we wrote through
348  // the descriptor provided by the broker.
349  char buf[1024];
350  len = read(tempfile.fd(), buf, sizeof(buf));
351
352  ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
353  ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0);
354
355  ASSERT_EQ(close(tempfile2), 0);
356}
357
358// Sandbox test because we could get a SIGPIPE.
359SANDBOX_TEST(BrokerProcess, BrokerDied) {
360  std::vector<std::string> read_whitelist;
361  read_whitelist.push_back("/proc/cpuinfo");
362
363  BrokerProcess open_broker(read_whitelist,
364                            std::vector<std::string>(),
365                            true /* fast_check_in_client */,
366                            true /* quiet_failures_for_tests */);
367  SANDBOX_ASSERT(open_broker.Init(NULL));
368  pid_t broker_pid = open_broker.broker_pid();
369  SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0);
370
371  // Now we check that the broker has exited properly.
372  int status = 0;
373  SANDBOX_ASSERT(waitpid(broker_pid, &status, 0) == broker_pid);
374  SANDBOX_ASSERT(WIFSIGNALED(status));
375  SANDBOX_ASSERT(WTERMSIG(status) == SIGKILL);
376  // Hopefully doing Open with a dead broker won't SIGPIPE us.
377  SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM);
378  SANDBOX_ASSERT(open_broker.Access("/proc/cpuinfo", O_RDONLY) == -ENOMEM);
379}
380
381void TestOpenComplexFlags(bool fast_check_in_client) {
382  const char kCpuInfo[] = "/proc/cpuinfo";
383  std::vector<std::string> whitelist;
384  whitelist.push_back(kCpuInfo);
385
386  BrokerProcess open_broker(whitelist,
387                            whitelist,
388                            fast_check_in_client);
389  ASSERT_TRUE(open_broker.Init(NULL));
390  // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
391  int fd = -1;
392  int ret = 0;
393  fd = open_broker.Open(kCpuInfo, O_RDONLY);
394  ASSERT_GE(fd, 0);
395  ret = fcntl(fd, F_GETFL);
396  ASSERT_NE(-1, ret);
397  // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
398  ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK));
399  ASSERT_EQ(0, close(fd));
400
401  fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC);
402  ASSERT_GE(fd, 0);
403  ret = fcntl(fd, F_GETFD);
404  ASSERT_NE(-1, ret);
405  // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
406  // is actually not used by the kernel.
407  ASSERT_TRUE(FD_CLOEXEC & ret);
408
409  // There is buggy userland code that can check for O_CLOEXEC with fcntl(2)
410  // even though it doesn't mean anything. We need to support this case.
411  // See crbug.com/237283.
412  ret = fcntl(fd, F_GETFL);
413  ASSERT_NE(-1, ret);
414  ASSERT_TRUE(O_CLOEXEC & ret);
415
416  ASSERT_EQ(0, close(fd));
417
418  fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK);
419  ASSERT_GE(fd, 0);
420  ret = fcntl(fd, F_GETFL);
421  ASSERT_NE(-1, ret);
422  ASSERT_TRUE(O_NONBLOCK & ret);
423  ASSERT_EQ(0, close(fd));
424}
425
426TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) {
427  TestOpenComplexFlags(true /* fast_check_in_client */);
428  // Don't do anything here, so that ASSERT works in the subfunction as
429  // expected.
430}
431
432TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) {
433  TestOpenComplexFlags(false /* fast_check_in_client */);
434  // Don't do anything here, so that ASSERT works in the subfunction as
435  // expected.
436}
437
438}  // namespace sandbox
439