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/syscall_broker/broker_process.h"
10 #include <sys/resource.h>
12 #include <sys/types.h>
20 #include "base/bind.h"
21 #include "base/files/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/syscall_broker/broker_client.h"
28 #include "sandbox/linux/tests/scoped_temporary_file.h"
29 #include "sandbox/linux/tests/test_utils.h"
30 #include "sandbox/linux/tests/unit_tests.h"
31 #include "testing/gtest/include/gtest/gtest.h"
35 namespace syscall_broker
{
37 class BrokerProcessTestHelper
{
39 static void CloseChannel(BrokerProcess
* broker
) { broker
->CloseChannel(); }
40 // Get the client's IPC descriptor to send IPC requests directly.
41 // TODO(jln): refator tests to get rid of this.
42 static int GetIPCDescriptor(const BrokerProcess
* broker
) {
43 return broker
->broker_client_
->GetIPCDescriptor();
55 TEST(BrokerProcess
, CreateAndDestroy
) {
56 std::vector
<BrokerFilePermission
> permissions
;
57 permissions
.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
59 scoped_ptr
<BrokerProcess
> open_broker(new BrokerProcess(EPERM
, permissions
));
60 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
62 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
63 // Destroy the broker and check it has exited properly.
65 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
68 TEST(BrokerProcess
, TestOpenAccessNull
) {
69 std::vector
<BrokerFilePermission
> empty
;
70 BrokerProcess
open_broker(EPERM
, empty
);
71 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
73 int fd
= open_broker
.Open(NULL
, O_RDONLY
);
74 ASSERT_EQ(fd
, -EFAULT
);
76 int ret
= open_broker
.Access(NULL
, F_OK
);
77 ASSERT_EQ(ret
, -EFAULT
);
80 void TestOpenFilePerms(bool fast_check_in_client
, int denied_errno
) {
81 const char kR_WhiteListed
[] = "/proc/DOESNOTEXIST1";
82 // We can't debug the init process, and shouldn't be able to access
84 const char kR_WhiteListedButDenied
[] = "/proc/1/auxv";
85 const char kW_WhiteListed
[] = "/proc/DOESNOTEXIST2";
86 const char kRW_WhiteListed
[] = "/proc/DOESNOTEXIST3";
87 const char k_NotWhitelisted
[] = "/proc/DOESNOTEXIST4";
89 std::vector
<BrokerFilePermission
> permissions
;
90 permissions
.push_back(BrokerFilePermission::ReadOnly(kR_WhiteListed
));
91 permissions
.push_back(
92 BrokerFilePermission::ReadOnly(kR_WhiteListedButDenied
));
93 permissions
.push_back(BrokerFilePermission::WriteOnly(kW_WhiteListed
));
94 permissions
.push_back(BrokerFilePermission::ReadWrite(kRW_WhiteListed
));
96 BrokerProcess
open_broker(denied_errno
, permissions
, fast_check_in_client
);
97 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
100 fd
= open_broker
.Open(kR_WhiteListed
, O_RDONLY
);
101 ASSERT_EQ(fd
, -ENOENT
);
102 fd
= open_broker
.Open(kR_WhiteListed
, O_WRONLY
);
103 ASSERT_EQ(fd
, -denied_errno
);
104 fd
= open_broker
.Open(kR_WhiteListed
, O_RDWR
);
105 ASSERT_EQ(fd
, -denied_errno
);
107 ret
= open_broker
.Access(kR_WhiteListed
, F_OK
);
108 ASSERT_EQ(ret
, -ENOENT
);
109 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
);
110 ASSERT_EQ(ret
, -ENOENT
);
111 ret
= open_broker
.Access(kR_WhiteListed
, W_OK
);
112 ASSERT_EQ(ret
, -denied_errno
);
113 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| W_OK
);
114 ASSERT_EQ(ret
, -denied_errno
);
115 ret
= open_broker
.Access(kR_WhiteListed
, X_OK
);
116 ASSERT_EQ(ret
, -denied_errno
);
117 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| X_OK
);
118 ASSERT_EQ(ret
, -denied_errno
);
120 // Android sometimes runs tests as root.
121 // This part of the test requires a process that doesn't have
122 // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
124 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDONLY
);
125 // The broker process will allow this, but the normal permission system
127 ASSERT_EQ(fd
, -EACCES
);
128 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_WRONLY
);
129 ASSERT_EQ(fd
, -denied_errno
);
130 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDWR
);
131 ASSERT_EQ(fd
, -denied_errno
);
132 ret
= open_broker
.Access(kR_WhiteListedButDenied
, F_OK
);
133 // The normal permission system will let us check that the file exists.
135 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
);
136 ASSERT_EQ(ret
, -EACCES
);
137 ret
= open_broker
.Access(kR_WhiteListedButDenied
, W_OK
);
138 ASSERT_EQ(ret
, -denied_errno
);
139 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| W_OK
);
140 ASSERT_EQ(ret
, -denied_errno
);
141 ret
= open_broker
.Access(kR_WhiteListedButDenied
, X_OK
);
142 ASSERT_EQ(ret
, -denied_errno
);
143 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| X_OK
);
144 ASSERT_EQ(ret
, -denied_errno
);
147 fd
= open_broker
.Open(kW_WhiteListed
, O_RDONLY
);
148 ASSERT_EQ(fd
, -denied_errno
);
149 fd
= open_broker
.Open(kW_WhiteListed
, O_WRONLY
);
150 ASSERT_EQ(fd
, -ENOENT
);
151 fd
= open_broker
.Open(kW_WhiteListed
, O_RDWR
);
152 ASSERT_EQ(fd
, -denied_errno
);
153 ret
= open_broker
.Access(kW_WhiteListed
, F_OK
);
154 ASSERT_EQ(ret
, -ENOENT
);
155 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
);
156 ASSERT_EQ(ret
, -denied_errno
);
157 ret
= open_broker
.Access(kW_WhiteListed
, W_OK
);
158 ASSERT_EQ(ret
, -ENOENT
);
159 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| W_OK
);
160 ASSERT_EQ(ret
, -denied_errno
);
161 ret
= open_broker
.Access(kW_WhiteListed
, X_OK
);
162 ASSERT_EQ(ret
, -denied_errno
);
163 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| X_OK
);
164 ASSERT_EQ(ret
, -denied_errno
);
166 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
);
167 ASSERT_EQ(fd
, -ENOENT
);
168 fd
= open_broker
.Open(kRW_WhiteListed
, O_WRONLY
);
169 ASSERT_EQ(fd
, -ENOENT
);
170 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
);
171 ASSERT_EQ(fd
, -ENOENT
);
172 ret
= open_broker
.Access(kRW_WhiteListed
, F_OK
);
173 ASSERT_EQ(ret
, -ENOENT
);
174 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
);
175 ASSERT_EQ(ret
, -ENOENT
);
176 ret
= open_broker
.Access(kRW_WhiteListed
, W_OK
);
177 ASSERT_EQ(ret
, -ENOENT
);
178 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| W_OK
);
179 ASSERT_EQ(ret
, -ENOENT
);
180 ret
= open_broker
.Access(kRW_WhiteListed
, X_OK
);
181 ASSERT_EQ(ret
, -denied_errno
);
182 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| X_OK
);
183 ASSERT_EQ(ret
, -denied_errno
);
185 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDONLY
);
186 ASSERT_EQ(fd
, -denied_errno
);
187 fd
= open_broker
.Open(k_NotWhitelisted
, O_WRONLY
);
188 ASSERT_EQ(fd
, -denied_errno
);
189 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDWR
);
190 ASSERT_EQ(fd
, -denied_errno
);
191 ret
= open_broker
.Access(k_NotWhitelisted
, F_OK
);
192 ASSERT_EQ(ret
, -denied_errno
);
193 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
);
194 ASSERT_EQ(ret
, -denied_errno
);
195 ret
= open_broker
.Access(k_NotWhitelisted
, W_OK
);
196 ASSERT_EQ(ret
, -denied_errno
);
197 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| W_OK
);
198 ASSERT_EQ(ret
, -denied_errno
);
199 ret
= open_broker
.Access(k_NotWhitelisted
, X_OK
);
200 ASSERT_EQ(ret
, -denied_errno
);
201 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| X_OK
);
202 ASSERT_EQ(ret
, -denied_errno
);
204 // We have some extra sanity check for clearly wrong values.
205 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
| O_WRONLY
| O_RDWR
);
206 ASSERT_EQ(fd
, -denied_errno
);
208 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
210 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
| O_CREAT
);
211 ASSERT_EQ(fd
, -denied_errno
);
214 // Run the same thing twice. The second time, we make sure that no security
215 // check is performed on the client.
216 TEST(BrokerProcess
, OpenFilePermsWithClientCheck
) {
217 TestOpenFilePerms(true /* fast_check_in_client */, EPERM
);
218 // Don't do anything here, so that ASSERT works in the subfunction as
222 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheck
) {
223 TestOpenFilePerms(false /* fast_check_in_client */, EPERM
);
224 // Don't do anything here, so that ASSERT works in the subfunction as
228 // Run the same twice again, but with ENOENT instead of EPERM.
229 TEST(BrokerProcess
, OpenFilePermsWithClientCheckNoEnt
) {
230 TestOpenFilePerms(true /* fast_check_in_client */, ENOENT
);
231 // Don't do anything here, so that ASSERT works in the subfunction as
235 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheckNoEnt
) {
236 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT
);
237 // Don't do anything here, so that ASSERT works in the subfunction as
241 void TestBadPaths(bool fast_check_in_client
) {
242 const char kFileCpuInfo
[] = "/proc/cpuinfo";
243 const char kNotAbsPath
[] = "proc/cpuinfo";
244 const char kDotDotStart
[] = "/../proc/cpuinfo";
245 const char kDotDotMiddle
[] = "/proc/self/../cpuinfo";
246 const char kDotDotEnd
[] = "/proc/..";
247 const char kTrailingSlash
[] = "/proc/";
249 std::vector
<BrokerFilePermission
> permissions
;
251 permissions
.push_back(BrokerFilePermission::ReadOnlyRecursive("/proc/"));
252 scoped_ptr
<BrokerProcess
> open_broker(
253 new BrokerProcess(EPERM
, permissions
, fast_check_in_client
));
254 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
255 // Open cpuinfo via the broker.
256 int cpuinfo_fd
= open_broker
->Open(kFileCpuInfo
, O_RDONLY
);
257 base::ScopedFD
cpuinfo_fd_closer(cpuinfo_fd
);
258 ASSERT_GE(cpuinfo_fd
, 0);
263 can_access
= open_broker
->Access(kNotAbsPath
, R_OK
);
264 ASSERT_EQ(can_access
, -EPERM
);
265 fd
= open_broker
->Open(kNotAbsPath
, O_RDONLY
);
266 ASSERT_EQ(fd
, -EPERM
);
268 can_access
= open_broker
->Access(kDotDotStart
, R_OK
);
269 ASSERT_EQ(can_access
, -EPERM
);
270 fd
= open_broker
->Open(kDotDotStart
, O_RDONLY
);
271 ASSERT_EQ(fd
, -EPERM
);
273 can_access
= open_broker
->Access(kDotDotMiddle
, R_OK
);
274 ASSERT_EQ(can_access
, -EPERM
);
275 fd
= open_broker
->Open(kDotDotMiddle
, O_RDONLY
);
276 ASSERT_EQ(fd
, -EPERM
);
278 can_access
= open_broker
->Access(kDotDotEnd
, R_OK
);
279 ASSERT_EQ(can_access
, -EPERM
);
280 fd
= open_broker
->Open(kDotDotEnd
, O_RDONLY
);
281 ASSERT_EQ(fd
, -EPERM
);
283 can_access
= open_broker
->Access(kTrailingSlash
, R_OK
);
284 ASSERT_EQ(can_access
, -EPERM
);
285 fd
= open_broker
->Open(kTrailingSlash
, O_RDONLY
);
286 ASSERT_EQ(fd
, -EPERM
);
289 TEST(BrokerProcess
, BadPathsClientCheck
) {
290 TestBadPaths(true /* fast_check_in_client */);
291 // Don't do anything here, so that ASSERT works in the subfunction as
295 TEST(BrokerProcess
, BadPathsNoClientCheck
) {
296 TestBadPaths(false /* fast_check_in_client */);
297 // Don't do anything here, so that ASSERT works in the subfunction as
301 void TestOpenCpuinfo(bool fast_check_in_client
, bool recursive
) {
302 const char kFileCpuInfo
[] = "/proc/cpuinfo";
303 const char kDirProc
[] = "/proc/";
305 std::vector
<BrokerFilePermission
> permissions
;
307 permissions
.push_back(BrokerFilePermission::ReadOnlyRecursive(kDirProc
));
309 permissions
.push_back(BrokerFilePermission::ReadOnly(kFileCpuInfo
));
311 scoped_ptr
<BrokerProcess
> open_broker(
312 new BrokerProcess(EPERM
, permissions
, fast_check_in_client
));
313 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
316 fd
= open_broker
->Open(kFileCpuInfo
, O_RDWR
);
317 base::ScopedFD
fd_closer(fd
);
318 ASSERT_EQ(fd
, -EPERM
);
320 // Check we can read /proc/cpuinfo.
321 int can_access
= open_broker
->Access(kFileCpuInfo
, R_OK
);
322 ASSERT_EQ(can_access
, 0);
323 can_access
= open_broker
->Access(kFileCpuInfo
, W_OK
);
324 ASSERT_EQ(can_access
, -EPERM
);
325 // Check we can not write /proc/cpuinfo.
327 // Open cpuinfo via the broker.
328 int cpuinfo_fd
= open_broker
->Open(kFileCpuInfo
, O_RDONLY
);
329 base::ScopedFD
cpuinfo_fd_closer(cpuinfo_fd
);
330 ASSERT_GE(cpuinfo_fd
, 0);
332 memset(buf
, 0, sizeof(buf
));
333 int read_len1
= read(cpuinfo_fd
, buf
, sizeof(buf
));
334 ASSERT_GT(read_len1
, 0);
336 // Open cpuinfo directly.
337 int cpuinfo_fd2
= open(kFileCpuInfo
, O_RDONLY
);
338 base::ScopedFD
cpuinfo_fd2_closer(cpuinfo_fd2
);
339 ASSERT_GE(cpuinfo_fd2
, 0);
341 memset(buf2
, 1, sizeof(buf2
));
342 int read_len2
= read(cpuinfo_fd2
, buf2
, sizeof(buf2
));
343 ASSERT_GT(read_len1
, 0);
345 // The following is not guaranteed true, but will be in practice.
346 ASSERT_EQ(read_len1
, read_len2
);
347 // Compare the cpuinfo as returned by the broker with the one we opened
349 ASSERT_EQ(memcmp(buf
, buf2
, read_len1
), 0);
351 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
353 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
356 // Run this test 4 times. With and without the check in client
357 // and using a recursive path.
358 TEST(BrokerProcess
, OpenCpuinfoWithClientCheck
) {
359 TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */);
360 // Don't do anything here, so that ASSERT works in the subfunction as
364 TEST(BrokerProcess
, OpenCpuinfoNoClientCheck
) {
365 TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */);
366 // Don't do anything here, so that ASSERT works in the subfunction as
370 TEST(BrokerProcess
, OpenCpuinfoWithClientCheckRecursive
) {
371 TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */);
372 // Don't do anything here, so that ASSERT works in the subfunction as
376 TEST(BrokerProcess
, OpenCpuinfoNoClientCheckRecursive
) {
377 TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */);
378 // Don't do anything here, so that ASSERT works in the subfunction as
382 TEST(BrokerProcess
, OpenFileRW
) {
383 ScopedTemporaryFile tempfile
;
384 const char* tempfile_name
= tempfile
.full_file_name();
386 std::vector
<BrokerFilePermission
> permissions
;
387 permissions
.push_back(BrokerFilePermission::ReadWrite(tempfile_name
));
389 BrokerProcess
open_broker(EPERM
, permissions
);
390 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
392 // Check we can access that file with read or write.
393 int can_access
= open_broker
.Access(tempfile_name
, R_OK
| W_OK
);
394 ASSERT_EQ(can_access
, 0);
397 tempfile2
= open_broker
.Open(tempfile_name
, O_RDWR
);
398 ASSERT_GE(tempfile2
, 0);
400 // Write to the descriptor opened by the broker.
401 char test_text
[] = "TESTTESTTEST";
402 ssize_t len
= write(tempfile2
, test_text
, sizeof(test_text
));
403 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
405 // Read back from the original file descriptor what we wrote through
406 // the descriptor provided by the broker.
408 len
= read(tempfile
.fd(), buf
, sizeof(buf
));
410 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
411 ASSERT_EQ(memcmp(test_text
, buf
, sizeof(test_text
)), 0);
413 ASSERT_EQ(close(tempfile2
), 0);
416 // SANDBOX_TEST because the process could die with a SIGPIPE
417 // and we want this to happen in a subprocess.
418 SANDBOX_TEST(BrokerProcess
, BrokerDied
) {
419 const char kCpuInfo
[] = "/proc/cpuinfo";
420 std::vector
<BrokerFilePermission
> permissions
;
421 permissions
.push_back(BrokerFilePermission::ReadOnly(kCpuInfo
));
423 BrokerProcess
open_broker(EPERM
, permissions
, true /* fast_check_in_client */,
424 true /* quiet_failures_for_tests */);
425 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
426 const pid_t broker_pid
= open_broker
.broker_pid();
427 SANDBOX_ASSERT(kill(broker_pid
, SIGKILL
) == 0);
429 // Now we check that the broker has been signaled, but do not reap it.
430 siginfo_t process_info
;
431 SANDBOX_ASSERT(HANDLE_EINTR(waitid(
432 P_PID
, broker_pid
, &process_info
, WEXITED
| WNOWAIT
)) ==
434 SANDBOX_ASSERT(broker_pid
== process_info
.si_pid
);
435 SANDBOX_ASSERT(CLD_KILLED
== process_info
.si_code
);
436 SANDBOX_ASSERT(SIGKILL
== process_info
.si_status
);
438 // Check that doing Open with a dead broker won't SIGPIPE us.
439 SANDBOX_ASSERT(open_broker
.Open(kCpuInfo
, O_RDONLY
) == -ENOMEM
);
440 SANDBOX_ASSERT(open_broker
.Access(kCpuInfo
, O_RDONLY
) == -ENOMEM
);
443 void TestOpenComplexFlags(bool fast_check_in_client
) {
444 const char kCpuInfo
[] = "/proc/cpuinfo";
445 std::vector
<BrokerFilePermission
> permissions
;
446 permissions
.push_back(BrokerFilePermission::ReadOnly(kCpuInfo
));
448 BrokerProcess
open_broker(EPERM
, permissions
, fast_check_in_client
);
449 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
450 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
453 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
455 ret
= fcntl(fd
, F_GETFL
);
457 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
458 ASSERT_EQ(0, ret
& (O_CLOEXEC
| O_NONBLOCK
));
459 ASSERT_EQ(0, close(fd
));
461 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_CLOEXEC
);
463 ret
= fcntl(fd
, F_GETFD
);
465 // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
466 // is actually not used by the kernel.
467 ASSERT_TRUE(FD_CLOEXEC
& ret
);
468 ASSERT_EQ(0, close(fd
));
470 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_NONBLOCK
);
472 ret
= fcntl(fd
, F_GETFL
);
474 ASSERT_TRUE(O_NONBLOCK
& ret
);
475 ASSERT_EQ(0, close(fd
));
478 TEST(BrokerProcess
, OpenComplexFlagsWithClientCheck
) {
479 TestOpenComplexFlags(true /* fast_check_in_client */);
480 // Don't do anything here, so that ASSERT works in the subfunction as
484 TEST(BrokerProcess
, OpenComplexFlagsNoClientCheck
) {
485 TestOpenComplexFlags(false /* fast_check_in_client */);
486 // Don't do anything here, so that ASSERT works in the subfunction as
490 // We need to allow noise because the broker will log when it receives our
492 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess
, RecvMsgDescriptorLeak
) {
493 // Android creates a socket on first use of the LOG call.
494 // We need to ensure this socket is open before we
496 LOG(INFO
) << "Ensure Android LOG socket is allocated";
498 // Find the four lowest available file descriptors.
499 int available_fds
[4];
500 SANDBOX_ASSERT(0 == pipe(available_fds
));
501 SANDBOX_ASSERT(0 == pipe(available_fds
+ 2));
503 // Save one FD to send to the broker later, and close the others.
504 base::ScopedFD
message_fd(available_fds
[0]);
505 for (size_t i
= 1; i
< arraysize(available_fds
); i
++) {
506 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds
[i
])));
509 // Lower our file descriptor limit to just allow three more file descriptors
510 // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file
511 // descriptors a process can have: it only limits the highest value that can
512 // be assigned to newly-created descriptors allocated by the process.)
513 const rlim_t fd_limit
=
515 *std::max_element(available_fds
,
516 available_fds
+ arraysize(available_fds
));
518 // Valgrind doesn't allow changing the hard descriptor limit, so we only
519 // change the soft descriptor limit here.
521 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE
, &rlim
));
522 SANDBOX_ASSERT(fd_limit
<= rlim
.rlim_cur
);
523 rlim
.rlim_cur
= fd_limit
;
524 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE
, &rlim
));
526 static const char kCpuInfo
[] = "/proc/cpuinfo";
527 std::vector
<BrokerFilePermission
> permissions
;
528 permissions
.push_back(BrokerFilePermission::ReadOnly(kCpuInfo
));
530 BrokerProcess
open_broker(EPERM
, permissions
);
531 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
533 const int ipc_fd
= BrokerProcessTestHelper::GetIPCDescriptor(&open_broker
);
534 SANDBOX_ASSERT(ipc_fd
>= 0);
536 static const char kBogus
[] = "not a pickle";
537 std::vector
<int> fds
;
538 fds
.push_back(message_fd
.get());
540 // The broker process should only have a couple spare file descriptors
541 // available, but for good measure we send it fd_limit bogus IPCs anyway.
542 for (rlim_t i
= 0; i
< fd_limit
; ++i
) {
544 base::UnixDomainSocket::SendMsg(ipc_fd
, kBogus
, sizeof(kBogus
), fds
));
547 const int fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
548 SANDBOX_ASSERT(fd
>= 0);
549 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd
)));
552 bool CloseFD(int fd
) {
553 PCHECK(0 == IGNORE_EINTR(close(fd
)));
557 // Return true if the other end of the |reader| pipe was closed,
558 // false if |timeout_in_seconds| was reached or another event
560 bool WaitForClosedPipeWriter(int reader
, int timeout_in_ms
) {
561 struct pollfd poll_fd
= {reader
, POLLIN
| POLLRDHUP
, 0};
562 const int num_events
= HANDLE_EINTR(poll(&poll_fd
, 1, timeout_in_ms
));
563 if (1 == num_events
&& poll_fd
.revents
| POLLHUP
)
568 // Closing the broker client's IPC channel should terminate the broker
570 TEST(BrokerProcess
, BrokerDiesOnClosedChannel
) {
571 std::vector
<BrokerFilePermission
> permissions
;
572 permissions
.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
574 // Get the writing end of a pipe into the broker (child) process so
575 // that we can reliably detect when it dies.
577 PCHECK(0 == pipe(lifeline_fds
));
579 BrokerProcess
open_broker(EPERM
, permissions
, true /* fast_check_in_client */,
580 false /* quiet_failures_for_tests */);
581 ASSERT_TRUE(open_broker
.Init(base::Bind(&CloseFD
, lifeline_fds
[0])));
582 // Make sure the writing end only exists in the broker process.
583 CloseFD(lifeline_fds
[1]);
584 base::ScopedFD
reader(lifeline_fds
[0]);
586 const pid_t broker_pid
= open_broker
.broker_pid();
588 // This should cause the broker process to exit.
589 BrokerProcessTestHelper::CloseChannel(&open_broker
);
591 const int kTimeoutInMilliseconds
= 5000;
592 const bool broker_lifeline_closed
=
593 WaitForClosedPipeWriter(reader
.get(), kTimeoutInMilliseconds
);
594 // If the broker exited, its lifeline fd should be closed.
595 ASSERT_TRUE(broker_lifeline_closed
);
596 // Now check that the broker has exited, but do not reap it.
597 siginfo_t process_info
;
598 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID
, broker_pid
, &process_info
,
599 WEXITED
| WNOWAIT
)));
600 EXPECT_EQ(broker_pid
, process_info
.si_pid
);
601 EXPECT_EQ(CLD_EXITED
, process_info
.si_code
);
602 EXPECT_EQ(1, process_info
.si_status
);
605 TEST(BrokerProcess
, CreateFile
) {
606 std::string temp_str
;
608 ScopedTemporaryFile tmp_file
;
609 temp_str
= tmp_file
.full_file_name();
611 const char* tempfile_name
= temp_str
.c_str();
613 std::vector
<BrokerFilePermission
> permissions
;
614 permissions
.push_back(BrokerFilePermission::ReadWriteCreate(tempfile_name
));
616 BrokerProcess
open_broker(EPERM
, permissions
);
617 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
621 // Try without O_EXCL
622 fd
= open_broker
.Open(tempfile_name
, O_RDWR
| O_CREAT
);
623 ASSERT_EQ(fd
, -EPERM
);
625 const char kTestText
[] = "TESTTESTTEST";
627 fd
= open_broker
.Open(tempfile_name
, O_RDWR
| O_CREAT
| O_EXCL
);
630 base::ScopedFD
scoped_fd(fd
);
632 // Confirm fail if file exists
633 int bad_fd
= open_broker
.Open(tempfile_name
, O_RDWR
| O_CREAT
| O_EXCL
);
634 ASSERT_EQ(bad_fd
, -EEXIST
);
636 // Write to the descriptor opened by the broker.
638 ssize_t len
= HANDLE_EINTR(write(fd
, kTestText
, sizeof(kTestText
)));
639 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(kTestText
)));
642 int fd_check
= open(tempfile_name
, O_RDONLY
);
643 ASSERT_GE(fd_check
, 0);
645 base::ScopedFD
scoped_fd(fd_check
);
647 ssize_t len
= HANDLE_EINTR(read(fd_check
, buf
, sizeof(buf
)));
649 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(kTestText
)));
650 ASSERT_EQ(memcmp(kTestText
, buf
, sizeof(kTestText
)), 0);
654 } // namespace syscall_broker
656 } // namespace sandbox