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 3// found in the LICENSE file. 4 5#include "services/service_manager/sandbox/mac/sandbox_mac.h" 6 7#import <Cocoa/Cocoa.h> 8#include <stddef.h> 9#include <stdint.h> 10 11#include <CoreFoundation/CFTimeZone.h> 12#include <signal.h> 13#include <sys/param.h> 14 15#include <algorithm> 16#include <iterator> 17#include <map> 18#include <string> 19 20#include "base/command_line.h" 21#include "base/compiler_specific.h" 22#include "base/files/file_util.h" 23#include "base/files/scoped_file.h" 24#include "base/mac/bundle_locations.h" 25#include "base/mac/foundation_util.h" 26#include "base/mac/mac_util.h" 27#include "base/mac/mach_port_rendezvous.h" 28#include "base/mac/scoped_cftyperef.h" 29#include "base/mac/scoped_nsobject.h" 30#include "base/rand_util.h" 31#include "base/stl_util.h" 32#include "base/strings/string16.h" 33#include "base/strings/string_piece.h" 34#include "base/strings/string_split.h" 35#include "base/strings/string_util.h" 36#include "base/strings/stringprintf.h" 37#include "base/strings/sys_string_conversions.h" 38#include "base/strings/utf_string_conversions.h" 39#include "base/system/sys_info.h" 40#include "sandbox/mac/sandbox_compiler.h" 41#include "services/service_manager/sandbox/mac/audio.sb.h" 42#include "services/service_manager/sandbox/mac/cdm.sb.h" 43#include "services/service_manager/sandbox/mac/common.sb.h" 44#include "services/service_manager/sandbox/mac/gpu.sb.h" 45#include "services/service_manager/sandbox/mac/gpu_v2.sb.h" 46#include "services/service_manager/sandbox/mac/nacl_loader.sb.h" 47#include "services/service_manager/sandbox/mac/network.sb.h" 48#include "services/service_manager/sandbox/mac/ppapi.sb.h" 49#include "services/service_manager/sandbox/mac/print_compositor.sb.h" 50#include "services/service_manager/sandbox/mac/renderer.sb.h" 51#include "services/service_manager/sandbox/mac/utility.sb.h" 52#include "services/service_manager/sandbox/sandbox_type.h" 53#include "services/service_manager/sandbox/switches.h" 54 55namespace service_manager { 56 57// Static variable declarations. 58const char* SandboxMac::kSandboxBrowserPID = "BROWSER_PID"; 59const char* SandboxMac::kSandboxBundlePath = "BUNDLE_PATH"; 60const char* SandboxMac::kSandboxChromeBundleId = "BUNDLE_ID"; 61const char* SandboxMac::kSandboxComponentPath = "COMPONENT_PATH"; 62#if defined(TOOLKIT_QT) 63const char* SandboxMac::kSandboxQtPrefixPath = "QT_PREFIX_PATH"; 64#endif 65const char* SandboxMac::kSandboxDisableDenialLogging = 66 "DISABLE_SANDBOX_DENIAL_LOGGING"; 67const char* SandboxMac::kSandboxEnableLogging = "ENABLE_LOGGING"; 68const char* SandboxMac::kSandboxHomedirAsLiteral = "USER_HOMEDIR_AS_LITERAL"; 69const char* SandboxMac::kSandboxLoggingPathAsLiteral = "LOG_FILE_PATH"; 70const char* SandboxMac::kSandboxOSVersion = "OS_VERSION"; 71const char* SandboxMac::kSandboxElCapOrLater = "ELCAP_OR_LATER"; 72const char* SandboxMac::kSandboxMacOS1013 = "MACOS_1013"; 73const char* SandboxMac::kSandboxFieldTrialSeverName = "FIELD_TRIAL_SERVER_NAME"; 74const char* SandboxMac::kSandboxBundleVersionPath = "BUNDLE_VERSION_PATH"; 75 76// Warm up System APIs that empirically need to be accessed before the Sandbox 77// is turned on. 78// This method is layed out in blocks, each one containing a separate function 79// that needs to be warmed up. The OS version on which we found the need to 80// enable the function is also noted. 81// This function is tested on the following OS versions: 82// 10.5.6, 10.6.0 83 84// static 85void SandboxMac::Warmup(SandboxType sandbox_type) { 86 DCHECK_EQ(sandbox_type, SandboxType::kGpu); 87 88 @autoreleasepool { 89 { // CGColorSpaceCreateWithName(), CGBitmapContextCreate() - 10.5.6 90 base::ScopedCFTypeRef<CGColorSpaceRef> rgb_colorspace( 91 CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)); 92 93 // Allocate a 1x1 image. 94 char data[4]; 95 base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate( 96 data, 1, 1, 8, 1 * 4, rgb_colorspace, 97 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); 98 99 // Load in the color profiles we'll need (as a side effect). 100 ignore_result(base::mac::GetSRGBColorSpace()); 101 ignore_result(base::mac::GetSystemColorSpace()); 102 103 // CGColorSpaceCreateSystemDefaultCMYK - 10.6 104 base::ScopedCFTypeRef<CGColorSpaceRef> cmyk_colorspace( 105 CGColorSpaceCreateWithName(kCGColorSpaceGenericCMYK)); 106 } 107 108 { // localtime() - 10.5.6 109 time_t tv = {0}; 110 localtime(&tv); 111 } 112 113 { // Gestalt() tries to read 114 // /System/Library/CoreServices/SystemVersion.plist 115 // on 10.5.6 116 int32_t tmp; 117 base::SysInfo::OperatingSystemVersionNumbers(&tmp, &tmp, &tmp); 118 } 119 120 { // CGImageSourceGetStatus() - 10.6 121 // Create a png with just enough data to get everything warmed up... 122 char png_header[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; 123 NSData* data = [NSData dataWithBytes:png_header 124 length:base::size(png_header)]; 125 base::ScopedCFTypeRef<CGImageSourceRef> img( 126 CGImageSourceCreateWithData((CFDataRef)data, NULL)); 127 CGImageSourceGetStatus(img); 128 } 129 130 { 131 // Allow access to /dev/urandom. 132 base::GetUrandomFD(); 133 } 134 135 { // IOSurfaceLookup() - 10.7 136 // Needed by zero-copy texture update framework - crbug.com/323338 137 base::ScopedCFTypeRef<IOSurfaceRef> io_surface(IOSurfaceLookup(0)); 138 } 139 } 140} 141 142// Load the appropriate template for the given sandbox type. 143// Returns the template as a string or an empty string on error. 144std::string LoadSandboxTemplate(SandboxType sandbox_type) { 145 DCHECK_EQ(sandbox_type, SandboxType::kGpu); 146 return kSeatbeltPolicyString_gpu; 147} 148 149// Turns on the OS X sandbox for this process. 150 151// static 152bool SandboxMac::Enable(SandboxType sandbox_type) { 153 DCHECK_EQ(sandbox_type, SandboxType::kGpu); 154 155 std::string sandbox_data = LoadSandboxTemplate(sandbox_type); 156 if (sandbox_data.empty()) 157 return false; 158 159 sandbox::SandboxCompiler compiler(sandbox_data); 160 161 // Enable verbose logging if enabled on the command line. (See common.sb 162 // for details). 163 const base::CommandLine* command_line = 164 base::CommandLine::ForCurrentProcess(); 165 bool enable_logging = 166 command_line->HasSwitch(switches::kEnableSandboxLogging); 167 if (!compiler.InsertBooleanParam(kSandboxEnableLogging, enable_logging)) 168 return false; 169 170 // Without this, the sandbox will print a message to the system log every 171 // time it denies a request. This floods the console with useless spew. 172 if (!compiler.InsertBooleanParam(kSandboxDisableDenialLogging, 173 !enable_logging)) 174 return false; 175 176 // Splice the path of the user's home directory into the sandbox profile 177 // (see renderer.sb for details). 178 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; 179 base::FilePath home_dir_canonical = 180 GetCanonicalPath(base::FilePath(home_dir)); 181 182 if (!compiler.InsertStringParam(kSandboxHomedirAsLiteral, 183 home_dir_canonical.value())) { 184 return false; 185 } 186 187 if (!compiler.InsertStringParam( 188 kSandboxFieldTrialSeverName, 189 base::MachPortRendezvousClient::GetBootstrapName())) { 190 return false; 191 } 192 193 bool elcap_or_later = base::mac::IsAtLeastOS10_11(); 194 if (!compiler.InsertBooleanParam(kSandboxElCapOrLater, elcap_or_later)) 195 return false; 196 197 bool macos_1013 = base::mac::IsOS10_13(); 198 if (!compiler.InsertBooleanParam(kSandboxMacOS1013, macos_1013)) 199 return false; 200 201 if (sandbox_type == service_manager::SandboxType::kGpu) { 202 base::FilePath bundle_path = 203 SandboxMac::GetCanonicalPath(base::mac::FrameworkBundlePath()); 204 if (!compiler.InsertStringParam(kSandboxBundleVersionPath, 205 bundle_path.value())) 206 return false; 207 } 208 209 // Initialize sandbox. 210 std::string error_str; 211 bool success = compiler.CompileAndApplyProfile(&error_str); 212 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " << error_str; 213 return success; 214} 215 216// static 217base::FilePath SandboxMac::GetCanonicalPath(const base::FilePath& path) { 218 base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); 219 if (!fd.is_valid()) { 220 DPLOG(ERROR) << "GetCanonicalSandboxPath() failed for: " << path.value(); 221 return path; 222 } 223 224 base::FilePath::CharType canonical_path[MAXPATHLEN]; 225 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { 226 DPLOG(ERROR) << "GetCanonicalSandboxPath() failed for: " << path.value(); 227 return path; 228 } 229 230 return base::FilePath(canonical_path); 231} 232 233// static 234std::string SandboxMac::GetSandboxProfile(SandboxType sandbox_type) { 235 std::string profile = 236 std::string(service_manager::kSeatbeltPolicyString_common); 237 238 switch (sandbox_type) { 239 case service_manager::SandboxType::kAudio: 240 profile += service_manager::kSeatbeltPolicyString_audio; 241 break; 242 case service_manager::SandboxType::kCdm: 243 profile += service_manager::kSeatbeltPolicyString_cdm; 244 break; 245 case service_manager::SandboxType::kGpu: 246 profile += service_manager::kSeatbeltPolicyString_gpu_v2; 247 break; 248 case service_manager::SandboxType::kNaClLoader: 249 profile += service_manager::kSeatbeltPolicyString_nacl_loader; 250 break; 251 case service_manager::SandboxType::kNetwork: 252 profile += service_manager::kSeatbeltPolicyString_network; 253 break; 254 case service_manager::SandboxType::kPpapi: 255 profile += service_manager::kSeatbeltPolicyString_ppapi; 256 break; 257 case service_manager::SandboxType::kPrintCompositor: 258 profile += service_manager::kSeatbeltPolicyString_print_compositor; 259 break; 260 case service_manager::SandboxType::kUtility: 261 profile += service_manager::kSeatbeltPolicyString_utility; 262 break; 263 case service_manager::SandboxType::kRenderer: 264 profile += service_manager::kSeatbeltPolicyString_renderer; 265 break; 266 case service_manager::SandboxType::kNoSandbox: 267 case service_manager::SandboxType::kInvalid: 268 case service_manager::SandboxType::kSoda: 269 CHECK(false); 270 break; 271 } 272 return profile; 273} 274 275} // namespace service_manager 276