Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Gabriel Charette | f385133 | 2022-04-28 23:39:18 | [diff] [blame] | 5 | #include "base/command_line.h" |
jcivelli | dad0cef | 2017-02-16 18:38:59 | [diff] [blame] | 6 | #include "base/path_service.h" |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 7 | #include "base/posix/global_descriptors.h" |
Alexander Alekseev | 0df843b | 2023-08-09 13:33:15 | [diff] [blame] | 8 | #include "base/trace_event/trace_event.h" |
Tom Sepez | d1a315b | 2018-01-11 18:18:00 | [diff] [blame] | 9 | #include "build/build_config.h" |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 10 | #include "content/browser/child_process_launcher.h" |
| 11 | #include "content/browser/child_process_launcher_helper.h" |
| 12 | #include "content/browser/child_process_launcher_helper_posix.h" |
Vladimir Levin | 11a23b1 | 2017-09-11 23:13:30 | [diff] [blame] | 13 | #include "content/browser/sandbox_host_linux.h" |
Robert Sesek | 8621aef0 | 2020-06-25 18:17:37 | [diff] [blame] | 14 | #include "content/browser/zygote_host/zygote_host_impl_linux.h" |
| 15 | #include "content/common/zygote/zygote_communication_linux.h" |
Xi Han | 89d93df | 2018-03-09 20:55:07 | [diff] [blame] | 16 | #include "content/public/browser/child_process_launcher_utils.h" |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 17 | #include "content/public/browser/content_browser_client.h" |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 18 | #include "content/public/common/content_client.h" |
Kuo-Hsin Yang | bff00c7 | 2020-02-14 05:59:23 | [diff] [blame] | 19 | #include "content/public/common/content_constants.h" |
Shintaro Kawamura | f29c8fdf | 2024-03-28 03:40:08 | [diff] [blame] | 20 | #include "content/public/common/content_features.h" |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 21 | #include "content/public/common/content_switches.h" |
| 22 | #include "content/public/common/result_codes.h" |
| 23 | #include "content/public/common/sandboxed_process_launcher_delegate.h" |
Robert Sesek | 8621aef0 | 2020-06-25 18:17:37 | [diff] [blame] | 24 | #include "content/public/common/zygote/sandbox_support_linux.h" |
| 25 | #include "content/public/common/zygote/zygote_handle.h" |
Robert Sesek | 7d0b49b | 2020-07-08 18:31:27 | [diff] [blame] | 26 | #include "sandbox/policy/linux/sandbox_linux.h" |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 27 | |
| 28 | namespace content { |
| 29 | namespace internal { |
| 30 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 31 | std::optional<mojo::NamedPlatformChannel> |
Will Harris | a7fb9d0 | 2023-02-15 02:08:24 | [diff] [blame] | 32 | ChildProcessLauncherHelper::CreateNamedPlatformChannelOnLauncherThread() { |
| 33 | DCHECK(CurrentlyOnProcessLauncherTaskRunner()); |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 34 | return std::nullopt; |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | void ChildProcessLauncherHelper::BeforeLaunchOnClientThread() { |
Ken Rockot | 8e23c3ab | 2019-08-01 23:39:10 | [diff] [blame] | 38 | DCHECK(client_task_runner_->RunsTasksInCurrentSequence()); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | std::unique_ptr<FileMappedForLaunch> |
| 42 | ChildProcessLauncherHelper::GetFilesToMap() { |
Xi Han | 89d93df | 2018-03-09 20:55:07 | [diff] [blame] | 43 | DCHECK(CurrentlyOnProcessLauncherTaskRunner()); |
Ken Rockot | 8dda8888 | 2019-12-04 05:56:22 | [diff] [blame] | 44 | return CreateDefaultPosixFilesToMap( |
Eriko Kurimoto | 9c83b40 | 2022-05-11 02:36:32 | [diff] [blame] | 45 | child_process_id(), mojo_channel_->remote_endpoint(), |
| 46 | file_data_->files_to_preload, GetProcessType(), command_line()); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 47 | } |
| 48 | |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 49 | bool ChildProcessLauncherHelper::IsUsingLaunchOptions() { |
Matthew Denton | 2bcef617 | 2023-01-18 01:14:24 | [diff] [blame] | 50 | return !GetZygoteForLaunch(); |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 51 | } |
| 52 | |
Greg Kerr | a1bc9d0 | 2018-01-04 23:22:31 | [diff] [blame] | 53 | bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread( |
Lucas Furukawa Gadani | 0d5e714 | 2019-04-18 23:00:50 | [diff] [blame] | 54 | PosixFileDescriptorInfo& files_to_register, |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 55 | base::LaunchOptions* options) { |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 56 | if (options) { |
Matthew Denton | 2bcef617 | 2023-01-18 01:14:24 | [diff] [blame] | 57 | DCHECK(!GetZygoteForLaunch()); |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 58 | // Convert FD mapping to FileHandleMappingVector |
| 59 | options->fds_to_remap = files_to_register.GetMappingWithIDAdjustment( |
| 60 | base::GlobalDescriptors::kBaseDescriptor); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 61 | |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 62 | if (GetProcessType() == switches::kRendererProcess) { |
| 63 | const int sandbox_fd = SandboxHostLinux::GetInstance()->GetChildSocket(); |
| 64 | options->fds_to_remap.emplace_back(sandbox_fd, GetSandboxFD()); |
| 65 | } |
| 66 | |
| 67 | options->environment = delegate_->GetEnvironment(); |
| 68 | } else { |
Matthew Denton | 2bcef617 | 2023-01-18 01:14:24 | [diff] [blame] | 69 | DCHECK(GetZygoteForLaunch()); |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 70 | // Environment variables could be supported in the future, but are not |
| 71 | // currently supported when launching with the zygote. |
| 72 | DCHECK(delegate_->GetEnvironment().empty()); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 73 | } |
| 74 | |
Greg Kerr | a1bc9d0 | 2018-01-04 23:22:31 | [diff] [blame] | 75 | return true; |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | ChildProcessLauncherHelper::Process |
| 79 | ChildProcessLauncherHelper::LaunchProcessOnLauncherThread( |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 80 | const base::LaunchOptions* options, |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 81 | std::unique_ptr<FileMappedForLaunch> files_to_register, |
| 82 | bool* is_synchronous_launch, |
| 83 | int* launch_result) { |
| 84 | *is_synchronous_launch = true; |
Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 85 | Process process; |
Matthew Denton | 2bcef617 | 2023-01-18 01:14:24 | [diff] [blame] | 86 | ZygoteCommunication* zygote_handle = GetZygoteForLaunch(); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 87 | if (zygote_handle) { |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 88 | // TODO(crbug.com/40448989): If chrome supported multiple zygotes they could |
jamescook | ca8595ad | 2017-05-01 16:58:33 | [diff] [blame] | 89 | // be created lazily here, or in the delegate GetZygote() implementations. |
| 90 | // Additionally, the delegate could provide a UseGenericZygote() method. |
| 91 | base::ProcessHandle handle = zygote_handle->ForkRequest( |
Tom Sepez | f60832d | 2018-01-08 23:35:50 | [diff] [blame] | 92 | command_line()->argv(), files_to_register->GetMapping(), |
| 93 | GetProcessType()); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 94 | *launch_result = LAUNCH_RESULT_SUCCESS; |
Tom Sepez | d1a315b | 2018-01-11 18:18:00 | [diff] [blame] | 95 | |
Xiaohan Wang | 1ecfd00 | 2022-01-19 22:33:10 | [diff] [blame] | 96 | #if !BUILDFLAG(IS_OPENBSD) |
Tom Sepez | d1a315b | 2018-01-11 18:18:00 | [diff] [blame] | 97 | if (handle) { |
Kuo-Hsin Yang | bff00c7 | 2020-02-14 05:59:23 | [diff] [blame] | 98 | // It could be a renderer process or an utility process. |
| 99 | int oom_score = content::kMiscOomScore; |
| 100 | if (command_line()->GetSwitchValueASCII(switches::kProcessType) == |
| 101 | switches::kRendererProcess) |
| 102 | oom_score = content::kLowestRendererOomScore; |
Robert Sesek | 8621aef0 | 2020-06-25 18:17:37 | [diff] [blame] | 103 | ZygoteHostImpl::GetInstance()->AdjustRendererOOMScore(handle, oom_score); |
Tom Sepez | d1a315b | 2018-01-11 18:18:00 | [diff] [blame] | 104 | } |
| 105 | #endif |
| 106 | |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 107 | process.process = base::Process(handle); |
jamescook | ca8595ad | 2017-05-01 16:58:33 | [diff] [blame] | 108 | process.zygote = zygote_handle; |
Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 109 | } else { |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 110 | process.process = base::LaunchProcess(*command_line(), *options); |
Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 111 | *launch_result = process.process.IsValid() ? LAUNCH_RESULT_SUCCESS |
| 112 | : LAUNCH_RESULT_FAILURE; |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 113 | } |
| 114 | |
Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 115 | #if BUILDFLAG(IS_CHROMEOS) |
Shintaro Kawamura | f726c129 | 2024-03-28 03:40:08 | [diff] [blame] | 116 | process_id_ = process.process.Pid(); |
| 117 | if (GetProcessType() == switches::kRendererProcess || |
| 118 | base::FeatureList::IsEnabled(features::kSchedQoSOnResourcedForChrome)) { |
Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 119 | process.process.InitializePriority(); |
| 120 | } |
| 121 | #endif |
| 122 | |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 123 | return process; |
| 124 | } |
| 125 | |
| 126 | void ChildProcessLauncherHelper::AfterLaunchOnLauncherThread( |
| 127 | const ChildProcessLauncherHelper::Process& process, |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 128 | const base::LaunchOptions* options) { |
Matthew Denton | c46d14cb | 2023-01-11 00:59:21 | [diff] [blame] | 129 | // Reset any FDs still held open. |
| 130 | file_data_.reset(); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 131 | } |
| 132 | |
Bo Liu | 0d2a232 | 2018-04-19 00:18:09 | [diff] [blame] | 133 | ChildProcessTerminationInfo ChildProcessLauncherHelper::GetTerminationInfo( |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 134 | const ChildProcessLauncherHelper::Process& process, |
Bo Liu | 0d2a232 | 2018-04-19 00:18:09 | [diff] [blame] | 135 | bool known_dead) { |
| 136 | ChildProcessTerminationInfo info; |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 137 | if (process.zygote) { |
Bo Liu | 0d2a232 | 2018-04-19 00:18:09 | [diff] [blame] | 138 | info.status = process.zygote->GetTerminationStatus( |
| 139 | process.process.Handle(), known_dead, &info.exit_code); |
| 140 | } else if (known_dead) { |
| 141 | info.status = base::GetKnownDeadTerminationStatus(process.process.Handle(), |
| 142 | &info.exit_code); |
| 143 | } else { |
| 144 | info.status = |
| 145 | base::GetTerminationStatus(process.process.Handle(), &info.exit_code); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 146 | } |
Bo Liu | 0d2a232 | 2018-04-19 00:18:09 | [diff] [blame] | 147 | return info; |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | // static |
Wez | 0abfbf51 | 2018-03-03 01:54:45 | [diff] [blame] | 151 | bool ChildProcessLauncherHelper::TerminateProcess(const base::Process& process, |
| 152 | int exit_code) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 153 | // TODO(crbug.com/40565504): Determine whether we should also call |
Wez | 0abfbf51 | 2018-03-03 01:54:45 | [diff] [blame] | 154 | // EnsureProcessTerminated() to make sure of process-exit, and reap it. |
| 155 | return process.Terminate(exit_code, false); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | // static |
| 159 | void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync( |
| 160 | ChildProcessLauncherHelper::Process process) { |
Alexander Alekseev | 0df843b | 2023-08-09 13:33:15 | [diff] [blame] | 161 | TRACE_EVENT0("chromeos", |
| 162 | "ChildProcessLauncherHelper::ForceNormalProcessTerminationSync"); |
Wez | c18a57c | 2018-04-02 20:20:14 | [diff] [blame] | 163 | DCHECK(CurrentlyOnProcessLauncherTaskRunner()); |
Ken Rockot | 1d00d6d0 | 2020-10-01 15:10:05 | [diff] [blame] | 164 | process.process.Terminate(RESULT_CODE_NORMAL_EXIT, false); |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 165 | // On POSIX, we must additionally reap the child. |
| 166 | if (process.zygote) { |
| 167 | // If the renderer was created via a zygote, we have to proxy the reaping |
| 168 | // through the zygote process. |
| 169 | process.zygote->EnsureProcessTerminated(process.process.Handle()); |
| 170 | } else { |
| 171 | base::EnsureProcessTerminated(std::move(process.process)); |
| 172 | } |
| 173 | } |
| 174 | |
Patrick Monette | 20997a2 | 2023-08-07 17:30:17 | [diff] [blame] | 175 | void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( |
boliu | 3e77d17 | 2017-05-11 04:56:04 | [diff] [blame] | 176 | base::Process process, |
Patrick Monette | 20997a2 | 2023-08-07 17:30:17 | [diff] [blame] | 177 | base::Process::Priority priority) { |
Xi Han | 89d93df | 2018-03-09 20:55:07 | [diff] [blame] | 178 | DCHECK(CurrentlyOnProcessLauncherTaskRunner()); |
Patrick Monette | 7a8ca386 | 2025-05-08 01:40:53 | [diff] [blame] | 179 | if (process.CanSetPriority()) { |
Patrick Monette | 20997a2 | 2023-08-07 17:30:17 | [diff] [blame] | 180 | process.SetPriority(priority); |
| 181 | } |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 182 | } |
| 183 | |
Matthew Denton | 2bcef617 | 2023-01-18 01:14:24 | [diff] [blame] | 184 | ZygoteCommunication* ChildProcessLauncherHelper::GetZygoteForLaunch() { |
Matthew Denton | 7f7c1f5 | 2023-01-11 23:35:12 | [diff] [blame] | 185 | return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote) |
| 186 | ? nullptr |
| 187 | : delegate_->GetZygote(); |
| 188 | } |
| 189 | |
jcivelli | dad0cef | 2017-02-16 18:38:59 | [diff] [blame] | 190 | base::File OpenFileToShare(const base::FilePath& path, |
| 191 | base::MemoryMappedFile::Region* region) { |
| 192 | base::FilePath exe_dir; |
| 193 | bool result = base::PathService::Get(base::BasePathKey::DIR_EXE, &exe_dir); |
| 194 | DCHECK(result); |
| 195 | base::File file(exe_dir.Append(path), |
| 196 | base::File::FLAG_OPEN | base::File::FLAG_READ); |
| 197 | *region = base::MemoryMappedFile::Region::kWholeFile; |
| 198 | return file; |
| 199 | } |
| 200 | |
jcivelli | 828cd7f | 2017-01-18 19:50:46 | [diff] [blame] | 201 | } // namespace internal |
| 202 | } // namespace content |