broker_permission_list.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2014 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. #include "sandbox/linux/syscall_broker/broker_permission_list.h"
  5. #include <fcntl.h>
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <string.h>
  9. #include <string>
  10. #include <vector>
  11. #include "base/check_op.h"
  12. #include "base/logging.h"
  13. #include "sandbox/linux/syscall_broker/broker_command.h"
  14. namespace sandbox {
  15. namespace syscall_broker {
  16. namespace {
  17. bool CheckCallerArgs(const char** file_to_access) {
  18. if (file_to_access && *file_to_access) {
  19. // Make sure that callers never pass a non-empty string. In case callers
  20. // wrongly forget to check the return value and look at the string
  21. // instead, this could catch bugs.
  22. RAW_LOG(FATAL, "*file_to_access should be nullptr");
  23. return false;
  24. }
  25. return true;
  26. }
  27. } // namespace
  28. BrokerPermissionList::BrokerPermissionList(
  29. int denied_errno,
  30. std::vector<BrokerFilePermission> permissions)
  31. : denied_errno_(denied_errno),
  32. permissions_(std::move(permissions)),
  33. num_of_permissions_(permissions_.size()) {
  34. // The spec guarantees vectors store their elements contiguously
  35. // so set up a pointer to array of element so it can be used
  36. // in async signal safe code instead of vector operations.
  37. if (num_of_permissions_ > 0) {
  38. permissions_array_ = &permissions_[0];
  39. } else {
  40. permissions_array_ = nullptr;
  41. }
  42. }
  43. BrokerPermissionList::~BrokerPermissionList() = default;
  44. // Check if calling access() should be allowed on |requested_filename| with
  45. // mode |requested_mode|.
  46. // Note: access() being a system call to check permissions, this can get a bit
  47. // confusing. We're checking if calling access() should even be allowed with
  48. // the same policy we would use for open().
  49. // If |file_to_access| is not nullptr, we will return the matching pointer from
  50. // the allowlist. For paranoia a caller should then use |file_to_access|. See
  51. // GetFileNameIfAllowedToOpen() for more explanation.
  52. // return true if calling access() on this file should be allowed, false
  53. // otherwise.
  54. // Async signal safe if and only if |file_to_access| is nullptr.
  55. bool BrokerPermissionList::GetFileNameIfAllowedToAccess(
  56. const char* requested_filename,
  57. int requested_mode,
  58. const char** file_to_access) const {
  59. if (!CheckCallerArgs(file_to_access))
  60. return false;
  61. for (size_t i = 0; i < num_of_permissions_; i++) {
  62. if (permissions_array_[i].CheckAccess(requested_filename, requested_mode,
  63. file_to_access)) {
  64. return true;
  65. }
  66. }
  67. return false;
  68. }
  69. // Check if |requested_filename| can be opened with flags |requested_flags|.
  70. // If |file_to_open| is not nullptr, we will return the matching pointer from
  71. // the allowlist. For paranoia, a caller should then use |file_to_open| rather
  72. // than |requested_filename|, so that it never attempts to open an
  73. // attacker-controlled file name, even if an attacker managed to fool the
  74. // string comparison mechanism.
  75. // Return true if opening should be allowed, false otherwise.
  76. // Async signal safe if and only if |file_to_open| is nullptr.
  77. bool BrokerPermissionList::GetFileNameIfAllowedToOpen(
  78. const char* requested_filename,
  79. int requested_flags,
  80. const char** file_to_open,
  81. bool* unlink_after_open) const {
  82. if (!CheckCallerArgs(file_to_open))
  83. return false;
  84. for (size_t i = 0; i < num_of_permissions_; i++) {
  85. if (permissions_array_[i].CheckOpen(requested_filename, requested_flags,
  86. file_to_open, unlink_after_open)) {
  87. return true;
  88. }
  89. }
  90. return false;
  91. }
  92. bool BrokerPermissionList::GetFileNameIfAllowedToStat(
  93. const char* requested_filename,
  94. const char** file_to_stat) const {
  95. if (!CheckCallerArgs(file_to_stat))
  96. return false;
  97. for (size_t i = 0; i < num_of_permissions_; i++) {
  98. if (permissions_array_[i].CheckStat(requested_filename, file_to_stat))
  99. return true;
  100. }
  101. return false;
  102. }
  103. } // namespace syscall_broker
  104. } // namespace sandbox