// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/sandbox_parameters_mac.h" #include #include "base/apple/bundle_locations.h" #include "base/apple/foundation_util.h" #include "base/check.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/files/file_util.h" #include "base/mac/mac_util.h" #include "base/no_destructor.h" #include "base/numerics/checked_math.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "base/system/sys_info.h" #include "components/services/screen_ai/buildflags/buildflags.h" #include "content/browser/mac_helpers.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_client.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "ppapi/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h" #include "sandbox/mac/sandbox_compiler.h" #include "sandbox/policy/mac/params.h" #include "sandbox/policy/mac/sandbox_mac.h" #include "sandbox/policy/mojom/sandbox.mojom.h" #include "sandbox/policy/switches.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace content { #if defined(TOOLKIT_QT) base::FilePath getSandboxPath(); #endif namespace { absl::optional& GetNetworkTestCertsDirectory() { // Set by SetNetworkTestCertsDirectoryForTesting(). static base::NoDestructor> network_test_certs_dir; return *network_test_certs_dir; } // Produce the OS version as an integer "1010", etc. and pass that to the // profile. The profile converts the string back to a number and can do // comparison operations on OS version. std::string GetOSVersion() { int32_t major_version, minor_version, bugfix_version; base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, &bugfix_version); base::CheckedNumeric os_version(major_version); os_version *= 100; os_version += minor_version; int32_t final_os_version = os_version.ValueOrDie(); return std::to_string(final_os_version); } // Retrieves the users shared darwin dirs and adds it to the profile. void AddDarwinDirs(sandbox::SandboxCompiler* compiler) { char dir_path[PATH_MAX + 1]; size_t rv = confstr(_CS_DARWIN_USER_CACHE_DIR, dir_path, sizeof(dir_path)); PCHECK(rv != 0); CHECK(compiler->SetParameter( sandbox::policy::kParamDarwinUserCacheDir, sandbox::policy::GetCanonicalPath(base::FilePath(dir_path)).value())); rv = confstr(_CS_DARWIN_USER_DIR, dir_path, sizeof(dir_path)); PCHECK(rv != 0); CHECK(compiler->SetParameter( sandbox::policy::kParamDarwinUserDir, sandbox::policy::GetCanonicalPath(base::FilePath(dir_path)).value())); rv = confstr(_CS_DARWIN_USER_TEMP_DIR, dir_path, sizeof(dir_path)); PCHECK(rv != 0); CHECK(compiler->SetParameter( sandbox::policy::kParamDarwinUserTempDir, sandbox::policy::GetCanonicalPath(base::FilePath(dir_path)).value())); } // All of the below functions populate the |client| with the parameters that the // sandbox needs to resolve information that cannot be known at build time, such // as the user's home directory. void SetupCommonSandboxParameters(sandbox::SandboxCompiler* compiler, const base::CommandLine& target_command_line) { const base::CommandLine* browser_command_line = base::CommandLine::ForCurrentProcess(); bool enable_logging = browser_command_line->HasSwitch( sandbox::policy::switches::kEnableSandboxLogging); CHECK(compiler->SetParameter( sandbox::policy::kParamExecutablePath, sandbox::policy::GetCanonicalPath(target_command_line.GetProgram()) .value())); CHECK(compiler->SetBooleanParameter(sandbox::policy::kParamEnableLogging, enable_logging)); CHECK(compiler->SetBooleanParameter( sandbox::policy::kParamDisableSandboxDenialLogging, !enable_logging)); std::string bundle_path = sandbox::policy::GetCanonicalPath(base::apple::MainBundlePath()).value(); CHECK(compiler->SetParameter(sandbox::policy::kParamBundlePath, bundle_path)); std::string bundle_id = base::apple::BaseBundleID(); DCHECK(!bundle_id.empty()) << "base::apple::OuterBundle is unset"; CHECK(compiler->SetParameter(sandbox::policy::kParamBundleId, bundle_id)); CHECK(compiler->SetParameter(sandbox::policy::kParamBrowserPid, base::NumberToString(getpid()))); std::string logging_path = GetContentClient() ->browser() ->GetLoggingFileName(*browser_command_line) .value(); CHECK( compiler->SetParameter(sandbox::policy::kParamLogFilePath, logging_path)); #if defined(COMPONENT_BUILD) // For component builds, allow access to one directory level higher, where // the dylibs live. base::FilePath component_path = base::apple::MainBundlePath().Append(".."); std::string component_path_canonical = sandbox::policy::GetCanonicalPath(component_path).value(); CHECK(compiler->SetParameter(sandbox::policy::kParamComponentPath, component_path_canonical)); #endif CHECK( compiler->SetParameter(sandbox::policy::kParamOsVersion, GetOSVersion())); #if defined(TOOLKIT_QT) // Allow read access to files under the Qt path. const base::FilePath qt_prefix_path = getSandboxPath(); const std::string qt_prefix_path_canonical = sandbox::policy::GetCanonicalPath(qt_prefix_path).value(); CHECK(compiler->SetParameter(sandbox::policy::kParamQtPrefixPath, qt_prefix_path_canonical)); #endif std::string homedir = sandbox::policy::GetCanonicalPath(base::GetHomeDir()).value(); CHECK( compiler->SetParameter(sandbox::policy::kParamHomedirAsLiteral, homedir)); CHECK(compiler->SetBooleanParameter( sandbox::policy::kParamFilterSyscalls, base::FeatureList::IsEnabled(features::kMacSyscallSandbox))); CHECK(compiler->SetBooleanParameter( sandbox::policy::kParamFilterSyscallsDebug, false)); } void SetupNetworkSandboxParameters(sandbox::SandboxCompiler* compiler, const base::CommandLine& command_line) { SetupCommonSandboxParameters(compiler, command_line); std::vector storage_paths = GetContentClient()->browser()->GetNetworkContextsParentDirectory(); AddDarwinDirs(compiler); CHECK(compiler->SetParameter( sandbox::policy::kParamNetworkServiceStoragePathsCount, base::NumberToString(storage_paths.size()))); for (size_t i = 0; i < storage_paths.size(); ++i) { base::FilePath path = sandbox::policy::GetCanonicalPath(storage_paths[i]); std::string param_name = base::StringPrintf( "%s%zu", sandbox::policy::kParamNetworkServiceStoragePathN, i); CHECK(compiler->SetParameter(param_name, path.value())) << param_name; } if (GetNetworkTestCertsDirectory().has_value()) { CHECK(compiler->SetParameter( sandbox::policy::kParamNetworkServiceTestCertsDir, sandbox::policy::GetCanonicalPath(*GetNetworkTestCertsDirectory()) .value())); } } #if BUILDFLAG(ENABLE_PPAPI) void SetupPPAPISandboxParameters( const std::vector& plugins, sandbox::SandboxCompiler* compiler, const base::CommandLine& command_line) { SetupCommonSandboxParameters(compiler, command_line); base::FilePath bundle_path = sandbox::policy::GetCanonicalPath(base::apple::MainBundlePath()); const std::string param_base_name = "PPAPI_PATH_"; int index = 0; for (const auto& plugin : plugins) { // Only add plugins which are external to Chrome's bundle to the profile. if (!bundle_path.IsParent(plugin.path) && plugin.path.IsAbsolute()) { std::string param_name = param_base_name + base::StringPrintf("%d", index++); CHECK(compiler->SetParameter(param_name, plugin.path.value())); } } // The profile does not support more than 4 PPAPI plugins, but it will be set // to n+1 more than the plugins added. CHECK(index <= 5); } #endif void SetupGpuSandboxParameters(sandbox::SandboxCompiler* compiler, const base::CommandLine& command_line) { SetupCommonSandboxParameters(compiler, command_line); AddDarwinDirs(compiler); CHECK(compiler->SetBooleanParameter( sandbox::policy::kParamDisableMetalShaderCache, command_line.HasSwitch( sandbox::policy::switches::kDisableMetalShaderCache))); base::FilePath helper_bundle_path = base::apple::GetInnermostAppBundlePath(command_line.GetProgram()); // The helper may not be contained in an app bundle for unit tests. // In that case `kParamHelperBundleId` will remain unset. if (!helper_bundle_path.empty()) { @autoreleasepool { NSBundle* helper_bundle = [NSBundle bundleWithPath:base::SysUTF8ToNSString(helper_bundle_path.value())]; CHECK(helper_bundle); CHECK(compiler->SetParameter( sandbox::policy::kParamHelperBundleId, base::SysNSStringToUTF8(helper_bundle.bundleIdentifier))); } } } } // namespace void SetupSandboxParameters(sandbox::mojom::Sandbox sandbox_type, const base::CommandLine& command_line, #if BUILDFLAG(ENABLE_PPAPI) const std::vector& plugins, #endif sandbox::SandboxCompiler* compiler) { switch (sandbox_type) { case sandbox::mojom::Sandbox::kAudio: case sandbox::mojom::Sandbox::kCdm: case sandbox::mojom::Sandbox::kMirroring: case sandbox::mojom::Sandbox::kNaClLoader: #if BUILDFLAG(ENABLE_OOP_PRINTING) case sandbox::mojom::Sandbox::kPrintBackend: #endif case sandbox::mojom::Sandbox::kPrintCompositor: case sandbox::mojom::Sandbox::kRenderer: case sandbox::mojom::Sandbox::kService: case sandbox::mojom::Sandbox::kServiceWithJit: case sandbox::mojom::Sandbox::kUtility: SetupCommonSandboxParameters(compiler, command_line); break; case sandbox::mojom::Sandbox::kGpu: { SetupGpuSandboxParameters(compiler, command_line); break; } case sandbox::mojom::Sandbox::kNetwork: SetupNetworkSandboxParameters(compiler, command_line); break; #if BUILDFLAG(ENABLE_PPAPI) case sandbox::mojom::Sandbox::kPpapi: SetupPPAPISandboxParameters(plugins, compiler, command_line); break; #endif case sandbox::mojom::Sandbox::kNoSandbox: CHECK(false) << "Unhandled parameters for sandbox_type " << static_cast(sandbox_type); break; // Setup parameters for sandbox types handled by embedders below. #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) case sandbox::mojom::Sandbox::kScreenAI: #endif case sandbox::mojom::Sandbox::kSpeechRecognition: SetupCommonSandboxParameters(compiler, command_line); CHECK(GetContentClient()->browser()->SetupEmbedderSandboxParameters( sandbox_type, compiler)); } } void SetNetworkTestCertsDirectoryForTesting(const base::FilePath& path) { GetNetworkTestCertsDirectory().emplace(path); } } // namespace content