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. 4 5 #include "sandbox/linux/services/broker_process.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <sys/resource.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 #include <sys/wait.h> 13 #include <unistd.h> 14 15 #include <algorithm> 16 #include <string> 17 #include <vector> 18 19 #include "base/basictypes.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/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" 31 32 namespace sandbox { 33 34 class BrokerProcessTestHelper { 35 public: 36 static int get_ipc_socketpair(const BrokerProcess* broker) { 37 return broker->ipc_socketpair_; 38 } 39 }; 40 41 namespace { 42 43 bool NoOpCallback() { return true; } 44 45 } // namespace 46 47 TEST(BrokerProcess, CreateAndDestroy) { 48 std::vector<std::string> read_whitelist; 49 read_whitelist.push_back("/proc/cpuinfo"); 50 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))); 54 55 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); 56 // Destroy the broker and check it has exited properly. 57 open_broker.reset(); 58 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); 59 } 60 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))); 65 66 int fd = open_broker.Open(NULL, O_RDONLY); 67 ASSERT_EQ(fd, -EFAULT); 68 69 int ret = open_broker.Access(NULL, F_OK); 70 ASSERT_EQ(ret, -EFAULT); 71 } 72 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 76 // its auxv file. 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"; 81 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); 86 87 std::vector<std::string> write_whitelist; 88 write_whitelist.push_back(kW_WhiteListed); 89 write_whitelist.push_back(kRW_WhiteListed); 90 91 BrokerProcess open_broker(denied_errno, 92 read_whitelist, 93 write_whitelist, 94 fast_check_in_client); 95 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 96 97 int fd = -1; 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); 104 int ret = -1; 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); 117 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. 121 if (geteuid()) { 122 fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY); 123 // The broker process will allow this, but the normal permission system 124 // won't. 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. 132 ASSERT_EQ(ret, 0); 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); 143 } 144 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); 163 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); 182 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); 201 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); 205 206 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this 207 // is denied. 208 fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT); 209 ASSERT_EQ(fd, -denied_errno); 210 } 211 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 217 // expected. 218 } 219 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 223 // expected. 224 } 225 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 230 // expected. 231 } 232 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 236 // expected. 237 } 238 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); 243 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))); 247 248 int fd = -1; 249 fd = open_broker->Open(kFileCpuInfo, O_RDWR); 250 base::ScopedFD fd_closer(fd); 251 ASSERT_EQ(fd, -EPERM); 252 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. 259 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); 264 char buf[3]; 265 memset(buf, 0, sizeof(buf)); 266 int read_len1 = read(cpuinfo_fd, buf, sizeof(buf)); 267 ASSERT_GT(read_len1, 0); 268 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); 273 char buf2[3]; 274 memset(buf2, 1, sizeof(buf2)); 275 int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2)); 276 ASSERT_GT(read_len1, 0); 277 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 281 // ourselves. 282 ASSERT_EQ(memcmp(buf, buf2, read_len1), 0); 283 284 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); 285 open_broker.reset(); 286 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); 287 } 288 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 294 // expected. 295 } 296 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 300 // expected. 301 } 302 303 TEST(BrokerProcess, OpenFileRW) { 304 ScopedTemporaryFile tempfile; 305 const char* tempfile_name = tempfile.full_file_name(); 306 307 std::vector<std::string> whitelist; 308 whitelist.push_back(tempfile_name); 309 310 BrokerProcess open_broker(EPERM, whitelist, whitelist); 311 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 312 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); 316 317 int tempfile2 = -1; 318 tempfile2 = open_broker.Open(tempfile_name, O_RDWR); 319 ASSERT_GE(tempfile2, 0); 320 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))); 325 326 // Read back from the original file descriptor what we wrote through 327 // the descriptor provided by the broker. 328 char buf[1024]; 329 len = read(tempfile.fd(), buf, sizeof(buf)); 330 331 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); 332 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); 333 334 ASSERT_EQ(close(tempfile2), 0); 335 } 336 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"); 342 343 BrokerProcess open_broker(EPERM, 344 read_whitelist, 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); 351 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)) == 356 0); 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); 360 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); 364 } 365 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); 370 371 BrokerProcess open_broker(EPERM, 372 whitelist, 373 whitelist, 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. 377 int fd = -1; 378 int ret = 0; 379 fd = open_broker.Open(kCpuInfo, O_RDONLY); 380 ASSERT_GE(fd, 0); 381 ret = fcntl(fd, F_GETFL); 382 ASSERT_NE(-1, ret); 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)); 386 387 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC); 388 ASSERT_GE(fd, 0); 389 ret = fcntl(fd, F_GETFD); 390 ASSERT_NE(-1, ret); 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)); 395 396 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK); 397 ASSERT_GE(fd, 0); 398 ret = fcntl(fd, F_GETFL); 399 ASSERT_NE(-1, ret); 400 ASSERT_TRUE(O_NONBLOCK & ret); 401 ASSERT_EQ(0, close(fd)); 402 } 403 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 407 // expected. 408 } 409 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 413 // expected. 414 } 415 416 // We need to allow noise because the broker will log when it receives our 417 // bogus IPCs. 418 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, RecvMsgDescriptorLeak) { 419 // Android creates a socket on first use of the LOG call. 420 // We need to ensure this socket is open before we 421 // begin the test. 422 LOG(INFO) << "Ensure Android LOG socket is allocated"; 423 424 // Find the four lowest available file descriptors. 425 int available_fds[4]; 426 SANDBOX_ASSERT(0 == pipe(available_fds)); 427 SANDBOX_ASSERT(0 == pipe(available_fds + 2)); 428 429 // Save one FD to send to the broker later, and close the others. 430 base::ScopedFD message_fd(available_fds[0]); 431 for (size_t i = 1; i < arraysize(available_fds); i++) { 432 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds[i]))); 433 } 434 435 // Lower our file descriptor limit to just allow three more file descriptors 436 // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file 437 // descriptors a process can have: it only limits the highest value that can 438 // be assigned to newly-created descriptors allocated by the process.) 439 const rlim_t fd_limit = 440 1 + *std::max_element(available_fds, 441 available_fds + arraysize(available_fds)); 442 443 // Valgrind doesn't allow changing the hard descriptor limit, so we only 444 // change the soft descriptor limit here. 445 struct rlimit rlim; 446 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim)); 447 SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur); 448 rlim.rlim_cur = fd_limit; 449 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); 450 451 static const char kCpuInfo[] = "/proc/cpuinfo"; 452 std::vector<std::string> read_whitelist; 453 read_whitelist.push_back(kCpuInfo); 454 455 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>()); 456 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); 457 458 const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker); 459 SANDBOX_ASSERT(ipc_fd >= 0); 460 461 static const char kBogus[] = "not a pickle"; 462 std::vector<int> fds; 463 fds.push_back(message_fd.get()); 464 465 // The broker process should only have a couple spare file descriptors 466 // available, but for good measure we send it fd_limit bogus IPCs anyway. 467 for (rlim_t i = 0; i < fd_limit; ++i) { 468 SANDBOX_ASSERT( 469 UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds)); 470 } 471 472 const int fd = open_broker.Open(kCpuInfo, O_RDONLY); 473 SANDBOX_ASSERT(fd >= 0); 474 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd))); 475 } 476 477 } // namespace sandbox 478