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