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/basictypes.h"
21 #include "base/bind.h"
22 #include "base/files/file_util.h"
23 #include "base/files/scoped_file.h"
24 #include "base/logging.h"
25 #include "base/memory/scoped_ptr.h"
26 #include "base/posix/eintr_wrapper.h"
27 #include "base/posix/unix_domain_socket_linux.h"
28 #include "sandbox/linux/syscall_broker/broker_client.h"
29 #include "sandbox/linux/tests/scoped_temporary_file.h"
30 #include "sandbox/linux/tests/test_utils.h"
31 #include "sandbox/linux/tests/unit_tests.h"
32 #include "testing/gtest/include/gtest/gtest.h"
36 namespace syscall_broker
{
38 class BrokerProcessTestHelper
{
40 static void CloseChannel(BrokerProcess
* broker
) { broker
->CloseChannel(); }
41 // Get the client's IPC descriptor to send IPC requests directly.
42 // TODO(jln): refator tests to get rid of this.
43 static int GetIPCDescriptor(const BrokerProcess
* broker
) {
44 return broker
->broker_client_
->GetIPCDescriptor();
56 TEST(BrokerProcess
, CreateAndDestroy
) {
57 std::vector
<BrokerFilePermission
> permissions
;
58 permissions
.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
60 scoped_ptr
<BrokerProcess
> open_broker(new BrokerProcess(EPERM
, permissions
));
61 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
63 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
64 // Destroy the broker and check it has exited properly.
66 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
69 TEST(BrokerProcess
, TestOpenAccessNull
) {
70 std::vector
<BrokerFilePermission
> empty
;
71 BrokerProcess
open_broker(EPERM
, empty
);
72 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
74 int fd
= open_broker
.Open(NULL
, O_RDONLY
);
75 ASSERT_EQ(fd
, -EFAULT
);
77 int ret
= open_broker
.Access(NULL
, F_OK
);
78 ASSERT_EQ(ret
, -EFAULT
);
81 void TestOpenFilePerms(bool fast_check_in_client
, int denied_errno
) {
82 const char kR_WhiteListed
[] = "/proc/DOESNOTEXIST1";
83 // We can't debug the init process, and shouldn't be able to access
85 const char kR_WhiteListedButDenied
[] = "/proc/1/auxv";
86 const char kW_WhiteListed
[] = "/proc/DOESNOTEXIST2";
87 const char kRW_WhiteListed
[] = "/proc/DOESNOTEXIST3";
88 const char k_NotWhitelisted
[] = "/proc/DOESNOTEXIST4";
90 std::vector
<BrokerFilePermission
> permissions
;
91 permissions
.push_back(BrokerFilePermission::ReadOnly(kR_WhiteListed
));
92 permissions
.push_back(
93 BrokerFilePermission::ReadOnly(kR_WhiteListedButDenied
));
94 permissions
.push_back(BrokerFilePermission::WriteOnly(kW_WhiteListed
));
95 permissions
.push_back(BrokerFilePermission::ReadWrite(kRW_WhiteListed
));
97 BrokerProcess
open_broker(denied_errno
, permissions
, fast_check_in_client
);
98 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
101 fd
= open_broker
.Open(kR_WhiteListed
, O_RDONLY
);
102 ASSERT_EQ(fd
, -ENOENT
);
103 fd
= open_broker
.Open(kR_WhiteListed
, O_WRONLY
);
104 ASSERT_EQ(fd
, -denied_errno
);
105 fd
= open_broker
.Open(kR_WhiteListed
, O_RDWR
);
106 ASSERT_EQ(fd
, -denied_errno
);
108 ret
= open_broker
.Access(kR_WhiteListed
, F_OK
);
109 ASSERT_EQ(ret
, -ENOENT
);
110 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
);
111 ASSERT_EQ(ret
, -ENOENT
);
112 ret
= open_broker
.Access(kR_WhiteListed
, W_OK
);
113 ASSERT_EQ(ret
, -denied_errno
);
114 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| W_OK
);
115 ASSERT_EQ(ret
, -denied_errno
);
116 ret
= open_broker
.Access(kR_WhiteListed
, X_OK
);
117 ASSERT_EQ(ret
, -denied_errno
);
118 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| X_OK
);
119 ASSERT_EQ(ret
, -denied_errno
);
121 // Android sometimes runs tests as root.
122 // This part of the test requires a process that doesn't have
123 // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
125 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDONLY
);
126 // The broker process will allow this, but the normal permission system
128 ASSERT_EQ(fd
, -EACCES
);
129 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_WRONLY
);
130 ASSERT_EQ(fd
, -denied_errno
);
131 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDWR
);
132 ASSERT_EQ(fd
, -denied_errno
);
133 ret
= open_broker
.Access(kR_WhiteListedButDenied
, F_OK
);
134 // The normal permission system will let us check that the file exists.
136 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
);
137 ASSERT_EQ(ret
, -EACCES
);
138 ret
= open_broker
.Access(kR_WhiteListedButDenied
, W_OK
);
139 ASSERT_EQ(ret
, -denied_errno
);
140 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| W_OK
);
141 ASSERT_EQ(ret
, -denied_errno
);
142 ret
= open_broker
.Access(kR_WhiteListedButDenied
, X_OK
);
143 ASSERT_EQ(ret
, -denied_errno
);
144 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| X_OK
);
145 ASSERT_EQ(ret
, -denied_errno
);
148 fd
= open_broker
.Open(kW_WhiteListed
, O_RDONLY
);
149 ASSERT_EQ(fd
, -denied_errno
);
150 fd
= open_broker
.Open(kW_WhiteListed
, O_WRONLY
);
151 ASSERT_EQ(fd
, -ENOENT
);
152 fd
= open_broker
.Open(kW_WhiteListed
, O_RDWR
);
153 ASSERT_EQ(fd
, -denied_errno
);
154 ret
= open_broker
.Access(kW_WhiteListed
, F_OK
);
155 ASSERT_EQ(ret
, -ENOENT
);
156 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
);
157 ASSERT_EQ(ret
, -denied_errno
);
158 ret
= open_broker
.Access(kW_WhiteListed
, W_OK
);
159 ASSERT_EQ(ret
, -ENOENT
);
160 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| W_OK
);
161 ASSERT_EQ(ret
, -denied_errno
);
162 ret
= open_broker
.Access(kW_WhiteListed
, X_OK
);
163 ASSERT_EQ(ret
, -denied_errno
);
164 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| X_OK
);
165 ASSERT_EQ(ret
, -denied_errno
);
167 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
);
168 ASSERT_EQ(fd
, -ENOENT
);
169 fd
= open_broker
.Open(kRW_WhiteListed
, O_WRONLY
);
170 ASSERT_EQ(fd
, -ENOENT
);
171 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
);
172 ASSERT_EQ(fd
, -ENOENT
);
173 ret
= open_broker
.Access(kRW_WhiteListed
, F_OK
);
174 ASSERT_EQ(ret
, -ENOENT
);
175 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
);
176 ASSERT_EQ(ret
, -ENOENT
);
177 ret
= open_broker
.Access(kRW_WhiteListed
, W_OK
);
178 ASSERT_EQ(ret
, -ENOENT
);
179 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| W_OK
);
180 ASSERT_EQ(ret
, -ENOENT
);
181 ret
= open_broker
.Access(kRW_WhiteListed
, X_OK
);
182 ASSERT_EQ(ret
, -denied_errno
);
183 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| X_OK
);
184 ASSERT_EQ(ret
, -denied_errno
);
186 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDONLY
);
187 ASSERT_EQ(fd
, -denied_errno
);
188 fd
= open_broker
.Open(k_NotWhitelisted
, O_WRONLY
);
189 ASSERT_EQ(fd
, -denied_errno
);
190 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDWR
);
191 ASSERT_EQ(fd
, -denied_errno
);
192 ret
= open_broker
.Access(k_NotWhitelisted
, F_OK
);
193 ASSERT_EQ(ret
, -denied_errno
);
194 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
);
195 ASSERT_EQ(ret
, -denied_errno
);
196 ret
= open_broker
.Access(k_NotWhitelisted
, W_OK
);
197 ASSERT_EQ(ret
, -denied_errno
);
198 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| W_OK
);
199 ASSERT_EQ(ret
, -denied_errno
);
200 ret
= open_broker
.Access(k_NotWhitelisted
, X_OK
);
201 ASSERT_EQ(ret
, -denied_errno
);
202 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| X_OK
);
203 ASSERT_EQ(ret
, -denied_errno
);
205 // We have some extra sanity check for clearly wrong values.
206 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
| O_WRONLY
| O_RDWR
);
207 ASSERT_EQ(fd
, -denied_errno
);
209 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
211 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
| O_CREAT
);
212 ASSERT_EQ(fd
, -denied_errno
);
215 // Run the same thing twice. The second time, we make sure that no security
216 // check is performed on the client.
217 TEST(BrokerProcess
, OpenFilePermsWithClientCheck
) {
218 TestOpenFilePerms(true /* fast_check_in_client */, EPERM
);
219 // Don't do anything here, so that ASSERT works in the subfunction as
223 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheck
) {
224 TestOpenFilePerms(false /* fast_check_in_client */, EPERM
);
225 // Don't do anything here, so that ASSERT works in the subfunction as
229 // Run the same twice again, but with ENOENT instead of EPERM.
230 TEST(BrokerProcess
, OpenFilePermsWithClientCheckNoEnt
) {
231 TestOpenFilePerms(true /* fast_check_in_client */, ENOENT
);
232 // Don't do anything here, so that ASSERT works in the subfunction as
236 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheckNoEnt
) {
237 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT
);
238 // Don't do anything here, so that ASSERT works in the subfunction as
242 void TestBadPaths(bool fast_check_in_client
) {
243 const char kFileCpuInfo
[] = "/proc/cpuinfo";
244 const char kNotAbsPath
[] = "proc/cpuinfo";
245 const char kDotDotStart
[] = "/../proc/cpuinfo";
246 const char kDotDotMiddle
[] = "/proc/self/../cpuinfo";
247 const char kDotDotEnd
[] = "/proc/..";
248 const char kTrailingSlash
[] = "/proc/";
250 std::vector
<BrokerFilePermission
> permissions
;
252 permissions
.push_back(BrokerFilePermission::ReadOnlyRecursive("/proc/"));
253 scoped_ptr
<BrokerProcess
> open_broker(
254 new BrokerProcess(EPERM
, permissions
, fast_check_in_client
));
255 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
256 // Open cpuinfo via the broker.
257 int cpuinfo_fd
= open_broker
->Open(kFileCpuInfo
, O_RDONLY
);
258 base::ScopedFD
cpuinfo_fd_closer(cpuinfo_fd
);
259 ASSERT_GE(cpuinfo_fd
, 0);
264 can_access
= open_broker
->Access(kNotAbsPath
, R_OK
);
265 ASSERT_EQ(can_access
, -EPERM
);
266 fd
= open_broker
->Open(kNotAbsPath
, O_RDONLY
);
267 ASSERT_EQ(fd
, -EPERM
);
269 can_access
= open_broker
->Access(kDotDotStart
, R_OK
);
270 ASSERT_EQ(can_access
, -EPERM
);
271 fd
= open_broker
->Open(kDotDotStart
, O_RDONLY
);
272 ASSERT_EQ(fd
, -EPERM
);
274 can_access
= open_broker
->Access(kDotDotMiddle
, R_OK
);
275 ASSERT_EQ(can_access
, -EPERM
);
276 fd
= open_broker
->Open(kDotDotMiddle
, O_RDONLY
);
277 ASSERT_EQ(fd
, -EPERM
);
279 can_access
= open_broker
->Access(kDotDotEnd
, R_OK
);
280 ASSERT_EQ(can_access
, -EPERM
);
281 fd
= open_broker
->Open(kDotDotEnd
, O_RDONLY
);
282 ASSERT_EQ(fd
, -EPERM
);
284 can_access
= open_broker
->Access(kTrailingSlash
, R_OK
);
285 ASSERT_EQ(can_access
, -EPERM
);
286 fd
= open_broker
->Open(kTrailingSlash
, O_RDONLY
);
287 ASSERT_EQ(fd
, -EPERM
);
290 TEST(BrokerProcess
, BadPathsClientCheck
) {
291 TestBadPaths(true /* fast_check_in_client */);
292 // Don't do anything here, so that ASSERT works in the subfunction as
296 TEST(BrokerProcess
, BadPathsNoClientCheck
) {
297 TestBadPaths(false /* fast_check_in_client */);
298 // Don't do anything here, so that ASSERT works in the subfunction as
302 void TestOpenCpuinfo(bool fast_check_in_client
, bool recursive
) {
303 const char kFileCpuInfo
[] = "/proc/cpuinfo";
304 const char kDirProc
[] = "/proc/";
306 std::vector
<BrokerFilePermission
> permissions
;
308 permissions
.push_back(BrokerFilePermission::ReadOnlyRecursive(kDirProc
));
310 permissions
.push_back(BrokerFilePermission::ReadOnly(kFileCpuInfo
));
312 scoped_ptr
<BrokerProcess
> open_broker(
313 new BrokerProcess(EPERM
, permissions
, fast_check_in_client
));
314 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
317 fd
= open_broker
->Open(kFileCpuInfo
, O_RDWR
);
318 base::ScopedFD
fd_closer(fd
);
319 ASSERT_EQ(fd
, -EPERM
);
321 // Check we can read /proc/cpuinfo.
322 int can_access
= open_broker
->Access(kFileCpuInfo
, R_OK
);
323 ASSERT_EQ(can_access
, 0);
324 can_access
= open_broker
->Access(kFileCpuInfo
, W_OK
);
325 ASSERT_EQ(can_access
, -EPERM
);
326 // Check we can not write /proc/cpuinfo.
328 // Open cpuinfo via the broker.
329 int cpuinfo_fd
= open_broker
->Open(kFileCpuInfo
, O_RDONLY
);
330 base::ScopedFD
cpuinfo_fd_closer(cpuinfo_fd
);
331 ASSERT_GE(cpuinfo_fd
, 0);
333 memset(buf
, 0, sizeof(buf
));
334 int read_len1
= read(cpuinfo_fd
, buf
, sizeof(buf
));
335 ASSERT_GT(read_len1
, 0);
337 // Open cpuinfo directly.
338 int cpuinfo_fd2
= open(kFileCpuInfo
, O_RDONLY
);
339 base::ScopedFD
cpuinfo_fd2_closer(cpuinfo_fd2
);
340 ASSERT_GE(cpuinfo_fd2
, 0);
342 memset(buf2
, 1, sizeof(buf2
));
343 int read_len2
= read(cpuinfo_fd2
, buf2
, sizeof(buf2
));
344 ASSERT_GT(read_len1
, 0);
346 // The following is not guaranteed true, but will be in practice.
347 ASSERT_EQ(read_len1
, read_len2
);
348 // Compare the cpuinfo as returned by the broker with the one we opened
350 ASSERT_EQ(memcmp(buf
, buf2
, read_len1
), 0);
352 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
354 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
357 // Run this test 4 times. With and without the check in client
358 // and using a recursive path.
359 TEST(BrokerProcess
, OpenCpuinfoWithClientCheck
) {
360 TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */);
361 // Don't do anything here, so that ASSERT works in the subfunction as
365 TEST(BrokerProcess
, OpenCpuinfoNoClientCheck
) {
366 TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */);
367 // Don't do anything here, so that ASSERT works in the subfunction as
371 TEST(BrokerProcess
, OpenCpuinfoWithClientCheckRecursive
) {
372 TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */);
373 // Don't do anything here, so that ASSERT works in the subfunction as
377 TEST(BrokerProcess
, OpenCpuinfoNoClientCheckRecursive
) {
378 TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */);
379 // Don't do anything here, so that ASSERT works in the subfunction as
383 TEST(BrokerProcess
, OpenFileRW
) {
384 ScopedTemporaryFile tempfile
;
385 const char* tempfile_name
= tempfile
.full_file_name();
387 std::vector
<BrokerFilePermission
> permissions
;
388 permissions
.push_back(BrokerFilePermission::ReadWrite(tempfile_name
));
390 BrokerProcess
open_broker(EPERM
, permissions
);
391 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
393 // Check we can access that file with read or write.
394 int can_access
= open_broker
.Access(tempfile_name
, R_OK
| W_OK
);
395 ASSERT_EQ(can_access
, 0);
398 tempfile2
= open_broker
.Open(tempfile_name
, O_RDWR
);
399 ASSERT_GE(tempfile2
, 0);
401 // Write to the descriptor opened by the broker.
402 char test_text
[] = "TESTTESTTEST";
403 ssize_t len
= write(tempfile2
, test_text
, sizeof(test_text
));
404 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
406 // Read back from the original file descriptor what we wrote through
407 // the descriptor provided by the broker.
409 len
= read(tempfile
.fd(), buf
, sizeof(buf
));
411 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
412 ASSERT_EQ(memcmp(test_text
, buf
, sizeof(test_text
)), 0);
414 ASSERT_EQ(close(tempfile2
), 0);
417 // SANDBOX_TEST because the process could die with a SIGPIPE
418 // and we want this to happen in a subprocess.
419 SANDBOX_TEST(BrokerProcess
, BrokerDied
) {
420 const char kCpuInfo
[] = "/proc/cpuinfo";
421 std::vector
<BrokerFilePermission
> permissions
;
422 permissions
.push_back(BrokerFilePermission::ReadOnly(kCpuInfo
));
424 BrokerProcess
open_broker(EPERM
, permissions
, true /* fast_check_in_client */,
425 true /* quiet_failures_for_tests */);
426 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
427 const pid_t broker_pid
= open_broker
.broker_pid();
428 SANDBOX_ASSERT(kill(broker_pid
, SIGKILL
) == 0);
430 // Now we check that the broker has been signaled, but do not reap it.
431 siginfo_t process_info
;
432 SANDBOX_ASSERT(HANDLE_EINTR(waitid(
433 P_PID
, broker_pid
, &process_info
, WEXITED
| WNOWAIT
)) ==
435 SANDBOX_ASSERT(broker_pid
== process_info
.si_pid
);
436 SANDBOX_ASSERT(CLD_KILLED
== process_info
.si_code
);
437 SANDBOX_ASSERT(SIGKILL
== process_info
.si_status
);
439 // Check that doing Open with a dead broker won't SIGPIPE us.
440 SANDBOX_ASSERT(open_broker
.Open(kCpuInfo
, O_RDONLY
) == -ENOMEM
);
441 SANDBOX_ASSERT(open_broker
.Access(kCpuInfo
, O_RDONLY
) == -ENOMEM
);
444 void TestOpenComplexFlags(bool fast_check_in_client
) {
445 const char kCpuInfo
[] = "/proc/cpuinfo";
446 std::vector
<BrokerFilePermission
> permissions
;
447 permissions
.push_back(BrokerFilePermission::ReadOnly(kCpuInfo
));
449 BrokerProcess
open_broker(EPERM
, permissions
, fast_check_in_client
);
450 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
451 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
454 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
456 ret
= fcntl(fd
, F_GETFL
);
458 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
459 ASSERT_EQ(0, ret
& (O_CLOEXEC
| O_NONBLOCK
));
460 ASSERT_EQ(0, close(fd
));
462 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_CLOEXEC
);
464 ret
= fcntl(fd
, F_GETFD
);
466 // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
467 // is actually not used by the kernel.
468 ASSERT_TRUE(FD_CLOEXEC
& ret
);
469 ASSERT_EQ(0, close(fd
));
471 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_NONBLOCK
);
473 ret
= fcntl(fd
, F_GETFL
);
475 ASSERT_TRUE(O_NONBLOCK
& ret
);
476 ASSERT_EQ(0, close(fd
));
479 TEST(BrokerProcess
, OpenComplexFlagsWithClientCheck
) {
480 TestOpenComplexFlags(true /* fast_check_in_client */);
481 // Don't do anything here, so that ASSERT works in the subfunction as
485 TEST(BrokerProcess
, OpenComplexFlagsNoClientCheck
) {
486 TestOpenComplexFlags(false /* fast_check_in_client */);
487 // Don't do anything here, so that ASSERT works in the subfunction as
491 // We need to allow noise because the broker will log when it receives our
493 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess
, RecvMsgDescriptorLeak
) {
494 // Android creates a socket on first use of the LOG call.
495 // We need to ensure this socket is open before we
497 LOG(INFO
) << "Ensure Android LOG socket is allocated";
499 // Find the four lowest available file descriptors.
500 int available_fds
[4];
501 SANDBOX_ASSERT(0 == pipe(available_fds
));
502 SANDBOX_ASSERT(0 == pipe(available_fds
+ 2));
504 // Save one FD to send to the broker later, and close the others.
505 base::ScopedFD
message_fd(available_fds
[0]);
506 for (size_t i
= 1; i
< arraysize(available_fds
); i
++) {
507 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds
[i
])));
510 // Lower our file descriptor limit to just allow three more file descriptors
511 // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file
512 // descriptors a process can have: it only limits the highest value that can
513 // be assigned to newly-created descriptors allocated by the process.)
514 const rlim_t fd_limit
=
516 *std::max_element(available_fds
,
517 available_fds
+ arraysize(available_fds
));
519 // Valgrind doesn't allow changing the hard descriptor limit, so we only
520 // change the soft descriptor limit here.
522 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE
, &rlim
));
523 SANDBOX_ASSERT(fd_limit
<= rlim
.rlim_cur
);
524 rlim
.rlim_cur
= fd_limit
;
525 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE
, &rlim
));
527 static const char kCpuInfo
[] = "/proc/cpuinfo";
528 std::vector
<BrokerFilePermission
> permissions
;
529 permissions
.push_back(BrokerFilePermission::ReadOnly(kCpuInfo
));
531 BrokerProcess
open_broker(EPERM
, permissions
);
532 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
534 const int ipc_fd
= BrokerProcessTestHelper::GetIPCDescriptor(&open_broker
);
535 SANDBOX_ASSERT(ipc_fd
>= 0);
537 static const char kBogus
[] = "not a pickle";
538 std::vector
<int> fds
;
539 fds
.push_back(message_fd
.get());
541 // The broker process should only have a couple spare file descriptors
542 // available, but for good measure we send it fd_limit bogus IPCs anyway.
543 for (rlim_t i
= 0; i
< fd_limit
; ++i
) {
545 UnixDomainSocket::SendMsg(ipc_fd
, kBogus
, sizeof(kBogus
), fds
));
548 const int fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
549 SANDBOX_ASSERT(fd
>= 0);
550 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd
)));
553 bool CloseFD(int fd
) {
554 PCHECK(0 == IGNORE_EINTR(close(fd
)));
558 // Return true if the other end of the |reader| pipe was closed,
559 // false if |timeout_in_seconds| was reached or another event
561 bool WaitForClosedPipeWriter(int reader
, int timeout_in_ms
) {
562 struct pollfd poll_fd
= {reader
, POLLIN
| POLLRDHUP
, 0};
563 const int num_events
= HANDLE_EINTR(poll(&poll_fd
, 1, timeout_in_ms
));
564 if (1 == num_events
&& poll_fd
.revents
| POLLHUP
)
569 // Closing the broker client's IPC channel should terminate the broker
571 TEST(BrokerProcess
, BrokerDiesOnClosedChannel
) {
572 std::vector
<BrokerFilePermission
> permissions
;
573 permissions
.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
575 // Get the writing end of a pipe into the broker (child) process so
576 // that we can reliably detect when it dies.
578 PCHECK(0 == pipe(lifeline_fds
));
580 BrokerProcess
open_broker(EPERM
, permissions
, true /* fast_check_in_client */,
581 false /* quiet_failures_for_tests */);
582 ASSERT_TRUE(open_broker
.Init(base::Bind(&CloseFD
, lifeline_fds
[0])));
583 // Make sure the writing end only exists in the broker process.
584 CloseFD(lifeline_fds
[1]);
585 base::ScopedFD
reader(lifeline_fds
[0]);
587 const pid_t broker_pid
= open_broker
.broker_pid();
589 // This should cause the broker process to exit.
590 BrokerProcessTestHelper::CloseChannel(&open_broker
);
592 const int kTimeoutInMilliseconds
= 5000;
593 const bool broker_lifeline_closed
=
594 WaitForClosedPipeWriter(reader
.get(), kTimeoutInMilliseconds
);
595 // If the broker exited, its lifeline fd should be closed.
596 ASSERT_TRUE(broker_lifeline_closed
);
597 // Now check that the broker has exited, but do not reap it.
598 siginfo_t process_info
;
599 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID
, broker_pid
, &process_info
,
600 WEXITED
| WNOWAIT
)));
601 EXPECT_EQ(broker_pid
, process_info
.si_pid
);
602 EXPECT_EQ(CLD_EXITED
, process_info
.si_code
);
603 EXPECT_EQ(1, process_info
.si_status
);
606 TEST(BrokerProcess
, CreateFile
) {
607 std::string temp_str
;
609 ScopedTemporaryFile tmp_file
;
610 temp_str
= tmp_file
.full_file_name();
612 const char* tempfile_name
= temp_str
.c_str();
614 std::vector
<BrokerFilePermission
> permissions
;
615 permissions
.push_back(BrokerFilePermission::ReadWriteCreate(tempfile_name
));
617 BrokerProcess
open_broker(EPERM
, permissions
);
618 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
622 // Try without O_EXCL
623 fd
= open_broker
.Open(tempfile_name
, O_RDWR
| O_CREAT
);
624 ASSERT_EQ(fd
, -EPERM
);
626 const char kTestText
[] = "TESTTESTTEST";
628 fd
= open_broker
.Open(tempfile_name
, O_RDWR
| O_CREAT
| O_EXCL
);
631 base::ScopedFD
scoped_fd(fd
);
633 // Confirm fail if file exists
634 int bad_fd
= open_broker
.Open(tempfile_name
, O_RDWR
| O_CREAT
| O_EXCL
);
635 ASSERT_EQ(bad_fd
, -EEXIST
);
637 // Write to the descriptor opened by the broker.
639 ssize_t len
= HANDLE_EINTR(write(fd
, kTestText
, sizeof(kTestText
)));
640 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(kTestText
)));
643 int fd_check
= open(tempfile_name
, O_RDONLY
);
644 ASSERT_GE(fd_check
, 0);
646 base::ScopedFD
scoped_fd(fd_check
);
648 ssize_t len
= HANDLE_EINTR(read(fd_check
, buf
, sizeof(buf
)));
650 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(kTestText
)));
651 ASSERT_EQ(memcmp(kTestText
, buf
, sizeof(kTestText
)), 0);
655 } // namespace syscall_broker
657 } // namespace sandbox