feat_configure_launch_options_for_service_process.patch 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: deepak1556 <[email protected]>
  3. Date: Wed, 17 Aug 2022 22:04:47 +0900
  4. Subject: feat: configure launch options for service process
  5. - POSIX:
  6. Allows configuring base::LaunchOptions::fds_to_remap when launching the child process.
  7. - Win:
  8. Allows configuring base::LaunchOptions::handles_to_inherit, base::LaunchOptions::stdout_handle
  9. and base::LaunchOptions::stderr_handle when launching the child process.
  10. - All:
  11. Allows configuring base::LauncOptions::current_directory, base::LaunchOptions::enviroment
  12. and base::LaunchOptions::clear_environment.
  13. An example use of this option, UtilityProcess API allows reading the output From
  14. stdout and stderr of child process by creating a pipe, whose write end is remapped
  15. to STDOUT_FILENO/STD_OUTPUT_HANDLE and STDERR_FILENO/STD_ERROR_HANDLE allowing the
  16. parent process to read from the pipe.
  17. diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
  18. index a4c96c333e840527a18a7ed935cb36726f56f190..1166a67c6912b5e0b497eddc914e2e270e137104 100644
  19. --- a/content/browser/child_process_launcher.h
  20. +++ b/content/browser/child_process_launcher.h
  21. @@ -32,6 +32,7 @@
  22. #if BUILDFLAG(IS_WIN)
  23. #include "base/win/windows_types.h"
  24. +#include "base/win/scoped_handle.h"
  25. #endif
  26. #if BUILDFLAG(IS_POSIX)
  27. @@ -174,7 +175,10 @@ struct ChildProcessLauncherFileData {
  28. delete;
  29. ~ChildProcessLauncherFileData();
  30. -#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
  31. +#if BUILDFLAG(IS_WIN)
  32. + base::win::ScopedHandle stdout_handle;
  33. + base::win::ScopedHandle stderr_handle;
  34. +#elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
  35. // Files opened by the browser and passed as corresponding file descriptors
  36. // in the child process. If a FilePath is provided, the file will be opened
  37. // and the descriptor cached for future process launches. If a ScopedFD is
  38. @@ -189,6 +193,15 @@ struct ChildProcessLauncherFileData {
  39. std::map<std::string, absl::variant<base::FilePath, base::ScopedFD>>
  40. files_to_preload;
  41. #endif
  42. +
  43. +#if BUILDFLAG(IS_POSIX)
  44. + // Map of file descriptors to pass. This is used instead of
  45. + // `files_to_preload` when the data needs to be installed at an exact FD
  46. + // number in the new process.
  47. + //
  48. + // Currently only supported on POSIX platforms.
  49. + std::map<int, base::ScopedFD> additional_remapped_fds;
  50. +#endif
  51. };
  52. // Launches a process asynchronously and notifies the client of the process
  53. diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc
  54. index 31a2a14a95540477297943df9b09b1e4659a884d..c02a81b1bd14a300dbbb47ad7aac2d2d7f3bb10f 100644
  55. --- a/content/browser/child_process_launcher_helper_linux.cc
  56. +++ b/content/browser/child_process_launcher_helper_linux.cc
  57. @@ -64,6 +64,11 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
  58. options->fds_to_remap.emplace_back(sandbox_fd, GetSandboxFD());
  59. }
  60. + for (const auto& remapped_fd : file_data_->additional_remapped_fds) {
  61. + options->fds_to_remap.emplace_back(remapped_fd.second.get(),
  62. + remapped_fd.first);
  63. + }
  64. +
  65. // (For Electron), if we're launching without zygote, that means we're
  66. // launching an unsandboxed process (since all sandboxed processes are
  67. // forked from the zygote). Relax the allow_new_privs option to permit
  68. @@ -73,7 +78,9 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
  69. options->allow_new_privs = true;
  70. }
  71. + options->current_directory = delegate_->GetCurrentDirectory();
  72. options->environment = delegate_->GetEnvironment();
  73. + options->clear_environment = !delegate_->ShouldInheritEnvironment();
  74. } else {
  75. DCHECK(GetZygoteForLaunch());
  76. // Environment variables could be supported in the future, but are not
  77. diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc
  78. index 24f86e68b2df0a084ae2151d5cd14a356d067f94..c424edfb7c65b9c5ae542a405446f0c15fce8995 100644
  79. --- a/content/browser/child_process_launcher_helper_mac.cc
  80. +++ b/content/browser/child_process_launcher_helper_mac.cc
  81. @@ -123,7 +123,8 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
  82. 'mojo', base::MachRendezvousPort(endpoint.TakeMachReceiveRight())));
  83. options->environment = delegate_->GetEnvironment();
  84. -
  85. + options->clear_environment = !delegate_->ShouldInheritEnvironment();
  86. + options->current_directory = delegate_->GetCurrentDirectory();
  87. options->disclaim_responsibility = delegate_->DisclaimResponsibility();
  88. options->enable_cpu_security_mitigations =
  89. delegate_->EnableCpuSecurityMitigations();
  90. @@ -193,6 +194,11 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
  91. base::StringPrintf("%s%d", sandbox::switches::kSeatbeltClient, pipe));
  92. }
  93. + for (const auto& remapped_fd : file_data_->additional_remapped_fds) {
  94. + options->fds_to_remap.emplace_back(remapped_fd.second.get(),
  95. + remapped_fd.first);
  96. + }
  97. +
  98. return true;
  99. }
  100. diff --git a/content/browser/child_process_launcher_helper_win.cc b/content/browser/child_process_launcher_helper_win.cc
  101. index 2a01487c8ff837357f6d62dba80115b0ec64c343..8b1ed51630dc4fe77bd0edadb85f04fb8962cdd8 100644
  102. --- a/content/browser/child_process_launcher_helper_win.cc
  103. +++ b/content/browser/child_process_launcher_helper_win.cc
  104. @@ -24,6 +24,8 @@
  105. #include "mojo/public/cpp/platform/named_platform_channel.h"
  106. #include "mojo/public/cpp/platform/platform_channel.h"
  107. +#include <windows.h>
  108. +
  109. namespace {
  110. // Helper to avoid marking the log file as non-executable every time we launch a
  111. @@ -132,6 +134,30 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
  112. mojo_channel_->PrepareToPassRemoteEndpoint(&options->handles_to_inherit,
  113. command_line());
  114. }
  115. +
  116. + if (file_data_->stdout_handle.IsValid() || file_data_->stderr_handle.IsValid()) {
  117. + // base::LaunchProcess requires that if any of the stdio handle is customized then
  118. + // the other two handles should also be set.
  119. + // https://source.chromium.org/chromium/chromium/src/+/main:base/process/launch_win.cc;l=341-350
  120. + options->stdin_handle = INVALID_HANDLE_VALUE;
  121. + if (file_data_->stdout_handle.IsValid()) {
  122. + options->stdout_handle = file_data_->stdout_handle.get();
  123. + } else {
  124. + options->stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
  125. + }
  126. +
  127. + if (file_data_->stderr_handle.IsValid()) {
  128. + options->stderr_handle = file_data_->stderr_handle.get();
  129. + } else {
  130. + options->stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
  131. + }
  132. + options->handles_to_inherit.push_back(options->stdout_handle);
  133. + options->handles_to_inherit.push_back(options->stderr_handle);
  134. + }
  135. +
  136. + options->current_directory = delegate_->GetCurrentDirectory();
  137. + options->environment = delegate_->GetEnvironment();
  138. + options->clear_environment = !delegate_->ShouldInheritEnvironment();
  139. return true;
  140. }
  141. @@ -159,7 +185,7 @@ ChildProcessLauncherHelper::LaunchProcessOnLauncherThread(
  142. ChildProcessLauncherHelper::Process process;
  143. *launch_result =
  144. StartSandboxedProcess(delegate_.get(), *command_line(),
  145. - options->handles_to_inherit, &process.process);
  146. + options, &process.process);
  147. return process;
  148. }
  149. diff --git a/content/browser/service_process_host_impl.cc b/content/browser/service_process_host_impl.cc
  150. index bdd5bec301f5fcff2d3e3d7994ecbc4eae46da36..45cf31157c535a0cdc9236a07e2ffffd166ba412 100644
  151. --- a/content/browser/service_process_host_impl.cc
  152. +++ b/content/browser/service_process_host_impl.cc
  153. @@ -205,6 +205,16 @@ void LaunchServiceProcess(mojo::GenericPendingReceiver receiver,
  154. options.allow_gpu_client.value()) {
  155. host->SetAllowGpuClient();
  156. }
  157. +
  158. +#if BUILDFLAG(IS_WIN)
  159. + host->SetStdioHandles(std::move(options.stdout_handle), std::move(options.stderr_handle));
  160. +#elif BUILDFLAG(IS_POSIX)
  161. + host->SetAdditionalFds(std::move(options.fds_to_remap));
  162. +#endif
  163. + host->SetCurrentDirectory(options.current_directory);
  164. + host->SetEnv(options.environment);
  165. + if (options.clear_environment)
  166. + host->ClearEnvironment();
  167. host->Start();
  168. host->GetChildProcess()->BindServiceInterface(std::move(receiver));
  169. }
  170. diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
  171. index 82f42c80eaa698aaa5da1d52c8e6486be1fb9bb6..1a8dd3c6950c1654c054d036acfdc83bd8b61c0b 100644
  172. --- a/content/browser/utility_process_host.cc
  173. +++ b/content/browser/utility_process_host.cc
  174. @@ -178,11 +178,13 @@ const ChildProcessData& UtilityProcessHost::GetData() {
  175. return process_->GetData();
  176. }
  177. -#if BUILDFLAG(IS_POSIX)
  178. void UtilityProcessHost::SetEnv(const base::EnvironmentMap& env) {
  179. env_ = env;
  180. }
  181. -#endif
  182. +
  183. +void UtilityProcessHost::ClearEnvironment() {
  184. + inherit_environment_ = false;
  185. +}
  186. bool UtilityProcessHost::Start() {
  187. return StartProcess();
  188. @@ -229,6 +231,24 @@ void UtilityProcessHost::SetZygoteForTesting(ZygoteCommunication* handle) {
  189. }
  190. #endif // BUILDFLAG(USE_ZYGOTE)
  191. +#if BUILDFLAG(IS_WIN)
  192. +void UtilityProcessHost::SetStdioHandles(
  193. + base::win::ScopedHandle stdout_handle,
  194. + base::win::ScopedHandle stderr_handle) {
  195. + stdout_handle_ = std::move(stdout_handle);
  196. + stderr_handle_ = std::move(stderr_handle);
  197. +}
  198. +#elif BUILDFLAG(IS_POSIX)
  199. +void UtilityProcessHost::SetAdditionalFds(base::FileHandleMappingVector mapping) {
  200. + fds_to_remap_ = std::move(mapping);
  201. +}
  202. +#endif
  203. +
  204. +void UtilityProcessHost::SetCurrentDirectory(
  205. + const base::FilePath& cwd) {
  206. + current_directory_ = cwd;
  207. +}
  208. +
  209. mojom::ChildProcess* UtilityProcessHost::GetChildProcess() {
  210. return static_cast<ChildProcessHostImpl*>(process_->GetHost())
  211. ->child_process();
  212. @@ -436,9 +456,22 @@ bool UtilityProcessHost::StartProcess() {
  213. }
  214. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
  215. +#if BUILDFLAG(IS_WIN)
  216. + file_data_->stdout_handle = std::move(stdout_handle_);
  217. + file_data_->stderr_handle = std::move(stderr_handle_);
  218. +#elif BUILDFLAG(IS_POSIX)
  219. + if (!fds_to_remap_.empty()) {
  220. + for (const auto& remapped_fd : fds_to_remap_) {
  221. + file_data_->additional_remapped_fds.emplace(
  222. + remapped_fd.second, remapped_fd.first);
  223. + }
  224. + }
  225. +#endif
  226. +
  227. std::unique_ptr<UtilitySandboxedProcessLauncherDelegate> delegate =
  228. std::make_unique<UtilitySandboxedProcessLauncherDelegate>(
  229. - sandbox_type_, env_, *cmd_line);
  230. + sandbox_type_, env_, current_directory_, *cmd_line,
  231. + inherit_environment_);
  232. #if BUILDFLAG(IS_WIN)
  233. if (!preload_libraries_.empty()) {
  234. diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
  235. index 9791ae2f761043b9eecd9064a6fd39a6e2339af4..1083f1683a05825f51f5b2d71f8107d910fa2474 100644
  236. --- a/content/browser/utility_process_host.h
  237. +++ b/content/browser/utility_process_host.h
  238. @@ -29,6 +29,10 @@
  239. #include "content/public/common/zygote/zygote_handle.h"
  240. #endif // BUILDFLAG(USE_ZYGOTE)
  241. +#if BUILDFLAG(IS_WIN)
  242. +#include "base/win/scoped_handle.h"
  243. +#endif
  244. +
  245. namespace base {
  246. class Thread;
  247. } // namespace base
  248. @@ -98,9 +102,13 @@ class CONTENT_EXPORT UtilityProcessHost
  249. // Returns information about the utility child process.
  250. const ChildProcessData& GetData();
  251. -#if BUILDFLAG(IS_POSIX)
  252. +
  253. + // Set/Unset environment variables.
  254. void SetEnv(const base::EnvironmentMap& env);
  255. -#endif
  256. +
  257. + // Clear the environment for the new process before processing
  258. + // changes from SetEnv.
  259. + void ClearEnvironment();
  260. // Starts the utility process.
  261. bool Start();
  262. @@ -138,6 +146,16 @@ class CONTENT_EXPORT UtilityProcessHost
  263. void SetZygoteForTesting(ZygoteCommunication* handle);
  264. #endif // BUILDFLAG(USE_ZYGOTE)
  265. +#if BUILDFLAG(IS_WIN)
  266. + void SetStdioHandles(base::win::ScopedHandle stdout_handle,
  267. + base::win::ScopedHandle stderr_handle);
  268. +#elif BUILDFLAG(IS_POSIX)
  269. + void SetAdditionalFds(base::FileHandleMappingVector mapping);
  270. +#endif
  271. +
  272. + // Sets the working directory of the process.
  273. + void SetCurrentDirectory(const base::FilePath& cwd);
  274. +
  275. // Returns a control interface for the running child process.
  276. mojom::ChildProcess* GetChildProcess();
  277. @@ -191,6 +209,22 @@ class CONTENT_EXPORT UtilityProcessHost
  278. std::optional<raw_ptr<ZygoteCommunication>> zygote_for_testing_;
  279. #endif // BUILDFLAG(USE_ZYGOTE)
  280. +#if BUILDFLAG(IS_WIN)
  281. + // Specifies the handles for redirection of stdout and stderr.
  282. + base::win::ScopedHandle stdout_handle_;
  283. + base::win::ScopedHandle stderr_handle_;
  284. +#elif BUILDFLAG(IS_POSIX)
  285. + // Specifies file descriptors to propagate into the child process
  286. + // based on the mapping.
  287. + base::FileHandleMappingVector fds_to_remap_;
  288. +#endif
  289. +
  290. + // If not empty, change to this directory before executing the new process.
  291. + base::FilePath current_directory_;
  292. +
  293. + // Inherit enviroment from parent process.
  294. + bool inherit_environment_ = true;
  295. +
  296. // Indicates whether the process has been successfully launched yet, or if
  297. // launch failed.
  298. enum class LaunchState {
  299. diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc
  300. index ad5ad7b27da8bc1b435bbb91e9e0eaa98aef9612..4f469e32f0e3ae88d11e6a6a1bb577c1302c624d 100644
  301. --- a/content/browser/utility_sandbox_delegate.cc
  302. +++ b/content/browser/utility_sandbox_delegate.cc
  303. @@ -34,17 +34,19 @@ UtilitySandboxedProcessLauncherDelegate::
  304. UtilitySandboxedProcessLauncherDelegate(
  305. sandbox::mojom::Sandbox sandbox_type,
  306. const base::EnvironmentMap& env,
  307. - const base::CommandLine& cmd_line)
  308. + const base::FilePath& cwd,
  309. + const base::CommandLine& cmd_line,
  310. + bool inherit_environment)
  311. :
  312. -#if BUILDFLAG(IS_POSIX)
  313. env_(env),
  314. -#endif
  315. + current_directory_(cwd),
  316. sandbox_type_(sandbox_type),
  317. #if BUILDFLAG(IS_WIN)
  318. app_container_disabled_(
  319. GetContentClient()->browser()->IsAppContainerDisabled(sandbox_type)),
  320. #endif
  321. - cmd_line_(cmd_line) {
  322. + cmd_line_(cmd_line),
  323. + inherit_environment_(inherit_environment) {
  324. #if DCHECK_IS_ON()
  325. bool supported_sandbox_type =
  326. sandbox_type_ == sandbox::mojom::Sandbox::kNoSandbox ||
  327. @@ -107,11 +109,17 @@ UtilitySandboxedProcessLauncherDelegate::GetSandboxType() {
  328. return sandbox_type_;
  329. }
  330. -#if BUILDFLAG(IS_POSIX)
  331. base::EnvironmentMap UtilitySandboxedProcessLauncherDelegate::GetEnvironment() {
  332. return env_;
  333. }
  334. -#endif // BUILDFLAG(IS_POSIX)
  335. +
  336. +bool UtilitySandboxedProcessLauncherDelegate::ShouldInheritEnvironment() {
  337. + return inherit_environment_;
  338. +}
  339. +
  340. +base::FilePath UtilitySandboxedProcessLauncherDelegate::GetCurrentDirectory() {
  341. + return current_directory_;
  342. +}
  343. #if BUILDFLAG(USE_ZYGOTE)
  344. ZygoteCommunication* UtilitySandboxedProcessLauncherDelegate::GetZygote() {
  345. diff --git a/content/browser/utility_sandbox_delegate.h b/content/browser/utility_sandbox_delegate.h
  346. index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..57c0d369e7373f755391da3fafbdaea86358d962 100644
  347. --- a/content/browser/utility_sandbox_delegate.h
  348. +++ b/content/browser/utility_sandbox_delegate.h
  349. @@ -30,7 +30,9 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
  350. public:
  351. UtilitySandboxedProcessLauncherDelegate(sandbox::mojom::Sandbox sandbox_type,
  352. const base::EnvironmentMap& env,
  353. - const base::CommandLine& cmd_line);
  354. + const base::FilePath& cwd,
  355. + const base::CommandLine& cmd_line,
  356. + bool inherit_environment);
  357. ~UtilitySandboxedProcessLauncherDelegate() override;
  358. sandbox::mojom::Sandbox GetSandboxType() override;
  359. @@ -56,18 +58,16 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
  360. ZygoteCommunication* GetZygote() override;
  361. #endif // BUILDFLAG(USE_ZYGOTE)
  362. -#if BUILDFLAG(IS_POSIX)
  363. base::EnvironmentMap GetEnvironment() override;
  364. -#endif // BUILDFLAG(IS_POSIX)
  365. + bool ShouldInheritEnvironment() override;
  366. + base::FilePath GetCurrentDirectory() override;
  367. #if BUILDFLAG(USE_ZYGOTE)
  368. void SetZygote(ZygoteCommunication* handle);
  369. #endif // BUILDFLAG(USE_ZYGOTE_HANDLE)
  370. private:
  371. -#if BUILDFLAG(IS_POSIX)
  372. base::EnvironmentMap env_;
  373. -#endif // BUILDFLAG(IS_POSIX)
  374. #if BUILDFLAG(IS_WIN)
  375. std::vector<base::FilePath> preload_libraries_;
  376. @@ -77,12 +77,14 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
  377. std::optional<raw_ptr<ZygoteCommunication>> zygote_;
  378. #endif // BUILDFLAG(USE_ZYGOTE)
  379. + base::FilePath current_directory_;
  380. const sandbox::mojom::Sandbox sandbox_type_;
  381. #if BUILDFLAG(IS_WIN)
  382. // If true then App Container will not be used for this utility process.
  383. const bool app_container_disabled_;
  384. #endif // BUILDFLAG(IS_WIN)
  385. base::CommandLine cmd_line_;
  386. + bool inherit_environment_;
  387. };
  388. } // namespace content
  389. diff --git a/content/common/sandbox_init_win.cc b/content/common/sandbox_init_win.cc
  390. index b96d6a879e8b6664559bac69f726321fdb02b40f..bfeec6ddb98d4127c1dcfe5999894f1cdebdc087 100644
  391. --- a/content/common/sandbox_init_win.cc
  392. +++ b/content/common/sandbox_init_win.cc
  393. @@ -23,7 +23,7 @@ namespace content {
  394. sandbox::ResultCode StartSandboxedProcess(
  395. SandboxedProcessLauncherDelegate* delegate,
  396. const base::CommandLine& target_command_line,
  397. - const base::HandlesToInheritVector& handles_to_inherit,
  398. + const base::LaunchOptions* options,
  399. base::Process* process) {
  400. std::string type_str =
  401. target_command_line.GetSwitchValueASCII(switches::kProcessType);
  402. @@ -45,7 +45,7 @@ sandbox::ResultCode StartSandboxedProcess(
  403. }
  404. return sandbox::policy::SandboxWin::StartSandboxedProcess(
  405. - full_command_line, handles_to_inherit, delegate, process);
  406. + full_command_line, options, delegate, process);
  407. }
  408. } // namespace content
  409. diff --git a/content/public/browser/service_process_host.cc b/content/public/browser/service_process_host.cc
  410. index 8defae52a201a97c402e304216ce772a717a9f7e..a3cdeab1c22cf9f1b5ea0c25d2d7cbff9b68b683 100644
  411. --- a/content/public/browser/service_process_host.cc
  412. +++ b/content/public/browser/service_process_host.cc
  413. @@ -52,12 +52,45 @@ ServiceProcessHost::Options::WithExtraCommandLineSwitches(
  414. return *this;
  415. }
  416. +#if BUILDFLAG(IS_WIN)
  417. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithStdoutHandle(
  418. + base::win::ScopedHandle handle) {
  419. + stdout_handle = std::move(handle);
  420. + return *this;
  421. +}
  422. +
  423. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithStderrHandle(
  424. + base::win::ScopedHandle handle) {
  425. + stderr_handle = std::move(handle);
  426. + return *this;
  427. +}
  428. +#elif BUILDFLAG(IS_POSIX)
  429. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithAdditionalFds(
  430. + base::FileHandleMappingVector mapping) {
  431. + fds_to_remap = std::move(mapping);
  432. + return *this;
  433. +}
  434. +#endif
  435. +
  436. ServiceProcessHost::Options& ServiceProcessHost::Options::WithProcessCallback(
  437. base::OnceCallback<void(const base::Process&)> callback) {
  438. process_callback = std::move(callback);
  439. return *this;
  440. }
  441. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithCurrentDirectory(
  442. + const base::FilePath& cwd) {
  443. + current_directory = cwd;
  444. + return *this;
  445. +}
  446. +
  447. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithEnvironment(
  448. + const base::EnvironmentMap& env, bool new_environment) {
  449. + environment = env;
  450. + clear_environment = new_environment;
  451. + return *this;
  452. +}
  453. +
  454. #if BUILDFLAG(IS_WIN)
  455. ServiceProcessHost::Options&
  456. ServiceProcessHost::Options::WithPreloadedLibraries(
  457. diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
  458. index 0062d2cb6634b8b29977a0312516b1b13936b40a..22e1191b57f56aa31b2c82fcc3ec0972f16752a8 100644
  459. --- a/content/public/browser/service_process_host.h
  460. +++ b/content/public/browser/service_process_host.h
  461. @@ -14,6 +14,7 @@
  462. #include "base/command_line.h"
  463. #include "base/functional/callback.h"
  464. #include "base/observer_list_types.h"
  465. +#include "base/process/launch.h"
  466. #include "base/process/process_handle.h"
  467. #include "content/common/content_export.h"
  468. #include "content/public/browser/service_process_info.h"
  469. @@ -28,6 +29,10 @@
  470. #include "base/types/pass_key.h"
  471. #endif // BUILDFLAG(IS_WIN)
  472. +#if BUILDFLAG(IS_WIN)
  473. +#include "base/win/scoped_handle.h"
  474. +#endif
  475. +
  476. namespace base {
  477. class Process;
  478. } // namespace base
  479. @@ -94,11 +99,30 @@ class CONTENT_EXPORT ServiceProcessHost {
  480. // Specifies extra command line switches to append before launch.
  481. Options& WithExtraCommandLineSwitches(std::vector<std::string> switches);
  482. +#if BUILDFLAG(IS_WIN)
  483. + // Specifies the handles for redirection of stdout and stderr.
  484. + Options& WithStdoutHandle(base::win::ScopedHandle stdout_handle);
  485. + Options& WithStderrHandle(base::win::ScopedHandle stderr_handle);
  486. +#elif BUILDFLAG(IS_POSIX)
  487. + // Specifies file descriptors to propagate into the child process
  488. + // based on the mapping.
  489. + Options& WithAdditionalFds(base::FileHandleMappingVector mapping);
  490. +#endif
  491. +
  492. // Specifies a callback to be invoked with service process once it's
  493. // launched. Will be on UI thread.
  494. Options& WithProcessCallback(
  495. base::OnceCallback<void(const base::Process&)>);
  496. + // Specifies the working directory for the launched process.
  497. + Options& WithCurrentDirectory(const base::FilePath& cwd);
  498. +
  499. + // Specifies the environment that should be applied to the process.
  500. + // |new_environment| controls whether the process should inherit
  501. + // environment from the parent process.
  502. + Options& WithEnvironment(const base::EnvironmentMap& environment,
  503. + bool new_environment);
  504. +
  505. #if BUILDFLAG(IS_WIN)
  506. // Specifies libraries to preload before the sandbox is locked down. Paths
  507. // should be absolute paths. Libraries will be preloaded before sandbox
  508. @@ -127,11 +151,20 @@ class CONTENT_EXPORT ServiceProcessHost {
  509. std::optional<GURL> site;
  510. std::optional<int> child_flags;
  511. std::vector<std::string> extra_switches;
  512. +#if BUILDFLAG(IS_WIN)
  513. + base::win::ScopedHandle stdout_handle;
  514. + base::win::ScopedHandle stderr_handle;
  515. +#elif BUILDFLAG(IS_POSIX)
  516. + base::FileHandleMappingVector fds_to_remap;
  517. +#endif
  518. base::OnceCallback<void(const base::Process&)> process_callback;
  519. #if BUILDFLAG(IS_WIN)
  520. std::vector<base::FilePath> preload_libraries;
  521. #endif // BUILDFLAG(IS_WIN)
  522. std::optional<bool> allow_gpu_client;
  523. + base::FilePath current_directory;
  524. + base::EnvironmentMap environment;
  525. + bool clear_environment = false;
  526. };
  527. // An interface which can be implemented and registered/unregistered with
  528. diff --git a/content/public/common/sandbox_init_win.h b/content/public/common/sandbox_init_win.h
  529. index 9bb4b30ba0f5d37ec2b28f0848d94f34c24f9423..b614fef01ee5cdf81b7112be721b851c454756a2 100644
  530. --- a/content/public/common/sandbox_init_win.h
  531. +++ b/content/public/common/sandbox_init_win.h
  532. @@ -29,7 +29,7 @@ class SandboxedProcessLauncherDelegate;
  533. CONTENT_EXPORT sandbox::ResultCode StartSandboxedProcess(
  534. SandboxedProcessLauncherDelegate* delegate,
  535. const base::CommandLine& target_command_line,
  536. - const base::HandlesToInheritVector& handles_to_inherit,
  537. + const base::LaunchOptions* options,
  538. base::Process* process);
  539. } // namespace content
  540. diff --git a/content/public/common/sandboxed_process_launcher_delegate.cc b/content/public/common/sandboxed_process_launcher_delegate.cc
  541. index 9c1aa450f32b6812d4a87cd0b9ee0dfb1a9557f4..3360302b4511ed914ac2d5756dcc7edf7e675631 100644
  542. --- a/content/public/common/sandboxed_process_launcher_delegate.cc
  543. +++ b/content/public/common/sandboxed_process_launcher_delegate.cc
  544. @@ -68,11 +68,17 @@ ZygoteCommunication* SandboxedProcessLauncherDelegate::GetZygote() {
  545. }
  546. #endif // BUILDFLAG(USE_ZYGOTE)
  547. -#if BUILDFLAG(IS_POSIX)
  548. base::EnvironmentMap SandboxedProcessLauncherDelegate::GetEnvironment() {
  549. return base::EnvironmentMap();
  550. }
  551. -#endif // BUILDFLAG(IS_POSIX)
  552. +
  553. +bool SandboxedProcessLauncherDelegate::ShouldInheritEnvironment() {
  554. + return true;
  555. +}
  556. +
  557. +base::FilePath SandboxedProcessLauncherDelegate::GetCurrentDirectory() {
  558. + return base::FilePath();
  559. +}
  560. #if BUILDFLAG(IS_MAC)
  561. diff --git a/content/public/common/sandboxed_process_launcher_delegate.h b/content/public/common/sandboxed_process_launcher_delegate.h
  562. index cb43aa14c9742f3788ae58c3e49b890cd532f327..6a738f7aade504f2ff3bb6647a0da8f8d1933de2 100644
  563. --- a/content/public/common/sandboxed_process_launcher_delegate.h
  564. +++ b/content/public/common/sandboxed_process_launcher_delegate.h
  565. @@ -6,6 +6,7 @@
  566. #define CONTENT_PUBLIC_COMMON_SANDBOXED_PROCESS_LAUNCHER_DELEGATE_H_
  567. #include "base/environment.h"
  568. +#include "base/files/file_path.h"
  569. #include "base/files/scoped_file.h"
  570. #include "base/process/process.h"
  571. #include "build/build_config.h"
  572. @@ -57,10 +58,14 @@ class CONTENT_EXPORT SandboxedProcessLauncherDelegate
  573. virtual ZygoteCommunication* GetZygote();
  574. #endif // BUILDFLAG(USE_ZYGOTE)
  575. -#if BUILDFLAG(IS_POSIX)
  576. // Override this if the process needs a non-empty environment map.
  577. virtual base::EnvironmentMap GetEnvironment();
  578. -#endif // BUILDFLAG(IS_POSIX)
  579. +
  580. + // Override this if the process should not inherit parent environment.
  581. + virtual bool ShouldInheritEnvironment();
  582. +
  583. + // Specifies the directory to change to before executing the process.
  584. + virtual base::FilePath GetCurrentDirectory();
  585. #if BUILDFLAG(IS_MAC)
  586. // Whether or not to disclaim TCC responsibility for the process, defaults to
  587. diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc
  588. index d25dc43074f15d81504dcf062a0284f73c417698..6e764cccfbb69717331d13af60c681a889ade750 100644
  589. --- a/sandbox/policy/win/sandbox_win.cc
  590. +++ b/sandbox/policy/win/sandbox_win.cc
  591. @@ -699,11 +699,9 @@ base::win::ScopedHandle CreateUnsandboxedJob() {
  592. // command line flag.
  593. ResultCode LaunchWithoutSandbox(
  594. const base::CommandLine& cmd_line,
  595. - const base::HandlesToInheritVector& handles_to_inherit,
  596. + base::LaunchOptions options,
  597. SandboxDelegate* delegate,
  598. base::Process* process) {
  599. - base::LaunchOptions options;
  600. - options.handles_to_inherit = handles_to_inherit;
  601. // Network process runs in a job even when unsandboxed. This is to ensure it
  602. // does not outlive the browser, which could happen if there is a lot of I/O
  603. // on process shutdown, in which case TerminateProcess can fail. See
  604. @@ -938,7 +936,7 @@ bool SandboxWin::InitTargetServices(TargetServices* target_services) {
  605. // static
  606. ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  607. const base::CommandLine& cmd_line,
  608. - const base::HandlesToInheritVector& handles_to_inherit,
  609. + const base::LaunchOptions* options,
  610. SandboxDelegate* delegate,
  611. TargetPolicy* policy) {
  612. const base::CommandLine& launcher_process_command_line =
  613. @@ -952,7 +950,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  614. }
  615. // Add any handles to be inherited to the policy.
  616. - for (HANDLE handle : handles_to_inherit)
  617. + for (HANDLE handle : options->handles_to_inherit)
  618. policy->AddHandleToShare(handle);
  619. if (!policy->GetConfig()->IsConfigured()) {
  620. @@ -967,6 +965,13 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  621. // have no effect. These calls can fail with SBOX_ERROR_BAD_PARAMS.
  622. policy->SetStdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE));
  623. policy->SetStderrHandle(GetStdHandle(STD_ERROR_HANDLE));
  624. +#else
  625. + if (options->stdout_handle != nullptr && options->stdout_handle != INVALID_HANDLE_VALUE) {
  626. + policy->SetStdoutHandle(options->stdout_handle);
  627. + }
  628. + if (options->stderr_handle != nullptr && options->stderr_handle != INVALID_HANDLE_VALUE) {
  629. + policy->SetStderrHandle(options->stderr_handle);
  630. + }
  631. #endif
  632. if (!delegate->PreSpawnTarget(policy))
  633. @@ -978,7 +983,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  634. // static
  635. ResultCode SandboxWin::StartSandboxedProcess(
  636. const base::CommandLine& cmd_line,
  637. - const base::HandlesToInheritVector& handles_to_inherit,
  638. + const base::LaunchOptions* options,
  639. SandboxDelegate* delegate,
  640. base::Process* process) {
  641. SandboxLaunchTimer timer;
  642. @@ -986,7 +991,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
  643. // Avoid making a policy if we won't use it.
  644. if (IsUnsandboxedProcess(delegate->GetSandboxType(), cmd_line,
  645. *base::CommandLine::ForCurrentProcess())) {
  646. - return LaunchWithoutSandbox(cmd_line, handles_to_inherit, delegate,
  647. + return LaunchWithoutSandbox(cmd_line, *options, delegate,
  648. process);
  649. }
  650. @@ -994,7 +999,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
  651. timer.OnPolicyCreated();
  652. ResultCode result = GeneratePolicyForSandboxedProcess(
  653. - cmd_line, handles_to_inherit, delegate, policy.get());
  654. + cmd_line, options, delegate, policy.get());
  655. if (SBOX_ALL_OK != result)
  656. return result;
  657. timer.OnPolicyGenerated();
  658. diff --git a/sandbox/policy/win/sandbox_win.h b/sandbox/policy/win/sandbox_win.h
  659. index 271e80f52b15484ecc8b31b12b012eac39b3d333..cd3d803f52972c4ae8af6a0411b5be0e0a5bc782 100644
  660. --- a/sandbox/policy/win/sandbox_win.h
  661. +++ b/sandbox/policy/win/sandbox_win.h
  662. @@ -52,7 +52,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
  663. // Otherwise, returns one of sandbox::ResultCode for any other error.
  664. static ResultCode StartSandboxedProcess(
  665. const base::CommandLine& cmd_line,
  666. - const base::HandlesToInheritVector& handles_to_inherit,
  667. + const base::LaunchOptions* options,
  668. SandboxDelegate* delegate,
  669. base::Process* process);
  670. @@ -65,7 +65,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
  671. // of sandbox::ResultCode for any other error while constructing the policy.
  672. static ResultCode GeneratePolicyForSandboxedProcess(
  673. const base::CommandLine& cmd_line,
  674. - const base::HandlesToInheritVector& handles_to_inherit,
  675. + const base::LaunchOptions* options,
  676. SandboxDelegate* delegate,
  677. TargetPolicy* policy);