|  | // 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 <unistd.h> | 
|  |  | 
|  | #include "base/check.h" | 
|  | #include "base/command_line.h" | 
|  | #include "base/feature_list.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/mac/bundle_locations.h" | 
|  | #include "base/mac/foundation_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/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 { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | absl::optional<base::FilePath>& GetNetworkTestCertsDirectory() { | 
|  | // Set by SetNetworkTestCertsDirectoryForTesting(). | 
|  | static base::NoDestructor<absl::optional<base::FilePath>> | 
|  | 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<int32_t> 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 `compiler` 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::mac::MainBundlePath()).value(); | 
|  | CHECK(compiler->SetParameter(sandbox::policy::kParamBundlePath, bundle_path)); | 
|  |  | 
|  | std::string bundle_id = base::mac::BaseBundleID(); | 
|  | DCHECK(!bundle_id.empty()) << "base::mac::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::mac::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())); | 
|  |  | 
|  | 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<base::FilePath> 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<content::WebPluginInfo>& plugins, | 
|  | sandbox::SandboxCompiler* compiler, | 
|  | const base::CommandLine& command_line) { | 
|  | SetupCommonSandboxParameters(compiler, command_line); | 
|  |  | 
|  | base::FilePath bundle_path = | 
|  | sandbox::policy::GetCanonicalPath(base::mac::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))); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | void SetupSandboxParameters(sandbox::mojom::Sandbox sandbox_type, | 
|  | const base::CommandLine& command_line, | 
|  | #if BUILDFLAG(ENABLE_PPAPI) | 
|  | const std::vector<content::WebPluginInfo>& 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<int>(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 |