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/scoped_temporary_file.h"
28 #include "sandbox/linux/tests/test_utils.h"
29 #include "sandbox/linux/tests/unit_tests.h"
30 #include "testing/gtest/include/gtest/gtest.h"
34 class BrokerProcessTestHelper
{
36 static int get_ipc_socketpair(const BrokerProcess
* broker
) {
37 return broker
->ipc_socketpair_
;
43 bool NoOpCallback() { return true; }
47 TEST(BrokerProcess
, CreateAndDestroy
) {
48 std::vector
<std::string
> read_whitelist
;
49 read_whitelist
.push_back("/proc/cpuinfo");
51 scoped_ptr
<BrokerProcess
> open_broker(
52 new BrokerProcess(EPERM
, read_whitelist
, std::vector
<std::string
>()));
53 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
55 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
56 // Destroy the broker and check it has exited properly.
58 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
61 TEST(BrokerProcess
, TestOpenAccessNull
) {
62 const std::vector
<std::string
> empty
;
63 BrokerProcess
open_broker(EPERM
, empty
, empty
);
64 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
66 int fd
= open_broker
.Open(NULL
, O_RDONLY
);
67 ASSERT_EQ(fd
, -EFAULT
);
69 int ret
= open_broker
.Access(NULL
, F_OK
);
70 ASSERT_EQ(ret
, -EFAULT
);
73 void TestOpenFilePerms(bool fast_check_in_client
, int denied_errno
) {
74 const char kR_WhiteListed
[] = "/proc/DOESNOTEXIST1";
75 // We can't debug the init process, and shouldn't be able to access
77 const char kR_WhiteListedButDenied
[] = "/proc/1/auxv";
78 const char kW_WhiteListed
[] = "/proc/DOESNOTEXIST2";
79 const char kRW_WhiteListed
[] = "/proc/DOESNOTEXIST3";
80 const char k_NotWhitelisted
[] = "/proc/DOESNOTEXIST4";
82 std::vector
<std::string
> read_whitelist
;
83 read_whitelist
.push_back(kR_WhiteListed
);
84 read_whitelist
.push_back(kR_WhiteListedButDenied
);
85 read_whitelist
.push_back(kRW_WhiteListed
);
87 std::vector
<std::string
> write_whitelist
;
88 write_whitelist
.push_back(kW_WhiteListed
);
89 write_whitelist
.push_back(kRW_WhiteListed
);
91 BrokerProcess
open_broker(denied_errno
,
94 fast_check_in_client
);
95 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
98 fd
= open_broker
.Open(kR_WhiteListed
, O_RDONLY
);
99 ASSERT_EQ(fd
, -ENOENT
);
100 fd
= open_broker
.Open(kR_WhiteListed
, O_WRONLY
);
101 ASSERT_EQ(fd
, -denied_errno
);
102 fd
= open_broker
.Open(kR_WhiteListed
, O_RDWR
);
103 ASSERT_EQ(fd
, -denied_errno
);
105 ret
= open_broker
.Access(kR_WhiteListed
, F_OK
);
106 ASSERT_EQ(ret
, -ENOENT
);
107 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
);
108 ASSERT_EQ(ret
, -ENOENT
);
109 ret
= open_broker
.Access(kR_WhiteListed
, W_OK
);
110 ASSERT_EQ(ret
, -denied_errno
);
111 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| W_OK
);
112 ASSERT_EQ(ret
, -denied_errno
);
113 ret
= open_broker
.Access(kR_WhiteListed
, X_OK
);
114 ASSERT_EQ(ret
, -denied_errno
);
115 ret
= open_broker
.Access(kR_WhiteListed
, R_OK
| X_OK
);
116 ASSERT_EQ(ret
, -denied_errno
);
118 // Android sometimes runs tests as root.
119 // This part of the test requires a process that doesn't have
120 // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
122 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDONLY
);
123 // The broker process will allow this, but the normal permission system
125 ASSERT_EQ(fd
, -EACCES
);
126 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_WRONLY
);
127 ASSERT_EQ(fd
, -denied_errno
);
128 fd
= open_broker
.Open(kR_WhiteListedButDenied
, O_RDWR
);
129 ASSERT_EQ(fd
, -denied_errno
);
130 ret
= open_broker
.Access(kR_WhiteListedButDenied
, F_OK
);
131 // The normal permission system will let us check that the file exists.
133 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
);
134 ASSERT_EQ(ret
, -EACCES
);
135 ret
= open_broker
.Access(kR_WhiteListedButDenied
, W_OK
);
136 ASSERT_EQ(ret
, -denied_errno
);
137 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| W_OK
);
138 ASSERT_EQ(ret
, -denied_errno
);
139 ret
= open_broker
.Access(kR_WhiteListedButDenied
, X_OK
);
140 ASSERT_EQ(ret
, -denied_errno
);
141 ret
= open_broker
.Access(kR_WhiteListedButDenied
, R_OK
| X_OK
);
142 ASSERT_EQ(ret
, -denied_errno
);
145 fd
= open_broker
.Open(kW_WhiteListed
, O_RDONLY
);
146 ASSERT_EQ(fd
, -denied_errno
);
147 fd
= open_broker
.Open(kW_WhiteListed
, O_WRONLY
);
148 ASSERT_EQ(fd
, -ENOENT
);
149 fd
= open_broker
.Open(kW_WhiteListed
, O_RDWR
);
150 ASSERT_EQ(fd
, -denied_errno
);
151 ret
= open_broker
.Access(kW_WhiteListed
, F_OK
);
152 ASSERT_EQ(ret
, -ENOENT
);
153 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
);
154 ASSERT_EQ(ret
, -denied_errno
);
155 ret
= open_broker
.Access(kW_WhiteListed
, W_OK
);
156 ASSERT_EQ(ret
, -ENOENT
);
157 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| W_OK
);
158 ASSERT_EQ(ret
, -denied_errno
);
159 ret
= open_broker
.Access(kW_WhiteListed
, X_OK
);
160 ASSERT_EQ(ret
, -denied_errno
);
161 ret
= open_broker
.Access(kW_WhiteListed
, R_OK
| X_OK
);
162 ASSERT_EQ(ret
, -denied_errno
);
164 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
);
165 ASSERT_EQ(fd
, -ENOENT
);
166 fd
= open_broker
.Open(kRW_WhiteListed
, O_WRONLY
);
167 ASSERT_EQ(fd
, -ENOENT
);
168 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
);
169 ASSERT_EQ(fd
, -ENOENT
);
170 ret
= open_broker
.Access(kRW_WhiteListed
, F_OK
);
171 ASSERT_EQ(ret
, -ENOENT
);
172 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
);
173 ASSERT_EQ(ret
, -ENOENT
);
174 ret
= open_broker
.Access(kRW_WhiteListed
, W_OK
);
175 ASSERT_EQ(ret
, -ENOENT
);
176 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| W_OK
);
177 ASSERT_EQ(ret
, -ENOENT
);
178 ret
= open_broker
.Access(kRW_WhiteListed
, X_OK
);
179 ASSERT_EQ(ret
, -denied_errno
);
180 ret
= open_broker
.Access(kRW_WhiteListed
, R_OK
| X_OK
);
181 ASSERT_EQ(ret
, -denied_errno
);
183 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDONLY
);
184 ASSERT_EQ(fd
, -denied_errno
);
185 fd
= open_broker
.Open(k_NotWhitelisted
, O_WRONLY
);
186 ASSERT_EQ(fd
, -denied_errno
);
187 fd
= open_broker
.Open(k_NotWhitelisted
, O_RDWR
);
188 ASSERT_EQ(fd
, -denied_errno
);
189 ret
= open_broker
.Access(k_NotWhitelisted
, F_OK
);
190 ASSERT_EQ(ret
, -denied_errno
);
191 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
);
192 ASSERT_EQ(ret
, -denied_errno
);
193 ret
= open_broker
.Access(k_NotWhitelisted
, W_OK
);
194 ASSERT_EQ(ret
, -denied_errno
);
195 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| W_OK
);
196 ASSERT_EQ(ret
, -denied_errno
);
197 ret
= open_broker
.Access(k_NotWhitelisted
, X_OK
);
198 ASSERT_EQ(ret
, -denied_errno
);
199 ret
= open_broker
.Access(k_NotWhitelisted
, R_OK
| X_OK
);
200 ASSERT_EQ(ret
, -denied_errno
);
202 // We have some extra sanity check for clearly wrong values.
203 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDONLY
| O_WRONLY
| O_RDWR
);
204 ASSERT_EQ(fd
, -denied_errno
);
206 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
208 fd
= open_broker
.Open(kRW_WhiteListed
, O_RDWR
| O_CREAT
);
209 ASSERT_EQ(fd
, -denied_errno
);
212 // Run the same thing twice. The second time, we make sure that no security
213 // check is performed on the client.
214 TEST(BrokerProcess
, OpenFilePermsWithClientCheck
) {
215 TestOpenFilePerms(true /* fast_check_in_client */, EPERM
);
216 // Don't do anything here, so that ASSERT works in the subfunction as
220 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheck
) {
221 TestOpenFilePerms(false /* fast_check_in_client */, EPERM
);
222 // Don't do anything here, so that ASSERT works in the subfunction as
226 // Run the same twice again, but with ENOENT instead of EPERM.
227 TEST(BrokerProcess
, OpenFilePermsWithClientCheckNoEnt
) {
228 TestOpenFilePerms(true /* fast_check_in_client */, ENOENT
);
229 // Don't do anything here, so that ASSERT works in the subfunction as
233 TEST(BrokerProcess
, OpenOpenFilePermsNoClientCheckNoEnt
) {
234 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT
);
235 // Don't do anything here, so that ASSERT works in the subfunction as
239 void TestOpenCpuinfo(bool fast_check_in_client
) {
240 const char kFileCpuInfo
[] = "/proc/cpuinfo";
241 std::vector
<std::string
> read_whitelist
;
242 read_whitelist
.push_back(kFileCpuInfo
);
244 scoped_ptr
<BrokerProcess
> open_broker(new BrokerProcess(
245 EPERM
, read_whitelist
, std::vector
<std::string
>(), fast_check_in_client
));
246 ASSERT_TRUE(open_broker
->Init(base::Bind(&NoOpCallback
)));
249 fd
= open_broker
->Open(kFileCpuInfo
, O_RDWR
);
250 base::ScopedFD
fd_closer(fd
);
251 ASSERT_EQ(fd
, -EPERM
);
253 // Check we can read /proc/cpuinfo.
254 int can_access
= open_broker
->Access(kFileCpuInfo
, R_OK
);
255 ASSERT_EQ(can_access
, 0);
256 can_access
= open_broker
->Access(kFileCpuInfo
, W_OK
);
257 ASSERT_EQ(can_access
, -EPERM
);
258 // Check we can not write /proc/cpuinfo.
260 // Open cpuinfo via the broker.
261 int cpuinfo_fd
= open_broker
->Open(kFileCpuInfo
, O_RDONLY
);
262 base::ScopedFD
cpuinfo_fd_closer(cpuinfo_fd
);
263 ASSERT_GE(cpuinfo_fd
, 0);
265 memset(buf
, 0, sizeof(buf
));
266 int read_len1
= read(cpuinfo_fd
, buf
, sizeof(buf
));
267 ASSERT_GT(read_len1
, 0);
269 // Open cpuinfo directly.
270 int cpuinfo_fd2
= open(kFileCpuInfo
, O_RDONLY
);
271 base::ScopedFD
cpuinfo_fd2_closer(cpuinfo_fd2
);
272 ASSERT_GE(cpuinfo_fd2
, 0);
274 memset(buf2
, 1, sizeof(buf2
));
275 int read_len2
= read(cpuinfo_fd2
, buf2
, sizeof(buf2
));
276 ASSERT_GT(read_len1
, 0);
278 // The following is not guaranteed true, but will be in practice.
279 ASSERT_EQ(read_len1
, read_len2
);
280 // Compare the cpuinfo as returned by the broker with the one we opened
282 ASSERT_EQ(memcmp(buf
, buf2
, read_len1
), 0);
284 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
286 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
289 // Run the same thing twice. The second time, we make sure that no security
290 // check is performed on the client.
291 TEST(BrokerProcess
, OpenCpuinfoWithClientCheck
) {
292 TestOpenCpuinfo(true /* fast_check_in_client */);
293 // Don't do anything here, so that ASSERT works in the subfunction as
297 TEST(BrokerProcess
, OpenCpuinfoNoClientCheck
) {
298 TestOpenCpuinfo(false /* fast_check_in_client */);
299 // Don't do anything here, so that ASSERT works in the subfunction as
303 TEST(BrokerProcess
, OpenFileRW
) {
304 ScopedTemporaryFile tempfile
;
305 const char* tempfile_name
= tempfile
.full_file_name();
307 std::vector
<std::string
> whitelist
;
308 whitelist
.push_back(tempfile_name
);
310 BrokerProcess
open_broker(EPERM
, whitelist
, whitelist
);
311 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
313 // Check we can access that file with read or write.
314 int can_access
= open_broker
.Access(tempfile_name
, R_OK
| W_OK
);
315 ASSERT_EQ(can_access
, 0);
318 tempfile2
= open_broker
.Open(tempfile_name
, O_RDWR
);
319 ASSERT_GE(tempfile2
, 0);
321 // Write to the descriptor opened by the broker.
322 char test_text
[] = "TESTTESTTEST";
323 ssize_t len
= write(tempfile2
, test_text
, sizeof(test_text
));
324 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
326 // Read back from the original file descriptor what we wrote through
327 // the descriptor provided by the broker.
329 len
= read(tempfile
.fd(), buf
, sizeof(buf
));
331 ASSERT_EQ(len
, static_cast<ssize_t
>(sizeof(test_text
)));
332 ASSERT_EQ(memcmp(test_text
, buf
, sizeof(test_text
)), 0);
334 ASSERT_EQ(close(tempfile2
), 0);
337 // SANDBOX_TEST because the process could die with a SIGPIPE
338 // and we want this to happen in a subprocess.
339 SANDBOX_TEST(BrokerProcess
, BrokerDied
) {
340 std::vector
<std::string
> read_whitelist
;
341 read_whitelist
.push_back("/proc/cpuinfo");
343 BrokerProcess
open_broker(EPERM
,
345 std::vector
<std::string
>(),
346 true /* fast_check_in_client */,
347 true /* quiet_failures_for_tests */);
348 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
349 const pid_t broker_pid
= open_broker
.broker_pid();
350 SANDBOX_ASSERT(kill(broker_pid
, SIGKILL
) == 0);
352 // Now we check that the broker has been signaled, but do not reap it.
353 siginfo_t process_info
;
354 SANDBOX_ASSERT(HANDLE_EINTR(waitid(
355 P_PID
, broker_pid
, &process_info
, WEXITED
| WNOWAIT
)) ==
357 SANDBOX_ASSERT(broker_pid
== process_info
.si_pid
);
358 SANDBOX_ASSERT(CLD_KILLED
== process_info
.si_code
);
359 SANDBOX_ASSERT(SIGKILL
== process_info
.si_status
);
361 // Check that doing Open with a dead broker won't SIGPIPE us.
362 SANDBOX_ASSERT(open_broker
.Open("/proc/cpuinfo", O_RDONLY
) == -ENOMEM
);
363 SANDBOX_ASSERT(open_broker
.Access("/proc/cpuinfo", O_RDONLY
) == -ENOMEM
);
366 void TestOpenComplexFlags(bool fast_check_in_client
) {
367 const char kCpuInfo
[] = "/proc/cpuinfo";
368 std::vector
<std::string
> whitelist
;
369 whitelist
.push_back(kCpuInfo
);
371 BrokerProcess
open_broker(EPERM
,
374 fast_check_in_client
);
375 ASSERT_TRUE(open_broker
.Init(base::Bind(&NoOpCallback
)));
376 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
379 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
381 ret
= fcntl(fd
, F_GETFL
);
383 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
384 ASSERT_EQ(0, ret
& (O_CLOEXEC
| O_NONBLOCK
));
385 ASSERT_EQ(0, close(fd
));
387 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_CLOEXEC
);
389 ret
= fcntl(fd
, F_GETFD
);
391 // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
392 // is actually not used by the kernel.
393 ASSERT_TRUE(FD_CLOEXEC
& ret
);
394 ASSERT_EQ(0, close(fd
));
396 fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
| O_NONBLOCK
);
398 ret
= fcntl(fd
, F_GETFL
);
400 ASSERT_TRUE(O_NONBLOCK
& ret
);
401 ASSERT_EQ(0, close(fd
));
404 TEST(BrokerProcess
, OpenComplexFlagsWithClientCheck
) {
405 TestOpenComplexFlags(true /* fast_check_in_client */);
406 // Don't do anything here, so that ASSERT works in the subfunction as
410 TEST(BrokerProcess
, OpenComplexFlagsNoClientCheck
) {
411 TestOpenComplexFlags(false /* fast_check_in_client */);
412 // Don't do anything here, so that ASSERT works in the subfunction as
416 // We need to allow noise because the broker will log when it receives our
418 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess
, RecvMsgDescriptorLeak
) {
419 // Find the four lowest available file descriptors.
420 int available_fds
[4];
421 SANDBOX_ASSERT(0 == pipe(available_fds
));
422 SANDBOX_ASSERT(0 == pipe(available_fds
+ 2));
424 // Save one FD to send to the broker later, and close the others.
425 base::ScopedFD
message_fd(available_fds
[0]);
426 for (size_t i
= 1; i
< arraysize(available_fds
); i
++) {
427 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds
[i
])));
430 // Lower our file descriptor limit to just allow three more file descriptors
431 // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file
432 // descriptors a process can have: it only limits the highest value that can
433 // be assigned to newly-created descriptors allocated by the process.)
434 const rlim_t fd_limit
=
435 1 + *std::max_element(available_fds
,
436 available_fds
+ arraysize(available_fds
));
438 // Valgrind doesn't allow changing the hard descriptor limit, so we only
439 // change the soft descriptor limit here.
441 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE
, &rlim
));
442 SANDBOX_ASSERT(fd_limit
<= rlim
.rlim_cur
);
443 rlim
.rlim_cur
= fd_limit
;
444 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE
, &rlim
));
446 static const char kCpuInfo
[] = "/proc/cpuinfo";
447 std::vector
<std::string
> read_whitelist
;
448 read_whitelist
.push_back(kCpuInfo
);
450 BrokerProcess
open_broker(EPERM
, read_whitelist
, std::vector
<std::string
>());
451 SANDBOX_ASSERT(open_broker
.Init(base::Bind(&NoOpCallback
)));
453 const int ipc_fd
= BrokerProcessTestHelper::get_ipc_socketpair(&open_broker
);
454 SANDBOX_ASSERT(ipc_fd
>= 0);
456 static const char kBogus
[] = "not a pickle";
457 std::vector
<int> fds
;
458 fds
.push_back(message_fd
.get());
460 // The broker process should only have a couple spare file descriptors
461 // available, but for good measure we send it fd_limit bogus IPCs anyway.
462 for (rlim_t i
= 0; i
< fd_limit
; ++i
) {
464 UnixDomainSocket::SendMsg(ipc_fd
, kBogus
, sizeof(kBogus
), fds
));
467 const int fd
= open_broker
.Open(kCpuInfo
, O_RDONLY
);
468 SANDBOX_ASSERT(fd
>= 0);
469 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd
)));
472 } // namespace sandbox