Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sandbox/linux/services/broker_process.h" | 5 #include "sandbox/linux/services/broker_process.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <sys/socket.h> | 8 #include <sys/socket.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| 11 #include <sys/types.h> | 11 #include <sys/types.h> |
| 12 #include <unistd.h> | 12 #include <unistd.h> |
| 13 | 13 |
| 14 #include <algorithm> | 14 #include <algorithm> |
| 15 #include <string> | 15 #include <string> |
| 16 #include <vector> | 16 #include <vector> |
| 17 | 17 |
| 18 #include "base/basictypes.h" | 18 #include "base/basictypes.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/pickle.h" | 20 #include "base/pickle.h" |
| 21 #include "base/posix/eintr_wrapper.h" | 21 #include "base/posix/eintr_wrapper.h" |
| 22 #include "base/posix/unix_domain_socket_linux.h" | 22 #include "base/posix/unix_domain_socket_linux.h" |
| 23 #include "build/build_config.h" | 23 #include "build/build_config.h" |
| 24 #include "sandbox/linux/services/broker_process_utils.h" | |
| 24 #include "sandbox/linux/services/linux_syscalls.h" | 25 #include "sandbox/linux/services/linux_syscalls.h" |
| 25 | 26 |
| 26 #if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC) | 27 #if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC) |
| 27 #define MSG_CMSG_CLOEXEC 0x40000000 | 28 #define MSG_CMSG_CLOEXEC 0x40000000 |
| 28 #endif | 29 #endif |
| 29 | 30 |
| 30 namespace { | 31 namespace { |
| 31 | 32 |
| 32 static const size_t kMaxMessageLength = 4096; | 33 static const size_t kMaxMessageLength = 4096; |
| 33 | 34 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 46 // Since we have to account for buggy userland (see crbug.com/237283), we will | 47 // Since we have to account for buggy userland (see crbug.com/237283), we will |
| 47 // open(2) the file with O_CLOEXEC in the broker process if necessary, in | 48 // open(2) the file with O_CLOEXEC in the broker process if necessary, in |
| 48 // addition to calling recvmsg(2) with MSG_CMSG_CLOEXEC. | 49 // addition to calling recvmsg(2) with MSG_CMSG_CLOEXEC. |
| 49 static const int kCurrentProcessOpenFlagsMask = O_CLOEXEC; | 50 static const int kCurrentProcessOpenFlagsMask = O_CLOEXEC; |
| 50 | 51 |
| 51 // Check whether |requested_filename| is in |allowed_file_names|. | 52 // Check whether |requested_filename| is in |allowed_file_names|. |
| 52 // See GetFileNameIfAllowedToOpen() for an explanation of |file_to_open|. | 53 // See GetFileNameIfAllowedToOpen() for an explanation of |file_to_open|. |
| 53 // async signal safe if |file_to_open| is NULL. | 54 // async signal safe if |file_to_open| is NULL. |
| 54 // TODO(jln): assert signal safety. | 55 // TODO(jln): assert signal safety. |
| 55 bool GetFileNameInWhitelist(const std::vector<std::string>& allowed_file_names, | 56 bool GetFileNameInWhitelist(const std::vector<std::string>& allowed_file_names, |
| 56 const std::string& requested_filename, | 57 const char* requested_filename, |
| 57 const char** file_to_open) { | 58 const char** file_to_open) { |
| 58 if (file_to_open && *file_to_open) { | 59 if (file_to_open && *file_to_open) { |
| 59 // Make sure that callers never pass a non-empty string. In case callers | 60 // Make sure that callers never pass a non-empty string. In case callers |
| 60 // wrongly forget to check the return value and look at the string | 61 // wrongly forget to check the return value and look at the string |
| 61 // instead, this could catch bugs. | 62 // instead, this could catch bugs. |
| 62 RAW_LOG(FATAL, "*file_to_open should be NULL"); | 63 RAW_LOG(FATAL, "*file_to_open should be NULL"); |
| 63 return false; | 64 return false; |
| 64 } | 65 } |
| 65 std::vector<std::string>::const_iterator it; | 66 const char* found_filename = |
| 66 it = std::find(allowed_file_names.begin(), allowed_file_names.end(), | 67 sandbox::BrokerProcessUtils::Find(requested_filename, allowed_file_names); |
| 67 requested_filename); | 68 |
| 68 if (it < allowed_file_names.end()) { // requested_filename was found? | 69 if (found_filename) { // |requested_filename| was found? |
| 69 if (file_to_open) | 70 if (file_to_open) |
| 70 *file_to_open = it->c_str(); | 71 *file_to_open = found_filename; |
| 71 return true; | 72 return true; |
| 72 } | 73 } |
| 73 return false; | 74 return false; |
| 74 } | 75 } |
| 75 | 76 |
| 76 // We maintain a list of flags that have been reviewed for "sanity" and that | 77 // We maintain a list of flags that have been reviewed for "sanity" and that |
| 77 // we're ok to allow in the broker. | 78 // we're ok to allow in the broker. |
| 78 // I.e. here is where we wouldn't add O_RESET_FILE_SYSTEM. | 79 // I.e. here is where we wouldn't add O_RESET_FILE_SYSTEM. |
| 79 bool IsAllowedOpenFlags(int flags) { | 80 bool IsAllowedOpenFlags(int flags) { |
| 80 // First, check the access mode | 81 // First, check the access mode |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 } | 387 } |
| 387 | 388 |
| 388 // Perform access(2) on |requested_filename| with mode |mode| if allowed by our | 389 // Perform access(2) on |requested_filename| with mode |mode| if allowed by our |
| 389 // policy. Write the syscall return value (-errno) to |write_pickle|. | 390 // policy. Write the syscall return value (-errno) to |write_pickle|. |
| 390 void BrokerProcess::AccessFileForIPC(const std::string& requested_filename, | 391 void BrokerProcess::AccessFileForIPC(const std::string& requested_filename, |
| 391 int mode, Pickle* write_pickle) const { | 392 int mode, Pickle* write_pickle) const { |
| 392 DCHECK(write_pickle); | 393 DCHECK(write_pickle); |
| 393 const char* file_to_access = NULL; | 394 const char* file_to_access = NULL; |
| 394 const bool safe_to_access_file = GetFileNameIfAllowedToAccess( | 395 const bool safe_to_access_file = GetFileNameIfAllowedToAccess( |
| 395 requested_filename.c_str(), mode, &file_to_access); | 396 requested_filename.c_str(), mode, &file_to_access); |
| 397 | |
| 396 if (safe_to_access_file) { | 398 if (safe_to_access_file) { |
| 397 CHECK(file_to_access); | 399 CHECK(file_to_access); |
| 398 int access_ret = access(file_to_access, mode); | 400 int access_ret = access(file_to_access, mode); |
| 399 int access_errno = errno; | 401 int access_errno = errno; |
| 400 if (!access_ret) | 402 if (!access_ret) |
| 401 write_pickle->WriteInt(0); | 403 write_pickle->WriteInt(0); |
| 402 else | 404 else |
| 403 write_pickle->WriteInt(-access_errno); | 405 write_pickle->WriteInt(-access_errno); |
| 404 } else { | 406 } else { |
| 405 write_pickle->WriteInt(-EPERM); | 407 write_pickle->WriteInt(-EPERM); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 // mode |requested_mode|. | 442 // mode |requested_mode|. |
| 441 // Note: access() being a system call to check permissions, this can get a bit | 443 // Note: access() being a system call to check permissions, this can get a bit |
| 442 // confusing. We're checking if calling access() should even be allowed with | 444 // confusing. We're checking if calling access() should even be allowed with |
| 443 // the same policy we would use for open(). | 445 // the same policy we would use for open(). |
| 444 // If |file_to_access| is not NULL, we will return the matching pointer from | 446 // If |file_to_access| is not NULL, we will return the matching pointer from |
| 445 // the whitelist. For paranoia a caller should then use |file_to_access|. See | 447 // the whitelist. For paranoia a caller should then use |file_to_access|. See |
| 446 // GetFileNameIfAllowedToOpen() fore more explanation. | 448 // GetFileNameIfAllowedToOpen() fore more explanation. |
| 447 // return true if calling access() on this file should be allowed, false | 449 // return true if calling access() on this file should be allowed, false |
| 448 // otherwise. | 450 // otherwise. |
| 449 // Async signal safe if and only if |file_to_access| is NULL. | 451 // Async signal safe if and only if |file_to_access| is NULL. |
| 450 bool BrokerProcess::GetFileNameIfAllowedToAccess(const char* requested_filename, | 452 bool BrokerProcess::GetFileNameIfAllowedToAccess( |
| 451 int requested_mode, const char** file_to_access) const { | 453 const char* requested_filename, int requested_mode, |
|
jln (very slow on Chromium)
2013/07/08 22:36:51
Why the re-indent?
Jorge Lucangeli Obes
2013/07/09 03:52:12
Done.
| |
| 454 const char** file_to_access) const { | |
| 452 // First, check if |requested_mode| is existence, ability to read or ability | 455 // First, check if |requested_mode| is existence, ability to read or ability |
| 453 // to write. We do not support X_OK. | 456 // to write. We do not support X_OK. |
| 454 if (requested_mode != F_OK && | 457 if (requested_mode != F_OK && |
| 455 requested_mode & ~(R_OK | W_OK)) { | 458 requested_mode & ~(R_OK | W_OK)) { |
| 456 return false; | 459 return false; |
| 457 } | 460 } |
| 458 switch (requested_mode) { | 461 switch (requested_mode) { |
| 459 case F_OK: | 462 case F_OK: |
| 460 // We allow to check for file existence if we can either read or write. | 463 // We allow to check for file existence if we can either read or write. |
| 461 return GetFileNameInWhitelist(allowed_r_files_, requested_filename, | 464 return GetFileNameInWhitelist(allowed_r_files_, requested_filename, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 482 } | 485 } |
| 483 | 486 |
| 484 // Check if |requested_filename| can be opened with flags |requested_flags|. | 487 // Check if |requested_filename| can be opened with flags |requested_flags|. |
| 485 // If |file_to_open| is not NULL, we will return the matching pointer from the | 488 // If |file_to_open| is not NULL, we will return the matching pointer from the |
| 486 // whitelist. For paranoia, a caller should then use |file_to_open| rather | 489 // whitelist. For paranoia, a caller should then use |file_to_open| rather |
| 487 // than |requested_filename|, so that it never attempts to open an | 490 // than |requested_filename|, so that it never attempts to open an |
| 488 // attacker-controlled file name, even if an attacker managed to fool the | 491 // attacker-controlled file name, even if an attacker managed to fool the |
| 489 // string comparison mechanism. | 492 // string comparison mechanism. |
| 490 // Return true if opening should be allowed, false otherwise. | 493 // Return true if opening should be allowed, false otherwise. |
| 491 // Async signal safe if and only if |file_to_open| is NULL. | 494 // Async signal safe if and only if |file_to_open| is NULL. |
| 492 bool BrokerProcess::GetFileNameIfAllowedToOpen(const char* requested_filename, | 495 bool BrokerProcess::GetFileNameIfAllowedToOpen( |
| 493 int requested_flags, const char** file_to_open) const { | 496 const char* requested_filename, int requested_flags, |
| 497 const char** file_to_open) const { | |
|
jln (very slow on Chromium)
2013/07/08 22:36:51
Why the re-indent?
Jorge Lucangeli Obes
2013/07/09 03:52:12
Done.
| |
| 494 if (!IsAllowedOpenFlags(requested_flags)) { | 498 if (!IsAllowedOpenFlags(requested_flags)) { |
| 495 return false; | 499 return false; |
| 496 } | 500 } |
| 497 switch (requested_flags & O_ACCMODE) { | 501 switch (requested_flags & O_ACCMODE) { |
| 498 case O_RDONLY: | 502 case O_RDONLY: |
| 499 return GetFileNameInWhitelist(allowed_r_files_, requested_filename, | 503 return GetFileNameInWhitelist(allowed_r_files_, requested_filename, |
| 500 file_to_open); | 504 file_to_open); |
| 501 case O_WRONLY: | 505 case O_WRONLY: |
| 502 return GetFileNameInWhitelist(allowed_w_files_, requested_filename, | 506 return GetFileNameInWhitelist(allowed_w_files_, requested_filename, |
| 503 file_to_open); | 507 file_to_open); |
| 504 case O_RDWR: | 508 case O_RDWR: |
| 505 { | 509 { |
| 506 bool allowed_for_read_and_write = | 510 bool allowed_for_read_and_write = |
| 507 GetFileNameInWhitelist(allowed_r_files_, requested_filename, NULL) && | 511 GetFileNameInWhitelist(allowed_r_files_, requested_filename, NULL) && |
| 508 GetFileNameInWhitelist(allowed_w_files_, requested_filename, | 512 GetFileNameInWhitelist(allowed_w_files_, requested_filename, |
| 509 file_to_open); | 513 file_to_open); |
| 510 return allowed_for_read_and_write; | 514 return allowed_for_read_and_write; |
| 511 } | 515 } |
| 512 default: | 516 default: |
| 513 return false; | 517 return false; |
| 514 } | 518 } |
| 515 } | 519 } |
| 516 | 520 |
| 517 } // namespace sandbox. | 521 } // namespace sandbox. |
| OLD | NEW |