1 // Copyright 2017 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 "base/command_line.h"
6 #include "base/feature_list.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/path_service.h"
9 #include "base/posix/global_descriptors.h"
10 #include "base/strings/stringprintf.h"
11 #include "build/build_config.h"
12 #include "content/browser/child_process_launcher.h"
13 #include "content/browser/child_process_launcher_helper.h"
14 #include "content/browser/child_process_launcher_helper_posix.h"
15 #include "content/browser/child_process_task_port_provider_mac.h"
16 #include "content/browser/sandbox_parameters_mac.h"
17 #include "content/grit/content_resources.h"
18 #include "content/public/browser/child_process_launcher_utils.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/common/content_features.h"
21 #include "content/public/common/content_paths.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/result_codes.h"
24 #include "content/public/common/sandboxed_process_launcher_delegate.h"
25 #include "sandbox/mac/seatbelt_exec.h"
26 #include "sandbox/policy/mac/sandbox_mac.h"
27 #include "sandbox/policy/sandbox.h"
28 #include "sandbox/policy/sandbox_type.h"
29 #include "sandbox/policy/switches.h"
30 
31 namespace content {
32 namespace internal {
33 
34 base::Optional<mojo::NamedPlatformChannel>
CreateNamedPlatformChannelOnClientThread()35 ChildProcessLauncherHelper::CreateNamedPlatformChannelOnClientThread() {
36   DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
37   return base::nullopt;
38 }
39 
BeforeLaunchOnClientThread()40 void ChildProcessLauncherHelper::BeforeLaunchOnClientThread() {
41   DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
42 }
43 
44 std::unique_ptr<PosixFileDescriptorInfo>
GetFilesToMap()45 ChildProcessLauncherHelper::GetFilesToMap() {
46   DCHECK(CurrentlyOnProcessLauncherTaskRunner());
47   return CreateDefaultPosixFilesToMap(
48       child_process_id(), mojo_channel_->remote_endpoint(),
49       /*files_to_preload=*/{}, GetProcessType(), command_line());
50 }
51 
BeforeLaunchOnLauncherThread(FileMappedForLaunch & files_to_register,base::LaunchOptions * options)52 bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
53     FileMappedForLaunch& files_to_register,
54     base::LaunchOptions* options) {
55   // Convert FD mapping to FileHandleMappingVector.
56   options->fds_to_remap = files_to_register.GetMappingWithIDAdjustment(
57       base::GlobalDescriptors::kBaseDescriptor);
58 
59   base::FieldTrialList::InsertFieldTrialHandleIfNeeded(
60       &options->mach_ports_for_rendezvous);
61 
62   mojo::PlatformHandle endpoint =
63       mojo_channel_->TakeRemoteEndpoint().TakePlatformHandle();
64   DCHECK(endpoint.is_valid_mach_receive());
65   options->mach_ports_for_rendezvous.insert(std::make_pair(
66       'mojo', base::MachRendezvousPort(endpoint.TakeMachReceiveRight())));
67 
68 #if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
69   options->launch_x86_64 = delegate_->LaunchX86_64();
70 #endif  // OS_MAC && ARCH_CPU_ARM64
71 
72   options->environment = delegate_->GetEnvironment();
73 
74   options->disclaim_responsibility = delegate_->DisclaimResponsibility();
75 
76   auto sandbox_type =
77       sandbox::policy::SandboxTypeFromCommandLine(*command_line_);
78 
79   bool no_sandbox =
80       command_line_->HasSwitch(sandbox::policy::switches::kNoSandbox) ||
81       sandbox::policy::IsUnsandboxedSandboxType(sandbox_type);
82 
83   bool use_v2 = (sandbox_type != sandbox::policy::SandboxType::kGpu) ||
84                 base::FeatureList::IsEnabled(features::kMacV2GPUSandbox);
85 
86   if (use_v2 && !no_sandbox) {
87     // Generate the profile string.
88     std::string profile =
89         sandbox::policy::SandboxMac::GetSandboxProfile(sandbox_type);
90 
91     // Disable os logging to com.apple.diagnosticd which is a performance
92     // problem.
93     options->environment.insert(std::make_pair("OS_ACTIVITY_MODE", "disable"));
94 
95     seatbelt_exec_client_ = std::make_unique<sandbox::SeatbeltExecClient>();
96     seatbelt_exec_client_->SetProfile(profile);
97 
98     SetupSandboxParameters(sandbox_type, *command_line_.get(),
99                            seatbelt_exec_client_.get());
100 
101     int pipe = seatbelt_exec_client_->GetReadFD();
102     if (pipe < 0) {
103       LOG(ERROR) << "The file descriptor for the sandboxed child is invalid.";
104       return false;
105     }
106 
107     options->fds_to_remap.push_back(std::make_pair(pipe, pipe));
108 
109     // Update the command line to enable the V2 sandbox and pass the
110     // communication FD to the helper executable.
111     command_line_->AppendArg(
112         base::StringPrintf("%s%d", sandbox::switches::kSeatbeltClient, pipe));
113   }
114 
115   return true;
116 }
117 
118 ChildProcessLauncherHelper::Process
LaunchProcessOnLauncherThread(const base::LaunchOptions & options,std::unique_ptr<PosixFileDescriptorInfo> files_to_register,bool * is_synchronous_launch,int * launch_result)119 ChildProcessLauncherHelper::LaunchProcessOnLauncherThread(
120     const base::LaunchOptions& options,
121     std::unique_ptr<PosixFileDescriptorInfo> files_to_register,
122     bool* is_synchronous_launch,
123     int* launch_result) {
124   *is_synchronous_launch = true;
125   ChildProcessLauncherHelper::Process process;
126   process.process = base::LaunchProcess(*command_line(), options);
127   *launch_result = process.process.IsValid() ? LAUNCH_RESULT_SUCCESS
128                                              : LAUNCH_RESULT_FAILURE;
129   return process;
130 }
131 
AfterLaunchOnLauncherThread(const ChildProcessLauncherHelper::Process & process,const base::LaunchOptions & options)132 void ChildProcessLauncherHelper::AfterLaunchOnLauncherThread(
133     const ChildProcessLauncherHelper::Process& process,
134     const base::LaunchOptions& options) {
135   // Send the sandbox profile after launch so that the child will exist and be
136   // waiting for the message on its side of the pipe.
137   if (process.process.IsValid() && seatbelt_exec_client_.get() != nullptr) {
138     seatbelt_exec_client_->SendProfile();
139   }
140 }
141 
GetTerminationInfo(const ChildProcessLauncherHelper::Process & process,bool known_dead)142 ChildProcessTerminationInfo ChildProcessLauncherHelper::GetTerminationInfo(
143     const ChildProcessLauncherHelper::Process& process,
144     bool known_dead) {
145   ChildProcessTerminationInfo info;
146   info.status = known_dead ? base::GetKnownDeadTerminationStatus(
147                                  process.process.Handle(), &info.exit_code)
148                            : base::GetTerminationStatus(
149                                  process.process.Handle(), &info.exit_code);
150   return info;
151 }
152 
153 // static
TerminateProcess(const base::Process & process,int exit_code)154 bool ChildProcessLauncherHelper::TerminateProcess(const base::Process& process,
155                                                   int exit_code) {
156   // TODO(https://crbug.com/818244): Determine whether we should also call
157   // EnsureProcessTerminated() to make sure of process-exit, and reap it.
158   return process.Terminate(exit_code, false);
159 }
160 
161 // static
ForceNormalProcessTerminationSync(ChildProcessLauncherHelper::Process process)162 void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync(
163     ChildProcessLauncherHelper::Process process) {
164   DCHECK(CurrentlyOnProcessLauncherTaskRunner());
165   // Client has gone away, so just kill the process.  Using exit code 0 means
166   // that UMA won't treat this as a crash.
167   process.process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
168   base::EnsureProcessTerminated(std::move(process.process));
169 }
170 
SetProcessPriorityOnLauncherThread(base::Process process,const ChildProcessLauncherPriority & priority)171 void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread(
172     base::Process process,
173     const ChildProcessLauncherPriority& priority) {
174   if (process.CanBackgroundProcesses()) {
175     process.SetProcessBackgrounded(ChildProcessTaskPortProvider::GetInstance(),
176                                    priority.is_background());
177   }
178 }
179 
180 // static
OpenFileToShare(const base::FilePath & path,base::MemoryMappedFile::Region * region)181 base::File OpenFileToShare(const base::FilePath& path,
182                            base::MemoryMappedFile::Region* region) {
183   // Not used yet (until required files are described in the service manifest on
184   // Mac).
185   NOTREACHED();
186   return base::File();
187 }
188 
189 }  //  namespace internal
190 }  // namespace content
191