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
<std::string
> read_whitelist
;
58 read_whitelist
.push_back("/proc/cpuinfo");
60 scoped_ptr
<BrokerProcess
> open_broker(
61 new BrokerProcess(EPERM
, read_whitelist
, std::vector
<std::string
>()));
62 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
64 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
65 // Destroy the broker and check it has exited properly.
67 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
70 TEST(BrokerProcess
, TestOpenAccessNull
) {
71 const std::vector
<std::string
> empty
;
72 BrokerProcess
open_broker(EPERM
, empty
, empty
);
73 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
75 int fd
= open_broker
.Open(NULL
, O_RDONLY
);
76 ASSERT_EQ(fd
, -EFAULT
);
78 int ret
= open_broker
.Access(NULL
, F_OK
);
79 ASSERT_EQ(ret
, -EFAULT
);
82 void TestOpenFilePerms(bool fast_check_in_client
, int denied_errno
) {
83 const char kR_WhiteListed
[] = "/proc/DOESNOTEXIST1";
84 // We can't debug the init process, and shouldn't be able to access
86 const char kR_WhiteListedButDenied
[] = "/proc/1/auxv";
87 const char kW_WhiteListed
[] = "/proc/DOESNOTEXIST2";
88 const char kRW_WhiteListed
[] = "/proc/DOESNOTEXIST3";
89 const char k_NotWhitelisted
[] = "/proc/DOESNOTEXIST4";
91 std::vector
<std::string
> read_whitelist
;
92 read_whitelist
.push_back(kR_WhiteListed
);
93 read_whitelist
.push_back(kR_WhiteListedButDenied
);
94 read_whitelist
.push_back(kRW_WhiteListed
);
96 std::vector
<std::string
> write_whitelist
;
97 write_whitelist
.push_back(kW_WhiteListed
);
98 write_whitelist
.push_back(kRW_WhiteListed
);
100 BrokerProcess
open_broker(
101 denied_errno
, read_whitelist
, write_whitelist
, fast_check_in_client
);
102 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
105 fd
= open_broker
.Open(kR_WhiteListed
, O_RDONLY
);
106 ASSERT_EQ(fd
, -ENOENT
);
107 fd
= open_broker
.Open(kR_WhiteListed
, O_WRONLY
);
108 ASSERT_EQ(fd
, -denied_errno
);
109 fd
= open_broker
.Open(kR_WhiteListed
, O_RDWR
);
110 ASSERT_EQ(fd
, -denied_errno
);
112 ret
= open_broker
.Access(kR_WhiteListed
, F_OK
);
113 ASSERT_EQ(ret
, -ENOENT
);
114 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
);
115 ASSERT_EQ(ret
, -ENOENT
);
116 ret
= open_broker
.Access(kR_WhiteListed
, W_OK
);
117 ASSERT_EQ(ret
, -denied_errno
);
118 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| W_OK
);
119 ASSERT_EQ(ret
, -denied_errno
);
120 ret
= open_broker
.Access(kR_WhiteListed
, X_OK
);
121 ASSERT_EQ(ret
, -denied_errno
);
122 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| X_OK
);
123 ASSERT_EQ(ret
, -denied_errno
);
125 // Android sometimes runs tests as root.
126 // This part of the test requires a process that doesn't have
127 // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
129 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDONLY
);
130 // The broker process will allow this, but the normal permission system
132 ASSERT_EQ(fd
, -EACCES
);
133 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_WRONLY
);
134 ASSERT_EQ(fd
, -denied_errno
);
135 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDWR
);
136 ASSERT_EQ(fd
, -denied_errno
);
137 ret
= open_broker
.Access(kR_WhiteListedButDenied
, F_OK
);
138 // The normal permission system will let us check that the file exists.
140 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
);
141 ASSERT_EQ(ret
, -EACCES
);
142 ret
= open_broker
.Access(kR_WhiteListedButDenied
, W_OK
);
143 ASSERT_EQ(ret
, -denied_errno
);
144 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| W_OK
);
145 ASSERT_EQ(ret
, -denied_errno
);
146 ret
= open_broker
.Access(kR_WhiteListedButDenied
, X_OK
);
147 ASSERT_EQ(ret
, -denied_errno
);
148 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| X_OK
);
149 ASSERT_EQ(ret
, -denied_errno
);
152 fd
= open_broker
.Open(kW_WhiteListed
, O_RDONLY
);
153 ASSERT_EQ(fd
, -denied_errno
);
154 fd
= open_broker
.Open(kW_WhiteListed
, O_WRONLY
);
155 ASSERT_EQ(fd
, -ENOENT
);
156 fd
= open_broker
.Open(kW_WhiteListed
, O_RDWR
);
157 ASSERT_EQ(fd
, -denied_errno
);
158 ret
= open_broker
.Access(kW_WhiteListed
, F_OK
);
159 ASSERT_EQ(ret
, -ENOENT
);
160 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
);
161 ASSERT_EQ(ret
, -denied_errno
);
162 ret
= open_broker
.Access(kW_WhiteListed
, W_OK
);
163 ASSERT_EQ(ret
, -ENOENT
);
164 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| W_OK
);
165 ASSERT_EQ(ret
, -denied_errno
);
166 ret
= open_broker
.Access(kW_WhiteListed
, X_OK
);
167 ASSERT_EQ(ret
, -denied_errno
);
168 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| X_OK
);
169 ASSERT_EQ(ret
, -denied_errno
);
171 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
);
172 ASSERT_EQ(fd
, -ENOENT
);
173 fd
= open_broker
.Open(kRW_WhiteListed
, O_WRONLY
);
174 ASSERT_EQ(fd
, -ENOENT
);
175 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
);
176 ASSERT_EQ(fd
, -ENOENT
);
177 ret
= open_broker
.Access(kRW_WhiteListed
, F_OK
);
178 ASSERT_EQ(ret
, -ENOENT
);
179 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
);
180 ASSERT_EQ(ret
, -ENOENT
);
181 ret
= open_broker
.Access(kRW_WhiteListed
, W_OK
);
182 ASSERT_EQ(ret
, -ENOENT
);
183 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| W_OK
);
184 ASSERT_EQ(ret
, -ENOENT
);
185 ret
= open_broker
.Access(kRW_WhiteListed
, X_OK
);
186 ASSERT_EQ(ret
, -denied_errno
);
187 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| X_OK
);
188 ASSERT_EQ(ret
, -denied_errno
);
190 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDONLY
);
191 ASSERT_EQ(fd
, -denied_errno
);
192 fd
= open_broker
.Open(k_NotWhitelisted
, O_WRONLY
);
193 ASSERT_EQ(fd
, -denied_errno
);
194 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDWR
);
195 ASSERT_EQ(fd
, -denied_errno
);
196 ret
= open_broker
.Access(k_NotWhitelisted
, F_OK
);
197 ASSERT_EQ(ret
, -denied_errno
);
198 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
);
199 ASSERT_EQ(ret
, -denied_errno
);
200 ret
= open_broker
.Access(k_NotWhitelisted
, W_OK
);
201 ASSERT_EQ(ret
, -denied_errno
);
202 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| W_OK
);
203 ASSERT_EQ(ret
, -denied_errno
);
204 ret
= open_broker
.Access(k_NotWhitelisted
, X_OK
);
205 ASSERT_EQ(ret
, -denied_errno
);
206 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| X_OK
);
207 ASSERT_EQ(ret
, -denied_errno
);
209 // We have some extra sanity check for clearly wrong values.
210 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
| O_WRONLY
| O_RDWR
);
211 ASSERT_EQ(fd
, -denied_errno
);
213 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
215 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
| O_CREAT
);
216 ASSERT_EQ(fd
, -denied_errno
);
219 // Run the same thing twice. The second time, we make sure that no security
220 // check is performed on the client.
221 TEST(BrokerProcess
, OpenFilePermsWithClientCheck
) {
222 TestOpenFilePerms(true /* fast_check_in_client */, EPERM
);
223 // Don't do anything here, so that ASSERT works in the subfunction as
227 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheck
) {
228 TestOpenFilePerms(false /* fast_check_in_client */, EPERM
);
229 // Don't do anything here, so that ASSERT works in the subfunction as
233 // Run the same twice again, but with ENOENT instead of EPERM.
234 TEST(BrokerProcess
, OpenFilePermsWithClientCheckNoEnt
) {
235 TestOpenFilePerms(true /* fast_check_in_client */, ENOENT
);
236 // Don't do anything here, so that ASSERT works in the subfunction as
240 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheckNoEnt
) {
241 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT
);
242 // Don't do anything here, so that ASSERT works in the subfunction as
246 void TestOpenCpuinfo(bool fast_check_in_client
) {
247 const char kFileCpuInfo
[] = "/proc/cpuinfo";
248 std::vector
<std::string
> read_whitelist
;
249 read_whitelist
.push_back(kFileCpuInfo
);
251 scoped_ptr
<BrokerProcess
> open_broker(new BrokerProcess(
252 EPERM
, read_whitelist
, std::vector
<std::string
>(), fast_check_in_client
));
253 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
256 fd
= open_broker
->Open(kFileCpuInfo
, O_RDWR
);
257 base::ScopedFD
fd_closer(fd
);
258 ASSERT_EQ(fd
, -EPERM
);
260 // Check we can read /proc/cpuinfo.
261 int can_access
= open_broker
->Access(kFileCpuInfo
, R_OK
);
262 ASSERT_EQ(can_access
, 0);
263 can_access
= open_broker
->Access(kFileCpuInfo
, W_OK
);
264 ASSERT_EQ(can_access
, -EPERM
);
265 // Check we can not write /proc/cpuinfo.
267 // Open cpuinfo via the broker.
268 int cpuinfo_fd
= open_broker
->Open(kFileCpuInfo
, O_RDONLY
);
269 base::ScopedFD
cpuinfo_fd_closer(cpuinfo_fd
);
270 ASSERT_GE(cpuinfo_fd
, 0);
272 memset(buf
, 0, sizeof(buf
));
273 int read_len1
= read(cpuinfo_fd
, buf
, sizeof(buf
));
274 ASSERT_GT(read_len1
, 0);
276 // Open cpuinfo directly.
277 int cpuinfo_fd2
= open(kFileCpuInfo
, O_RDONLY
);
278 base::ScopedFD
cpuinfo_fd2_closer(cpuinfo_fd2
);
279 ASSERT_GE(cpuinfo_fd2
, 0);
281 memset(buf2
, 1, sizeof(buf2
));
282 int read_len2
= read(cpuinfo_fd2
, buf2
, sizeof(buf2
));
283 ASSERT_GT(read_len1
, 0);
285 // The following is not guaranteed true, but will be in practice.
286 ASSERT_EQ(read_len1
, read_len2
);
287 // Compare the cpuinfo as returned by the broker with the one we opened
289 ASSERT_EQ(memcmp(buf
, buf2
, read_len1
), 0);
291 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
293 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
296 // Run the same thing twice. The second time, we make sure that no security
297 // check is performed on the client.
298 TEST(BrokerProcess
, OpenCpuinfoWithClientCheck
) {
299 TestOpenCpuinfo(true /* fast_check_in_client */);
300 // Don't do anything here, so that ASSERT works in the subfunction as
304 TEST(BrokerProcess
, OpenCpuinfoNoClientCheck
) {
305 TestOpenCpuinfo(false /* fast_check_in_client */);
306 // Don't do anything here, so that ASSERT works in the subfunction as
310 TEST(BrokerProcess
, OpenFileRW
) {
311 ScopedTemporaryFile tempfile
;
312 const char* tempfile_name
= tempfile
.full_file_name();
314 std::vector
<std::string
> whitelist
;
315 whitelist
.push_back(tempfile_name
);
317 BrokerProcess
open_broker(EPERM
, whitelist
, whitelist
);
318 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
320 // Check we can access that file with read or write.
321 int can_access
= open_broker
.Access(tempfile_name
, R_OK
| W_OK
);
322 ASSERT_EQ(can_access
, 0);
325 tempfile2
= open_broker
.Open(tempfile_name
, O_RDWR
);
326 ASSERT_GE(tempfile2
, 0);
328 // Write to the descriptor opened by the broker.
329 char test_text
[] = "TESTTESTTEST";
330 ssize_t len
= write(tempfile2
, test_text
, sizeof(test_text
));
331 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
333 // Read back from the original file descriptor what we wrote through
334 // the descriptor provided by the broker.
336 len
= read(tempfile
.fd(), buf
, sizeof(buf
));
338 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
339 ASSERT_EQ(memcmp(test_text
, buf
, sizeof(test_text
)), 0);
341 ASSERT_EQ(close(tempfile2
), 0);
344 // SANDBOX_TEST because the process could die with a SIGPIPE
345 // and we want this to happen in a subprocess.
346 SANDBOX_TEST(BrokerProcess
, BrokerDied
) {
347 std::vector
<std::string
> read_whitelist
;
348 read_whitelist
.push_back("/proc/cpuinfo");
350 BrokerProcess
open_broker(EPERM
,
352 std::vector
<std::string
>(),
353 true /* fast_check_in_client */,
354 true /* quiet_failures_for_tests */);
355 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
356 const pid_t broker_pid
= open_broker
.broker_pid();
357 SANDBOX_ASSERT(kill(broker_pid
, SIGKILL
) == 0);
359 // Now we check that the broker has been signaled, but do not reap it.
360 siginfo_t process_info
;
361 SANDBOX_ASSERT(HANDLE_EINTR(waitid(
362 P_PID
, broker_pid
, &process_info
, WEXITED
| WNOWAIT
)) ==
364 SANDBOX_ASSERT(broker_pid
== process_info
.si_pid
);
365 SANDBOX_ASSERT(CLD_KILLED
== process_info
.si_code
);
366 SANDBOX_ASSERT(SIGKILL
== process_info
.si_status
);
368 // Check that doing Open with a dead broker won't SIGPIPE us.
369 SANDBOX_ASSERT(open_broker
.Open("/proc/cpuinfo", O_RDONLY
) == -ENOMEM
);
370 SANDBOX_ASSERT(open_broker
.Access("/proc/cpuinfo", O_RDONLY
) == -ENOMEM
);
373 void TestOpenComplexFlags(bool fast_check_in_client
) {
374 const char kCpuInfo
[] = "/proc/cpuinfo";
375 std::vector
<std::string
> whitelist
;
376 whitelist
.push_back(kCpuInfo
);
378 BrokerProcess
open_broker(EPERM
, whitelist
, whitelist
, fast_check_in_client
);
379 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
380 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
383 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
385 ret
= fcntl(fd
, F_GETFL
);
387 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
388 ASSERT_EQ(0, ret
& (O_CLOEXEC
| O_NONBLOCK
));
389 ASSERT_EQ(0, close(fd
));
391 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_CLOEXEC
);
393 ret
= fcntl(fd
, F_GETFD
);
395 // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
396 // is actually not used by the kernel.
397 ASSERT_TRUE(FD_CLOEXEC
& ret
);
398 ASSERT_EQ(0, close(fd
));
400 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_NONBLOCK
);
402 ret
= fcntl(fd
, F_GETFL
);
404 ASSERT_TRUE(O_NONBLOCK
& ret
);
405 ASSERT_EQ(0, close(fd
));
408 TEST(BrokerProcess
, OpenComplexFlagsWithClientCheck
) {
409 TestOpenComplexFlags(true /* fast_check_in_client */);
410 // Don't do anything here, so that ASSERT works in the subfunction as
414 TEST(BrokerProcess
, OpenComplexFlagsNoClientCheck
) {
415 TestOpenComplexFlags(false /* fast_check_in_client */);
416 // Don't do anything here, so that ASSERT works in the subfunction as
420 // We need to allow noise because the broker will log when it receives our
422 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess
, RecvMsgDescriptorLeak
) {
423 // Android creates a socket on first use of the LOG call.
424 // We need to ensure this socket is open before we
426 LOG(INFO
) << "Ensure Android LOG socket is allocated";
428 // Find the four lowest available file descriptors.
429 int available_fds
[4];
430 SANDBOX_ASSERT(0 == pipe(available_fds
));
431 SANDBOX_ASSERT(0 == pipe(available_fds
+ 2));
433 // Save one FD to send to the broker later, and close the others.
434 base::ScopedFD
message_fd(available_fds
[0]);
435 for (size_t i
= 1; i
< arraysize(available_fds
); i
++) {
436 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds
[i
])));
439 // Lower our file descriptor limit to just allow three more file descriptors
440 // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file
441 // descriptors a process can have: it only limits the highest value that can
442 // be assigned to newly-created descriptors allocated by the process.)
443 const rlim_t fd_limit
=
445 *std::max_element(available_fds
,
446 available_fds
+ arraysize(available_fds
));
448 // Valgrind doesn't allow changing the hard descriptor limit, so we only
449 // change the soft descriptor limit here.
451 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE
, &rlim
));
452 SANDBOX_ASSERT(fd_limit
<= rlim
.rlim_cur
);
453 rlim
.rlim_cur
= fd_limit
;
454 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE
, &rlim
));
456 static const char kCpuInfo
[] = "/proc/cpuinfo";
457 std::vector
<std::string
> read_whitelist
;
458 read_whitelist
.push_back(kCpuInfo
);
460 BrokerProcess
open_broker(EPERM
, read_whitelist
, std::vector
<std::string
>());
461 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
463 const int ipc_fd
= BrokerProcessTestHelper::GetIPCDescriptor(&open_broker
);
464 SANDBOX_ASSERT(ipc_fd
>= 0);
466 static const char kBogus
[] = "not a pickle";
467 std::vector
<int> fds
;
468 fds
.push_back(message_fd
.get());
470 // The broker process should only have a couple spare file descriptors
471 // available, but for good measure we send it fd_limit bogus IPCs anyway.
472 for (rlim_t i
= 0; i
< fd_limit
; ++i
) {
474 UnixDomainSocket::SendMsg(ipc_fd
, kBogus
, sizeof(kBogus
), fds
));
477 const int fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
478 SANDBOX_ASSERT(fd
>= 0);
479 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd
)));
482 bool CloseFD(int fd
) {
483 PCHECK(0 == IGNORE_EINTR(close(fd
)));
487 // Return true if the other end of the |reader| pipe was closed,
488 // false if |timeout_in_seconds| was reached or another event
490 bool WaitForClosedPipeWriter(int reader
, int timeout_in_ms
) {
491 struct pollfd poll_fd
= {reader
, POLLIN
| POLLRDHUP
, 0};
492 const int num_events
= HANDLE_EINTR(poll(&poll_fd
, 1, timeout_in_ms
));
493 if (1 == num_events
&& poll_fd
.revents
| POLLHUP
)
498 // Closing the broker client's IPC channel should terminate the broker
500 TEST(BrokerProcess
, BrokerDiesOnClosedChannel
) {
501 std::vector
<std::string
> read_whitelist
;
502 read_whitelist
.push_back("/proc/cpuinfo");
504 // Get the writing end of a pipe into the broker (child) process so
505 // that we can reliably detect when it dies.
507 PCHECK(0 == pipe(lifeline_fds
));
509 BrokerProcess
open_broker(EPERM
, read_whitelist
, std::vector
<std::string
>(),
510 true /* fast_check_in_client */,
511 false /* quiet_failures_for_tests */);
512 ASSERT_TRUE(open_broker
.Init(base::Bind(&CloseFD
, lifeline_fds
[0])));
513 // Make sure the writing end only exists in the broker process.
514 CloseFD(lifeline_fds
[1]);
515 base::ScopedFD
reader(lifeline_fds
[0]);
517 const pid_t broker_pid
= open_broker
.broker_pid();
519 // This should cause the broker process to exit.
520 BrokerProcessTestHelper::CloseChannel(&open_broker
);
522 const int kTimeoutInMilliseconds
= 5000;
523 const bool broker_lifeline_closed
=
524 WaitForClosedPipeWriter(reader
.get(), kTimeoutInMilliseconds
);
525 // If the broker exited, its lifeline fd should be closed.
526 ASSERT_TRUE(broker_lifeline_closed
);
527 // Now check that the broker has exited, but do not reap it.
528 siginfo_t process_info
;
529 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID
, broker_pid
, &process_info
,
530 WEXITED
| WNOWAIT
)));
531 EXPECT_EQ(broker_pid
, process_info
.si_pid
);
532 EXPECT_EQ(CLD_EXITED
, process_info
.si_code
);
533 EXPECT_EQ(1, process_info
.si_status
);
536 } // namespace syscall_broker
538 } // namespace sandbox