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.
5 #include "sandbox/linux/services/broker_process.h"
9 #include <sys/resource.h>
11 #include <sys/types.h>
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"
33 class BrokerProcessTestHelper {
35 static int get_ipc_socketpair(const BrokerProcess* broker) {
36 return broker->ipc_socketpair_;
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 {
49 #if defined(OS_ANDROID)
50 static const char file_template[] = "/data/local/tmp/ScopedTempFileXXXXXX";
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_);
60 ~ScopedTemporaryFile() {
61 CHECK_EQ(0, unlink(full_file_name_));
62 CHECK_EQ(0, IGNORE_EINTR(close(fd_)));
65 int fd() const { return fd_; }
66 const char* full_file_name() const { return full_file_name_; }
70 char full_file_name_[128];
71 DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile);
74 bool NoOpCallback() { return true; }
78 TEST(BrokerProcess, CreateAndDestroy) {
79 std::vector<std::string> read_whitelist;
80 read_whitelist.push_back("/proc/cpuinfo");
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)));
86 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
87 // Destroy the broker and check it has exited properly.
89 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
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)));
97 int fd = open_broker.Open(NULL, O_RDONLY);
98 ASSERT_EQ(fd, -EFAULT);
100 int ret = open_broker.Access(NULL, F_OK);
101 ASSERT_EQ(ret, -EFAULT);
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
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";
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);
118 std::vector<std::string> write_whitelist;
119 write_whitelist.push_back(kW_WhiteListed);
120 write_whitelist.push_back(kRW_WhiteListed);
122 BrokerProcess open_broker(denied_errno,
125 fast_check_in_client);
126 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
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);
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);
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.
153 fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY);
154 // The broker process will allow this, but the normal permission system
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.
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);
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);
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);
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);
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);
237 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
239 fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT);
240 ASSERT_EQ(fd, -denied_errno);
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
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
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
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
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);
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)));
280 fd = open_broker->Open(kFileCpuInfo, O_RDWR);
281 base::ScopedFD fd_closer(fd);
282 ASSERT_EQ(fd, -EPERM);
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.
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);
296 memset(buf, 0, sizeof(buf));
297 int read_len1 = read(cpuinfo_fd, buf, sizeof(buf));
298 ASSERT_GT(read_len1, 0);
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);
305 memset(buf2, 1, sizeof(buf2));
306 int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2));
307 ASSERT_GT(read_len1, 0);
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
313 ASSERT_EQ(memcmp(buf, buf2, read_len1), 0);
315 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
317 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
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
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
334 TEST(BrokerProcess, OpenFileRW) {
335 ScopedTemporaryFile tempfile;
336 const char* tempfile_name = tempfile.full_file_name();
338 std::vector<std::string> whitelist;
339 whitelist.push_back(tempfile_name);
341 BrokerProcess open_broker(EPERM, whitelist, whitelist);
342 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
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);
349 tempfile2 = open_broker.Open(tempfile_name, O_RDWR);
350 ASSERT_GE(tempfile2, 0);
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)));
357 // Read back from the original file descriptor what we wrote through
358 // the descriptor provided by the broker.
360 len = read(tempfile.fd(), buf, sizeof(buf));
362 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
363 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0);
365 ASSERT_EQ(close(tempfile2), 0);
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");
374 BrokerProcess open_broker(EPERM,
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);
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)) ==
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);
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);
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);
402 BrokerProcess open_broker(EPERM,
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.
410 fd = open_broker.Open(kCpuInfo, O_RDONLY);
412 ret = fcntl(fd, F_GETFL);
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));
418 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC);
420 ret = fcntl(fd, F_GETFD);
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));
427 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK);
429 ret = fcntl(fd, F_GETFL);
431 ASSERT_TRUE(O_NONBLOCK & ret);
432 ASSERT_EQ(0, close(fd));
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
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
447 // We need to allow noise because the broker will log when it receives our
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));
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])));
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));
469 // Valgrind doesn't allow changing the hard descriptor limit, so we only
470 // change the soft descriptor limit here.
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));
477 static const char kCpuInfo[] = "/proc/cpuinfo";
478 std::vector<std::string> read_whitelist;
479 read_whitelist.push_back(kCpuInfo);
481 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>());
482 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
484 const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker);
485 SANDBOX_ASSERT(ipc_fd >= 0);
487 static const char kBogus[] = "not a pickle";
488 std::vector<int> fds;
489 fds.push_back(message_fd.get());
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) {
495 UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds));
498 const int fd = open_broker.Open(kCpuInfo, O_RDONLY);
499 SANDBOX_ASSERT(fd >= 0);
500 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd)));
503 } // namespace sandbox