// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sandbox/linux/syscall_broker/broker_policy.h" #include <fcntl.h> #include <stddef.h> #include <stdint.h> #include <string.h> #include <string> #include <vector> #include "base/logging.h" #include "sandbox/linux/syscall_broker/broker_common.h" namespace sandbox { namespace syscall_broker { BrokerPolicy::BrokerPolicy(int denied_errno, const std::vector<BrokerFilePermission>& permissions) : denied_errno_(denied_errno), permissions_(permissions), num_of_permissions_(permissions.size()) { // The spec guarantees vectors store their elements contiguously // so set up a pointer to array of element so it can be used // in async signal safe code instead of vector operations. if (num_of_permissions_ > 0) { permissions_array_ = &permissions_[0]; } else { permissions_array_ = NULL; } } BrokerPolicy::~BrokerPolicy() { } // Check if calling access() should be allowed on |requested_filename| with // mode |requested_mode|. // Note: access() being a system call to check permissions, this can get a bit // confusing. We're checking if calling access() should even be allowed with // the same policy we would use for open(). // If |file_to_access| is not NULL, we will return the matching pointer from // the whitelist. For paranoia a caller should then use |file_to_access|. See // GetFileNameIfAllowedToOpen() for more explanation. // return true if calling access() on this file should be allowed, false // otherwise. // Async signal safe if and only if |file_to_access| is NULL. bool BrokerPolicy::GetFileNameIfAllowedToAccess( const char* requested_filename, int requested_mode, const char** file_to_access) const { if (file_to_access && *file_to_access) { // Make sure that callers never pass a non-empty string. In case callers // wrongly forget to check the return value and look at the string // instead, this could catch bugs. RAW_LOG(FATAL, "*file_to_access should be NULL"); return false; } for (size_t i = 0; i < num_of_permissions_; i++) { if (permissions_array_[i].CheckAccess(requested_filename, requested_mode, file_to_access)) { return true; } } return false; } // Check if |requested_filename| can be opened with flags |requested_flags|. // If |file_to_open| is not NULL, we will return the matching pointer from the // whitelist. For paranoia, a caller should then use |file_to_open| rather // than |requested_filename|, so that it never attempts to open an // attacker-controlled file name, even if an attacker managed to fool the // string comparison mechanism. // Return true if opening should be allowed, false otherwise. // Async signal safe if and only if |file_to_open| is NULL. bool BrokerPolicy::GetFileNameIfAllowedToOpen(const char* requested_filename, int requested_flags, const char** file_to_open, bool* unlink_after_open) const { if (file_to_open && *file_to_open) { // Make sure that callers never pass a non-empty string. In case callers // wrongly forget to check the return value and look at the string // instead, this could catch bugs. RAW_LOG(FATAL, "*file_to_open should be NULL"); return false; } for (size_t i = 0; i < num_of_permissions_; i++) { if (permissions_array_[i].CheckOpen(requested_filename, requested_flags, file_to_open, unlink_after_open)) { return true; } } return false; } } // namespace syscall_broker } // namespace sandbox