1 // Copyright (c) 2013 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 "content/common/sandbox_linux/bpf_gpu_policy_linux.h" 6 7 #include <dlfcn.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <sys/socket.h> 11 #include <sys/stat.h> 12 #include <sys/types.h> 13 #include <unistd.h> 14 15 #include <string> 16 #include <vector> 17 18 #include "base/bind.h" 19 #include "base/command_line.h" 20 #include "base/compiler_specific.h" 21 #include "base/logging.h" 22 #include "base/memory/scoped_ptr.h" 23 #include "build/build_config.h" 24 #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h" 25 #include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h" 26 #include "content/common/set_process_title.h" 27 #include "content/public/common/content_switches.h" 28 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h" 29 #include "sandbox/linux/seccomp-bpf/trap.h" 30 #include "sandbox/linux/services/broker_process.h" 31 #include "sandbox/linux/services/linux_syscalls.h" 32 33 using sandbox::BrokerProcess; 34 using sandbox::SyscallSets; 35 using sandbox::arch_seccomp_data; 36 using sandbox::bpf_dsl::Allow; 37 using sandbox::bpf_dsl::ResultExpr; 38 39 namespace content { 40 41 namespace { 42 43 inline bool IsChromeOS() { 44 #if defined(OS_CHROMEOS) 45 return true; 46 #else 47 return false; 48 #endif 49 } 50 51 inline bool IsArchitectureX86_64() { 52 #if defined(__x86_64__) 53 return true; 54 #else 55 return false; 56 #endif 57 } 58 59 inline bool IsArchitectureI386() { 60 #if defined(__i386__) 61 return true; 62 #else 63 return false; 64 #endif 65 } 66 67 inline bool IsArchitectureArm() { 68 #if defined(__arm__) 69 return true; 70 #else 71 return false; 72 #endif 73 } 74 75 bool IsAcceleratedVideoEnabled() { 76 const base::CommandLine& command_line = 77 *base::CommandLine::ForCurrentProcess(); 78 bool accelerated_encode_enabled = false; 79 #if defined(OS_CHROMEOS) 80 accelerated_encode_enabled = 81 !command_line.HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode); 82 #endif 83 return !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode) || 84 accelerated_encode_enabled; 85 } 86 87 intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args, 88 void* aux_broker_process) { 89 RAW_CHECK(aux_broker_process); 90 BrokerProcess* broker_process = 91 static_cast<BrokerProcess*>(aux_broker_process); 92 switch (args.nr) { 93 case __NR_access: 94 return broker_process->Access(reinterpret_cast<const char*>(args.args[0]), 95 static_cast<int>(args.args[1])); 96 case __NR_open: 97 #if defined(MEMORY_SANITIZER) 98 // http://crbug.com/372840 99 __msan_unpoison_string(reinterpret_cast<const char*>(args.args[0])); 100 #endif 101 return broker_process->Open(reinterpret_cast<const char*>(args.args[0]), 102 static_cast<int>(args.args[1])); 103 case __NR_openat: 104 // Allow using openat() as open(). 105 if (static_cast<int>(args.args[0]) == AT_FDCWD) { 106 return 107 broker_process->Open(reinterpret_cast<const char*>(args.args[1]), 108 static_cast<int>(args.args[2])); 109 } else { 110 return -EPERM; 111 } 112 default: 113 RAW_CHECK(false); 114 return -ENOSYS; 115 } 116 } 117 118 class GpuBrokerProcessPolicy : public GpuProcessPolicy { 119 public: 120 static sandbox::bpf_dsl::SandboxBPFDSLPolicy* Create() { 121 return new GpuBrokerProcessPolicy(); 122 } 123 virtual ~GpuBrokerProcessPolicy() {} 124 125 virtual ResultExpr EvaluateSyscall(int system_call_number) const OVERRIDE; 126 127 private: 128 GpuBrokerProcessPolicy() {} 129 DISALLOW_COPY_AND_ASSIGN(GpuBrokerProcessPolicy); 130 }; 131 132 // x86_64/i386 or desktop ARM. 133 // A GPU broker policy is the same as a GPU policy with open and 134 // openat allowed. 135 ResultExpr GpuBrokerProcessPolicy::EvaluateSyscall(int sysno) const { 136 switch (sysno) { 137 case __NR_access: 138 case __NR_open: 139 case __NR_openat: 140 return Allow(); 141 default: 142 return GpuProcessPolicy::EvaluateSyscall(sysno); 143 } 144 } 145 146 void UpdateProcessTypeToGpuBroker() { 147 base::CommandLine::StringVector exec = 148 base::CommandLine::ForCurrentProcess()->GetArgs(); 149 base::CommandLine::Reset(); 150 base::CommandLine::Init(0, NULL); 151 base::CommandLine::ForCurrentProcess()->InitFromArgv(exec); 152 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 153 switches::kProcessType, "gpu-broker"); 154 155 // Update the process title. The argv was already cached by the call to 156 // SetProcessTitleFromCommandLine in content_main_runner.cc, so we can pass 157 // NULL here (we don't have the original argv at this point). 158 SetProcessTitleFromCommandLine(NULL); 159 } 160 161 bool UpdateProcessTypeAndEnableSandbox(sandbox::bpf_dsl::SandboxBPFDSLPolicy* ( 162 *broker_sandboxer_allocator)(void)) { 163 DCHECK(broker_sandboxer_allocator); 164 UpdateProcessTypeToGpuBroker(); 165 return SandboxSeccompBPF::StartSandboxWithExternalPolicy( 166 make_scoped_ptr(broker_sandboxer_allocator())); 167 } 168 169 } // namespace 170 171 GpuProcessPolicy::GpuProcessPolicy() : broker_process_(NULL) {} 172 173 GpuProcessPolicy::~GpuProcessPolicy() {} 174 175 // Main policy for x86_64/i386. Extended by CrosArmGpuProcessPolicy. 176 ResultExpr GpuProcessPolicy::EvaluateSyscall(int sysno) const { 177 switch (sysno) { 178 case __NR_ioctl: 179 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) 180 // The Nvidia driver uses flags not in the baseline policy 181 // (MAP_LOCKED | MAP_EXECUTABLE | MAP_32BIT) 182 case __NR_mmap: 183 #endif 184 // We also hit this on the linux_chromeos bot but don't yet know what 185 // weird flags were involved. 186 case __NR_mprotect: 187 // TODO(jln): restrict prctl. 188 case __NR_prctl: 189 case __NR_sched_getaffinity: 190 case __NR_sched_setaffinity: 191 case __NR_setpriority: 192 return Allow(); 193 case __NR_access: 194 case __NR_open: 195 case __NR_openat: 196 DCHECK(broker_process_); 197 return Trap(GpuSIGSYS_Handler, broker_process_); 198 default: 199 if (SyscallSets::IsEventFd(sysno)) 200 return Allow(); 201 202 // Default on the baseline policy. 203 return SandboxBPFBasePolicy::EvaluateSyscall(sysno); 204 } 205 } 206 207 bool GpuProcessPolicy::PreSandboxHook() { 208 // Warm up resources needed by the policy we're about to enable and 209 // eventually start a broker process. 210 const bool chromeos_arm_gpu = IsChromeOS() && IsArchitectureArm(); 211 // This policy is for x86 or Desktop. 212 DCHECK(!chromeos_arm_gpu); 213 214 DCHECK(!broker_process()); 215 // Create a new broker process. 216 InitGpuBrokerProcess( 217 GpuBrokerProcessPolicy::Create, 218 std::vector<std::string>(), // No extra files in whitelist. 219 std::vector<std::string>()); 220 221 if (IsArchitectureX86_64() || IsArchitectureI386()) { 222 // Accelerated video dlopen()'s some shared objects 223 // inside the sandbox, so preload them now. 224 if (IsAcceleratedVideoEnabled()) { 225 const char* I965DrvVideoPath = NULL; 226 227 if (IsArchitectureX86_64()) { 228 I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so"; 229 } else if (IsArchitectureI386()) { 230 I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so"; 231 } 232 233 dlopen(I965DrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); 234 dlopen("libva.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); 235 dlopen("libva-x11.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); 236 } 237 } 238 239 return true; 240 } 241 242 void GpuProcessPolicy::InitGpuBrokerProcess( 243 sandbox::bpf_dsl::SandboxBPFDSLPolicy* (*broker_sandboxer_allocator)(void), 244 const std::vector<std::string>& read_whitelist_extra, 245 const std::vector<std::string>& write_whitelist_extra) { 246 static const char kDriRcPath[] = "/etc/drirc"; 247 static const char kDriCard0Path[] = "/dev/dri/card0"; 248 249 CHECK(broker_process_ == NULL); 250 251 // All GPU process policies need these files brokered out. 252 std::vector<std::string> read_whitelist; 253 read_whitelist.push_back(kDriCard0Path); 254 read_whitelist.push_back(kDriRcPath); 255 // Add eventual extra files from read_whitelist_extra. 256 read_whitelist.insert(read_whitelist.end(), 257 read_whitelist_extra.begin(), 258 read_whitelist_extra.end()); 259 260 std::vector<std::string> write_whitelist; 261 write_whitelist.push_back(kDriCard0Path); 262 // Add eventual extra files from write_whitelist_extra. 263 write_whitelist.insert(write_whitelist.end(), 264 write_whitelist_extra.begin(), 265 write_whitelist_extra.end()); 266 267 broker_process_ = new BrokerProcess(GetFSDeniedErrno(), 268 read_whitelist, 269 write_whitelist); 270 // The initialization callback will perform generic initialization and then 271 // call broker_sandboxer_callback. 272 CHECK(broker_process_->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox, 273 broker_sandboxer_allocator))); 274 } 275 276 } // namespace content 277