feat_configure_launch_options_for_service_process.patch 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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 7d449854cb60c184baba2cc17ae3d47fba3d3f7a..b76d963a0232fdbc27ddc52598860b35b6853034 100644
  19. --- a/content/browser/child_process_launcher.h
  20. +++ b/content/browser/child_process_launcher.h
  21. @@ -33,6 +33,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. @@ -166,7 +167,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. @@ -181,6 +185,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 795ad47165f2f02e816f424ce74391a435c61a32..ace57135682f4372814acfbd202d1b077ecb1c0c 100644
  55. --- a/content/browser/child_process_launcher_helper_linux.cc
  56. +++ b/content/browser/child_process_launcher_helper_linux.cc
  57. @@ -63,6 +63,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. @@ -72,7 +77,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 8736af0021dccba915e3d2303191ae3ec80f6e75..56f8384c3ff4959272363cb71e4c380ee9125273 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. @@ -187,6 +188,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 1d6bc6590720cda38983203455cc20638710148f..8f965150db13d3f4fe1757a021b9a2f6446529d6 100644
  102. --- a/content/browser/child_process_launcher_helper_win.cc
  103. +++ b/content/browser/child_process_launcher_helper_win.cc
  104. @@ -21,6 +21,8 @@
  105. #include "sandbox/policy/win/sandbox_win.h"
  106. #include "sandbox/win/src/sandbox_types.h"
  107. +#include <windows.h>
  108. +
  109. namespace {
  110. // /prefetch:# arguments to use when launching various process types. It has
  111. @@ -189,6 +191,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. @@ -216,7 +242,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 7c9548bc25fa3a886806e1611791f2a74aa94d1a..d61ce98e754c2546987bf2cbe0ed6bf9332cf46a 100644
  151. --- a/content/browser/service_process_host_impl.cc
  152. +++ b/content/browser/service_process_host_impl.cc
  153. @@ -203,6 +203,15 @@ void LaunchServiceProcess(mojo::GenericPendingReceiver receiver,
  154. host->SetPinUser32();
  155. }
  156. #endif // BUILDFLAG(IS_WIN)
  157. +#if BUILDFLAG(IS_WIN)
  158. + host->SetStdioHandles(std::move(options.stdout_handle), std::move(options.stderr_handle));
  159. +#elif BUILDFLAG(IS_POSIX)
  160. + host->SetAdditionalFds(std::move(options.fds_to_remap));
  161. +#endif
  162. + host->SetCurrentDirectory(options.current_directory);
  163. + host->SetEnv(options.environment);
  164. + if (options.clear_environment)
  165. + host->ClearEnvironment();
  166. host->Start();
  167. host->GetChildProcess()->BindServiceInterface(std::move(receiver));
  168. }
  169. diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
  170. index 009e97487209e3ebe811d061d5e8a44df7eb9eb3..3ae41211ea66161a5117262907d9fc70f33e4c8a 100644
  171. --- a/content/browser/utility_process_host.cc
  172. +++ b/content/browser/utility_process_host.cc
  173. @@ -177,11 +177,13 @@ const ChildProcessData& UtilityProcessHost::GetData() {
  174. return process_->GetData();
  175. }
  176. -#if BUILDFLAG(IS_POSIX)
  177. void UtilityProcessHost::SetEnv(const base::EnvironmentMap& env) {
  178. env_ = env;
  179. }
  180. -#endif
  181. +
  182. +void UtilityProcessHost::ClearEnvironment() {
  183. + inherit_environment_ = false;
  184. +}
  185. bool UtilityProcessHost::Start() {
  186. return StartProcess();
  187. @@ -247,6 +249,24 @@ void UtilityProcessHost::SetZygoteForTesting(ZygoteCommunication* handle) {
  188. }
  189. #endif // BUILDFLAG(USE_ZYGOTE)
  190. +#if BUILDFLAG(IS_WIN)
  191. +void UtilityProcessHost::SetStdioHandles(
  192. + base::win::ScopedHandle stdout_handle,
  193. + base::win::ScopedHandle stderr_handle) {
  194. + stdout_handle_ = std::move(stdout_handle);
  195. + stderr_handle_ = std::move(stderr_handle);
  196. +}
  197. +#elif BUILDFLAG(IS_POSIX)
  198. +void UtilityProcessHost::SetAdditionalFds(base::FileHandleMappingVector mapping) {
  199. + fds_to_remap_ = std::move(mapping);
  200. +}
  201. +#endif
  202. +
  203. +void UtilityProcessHost::SetCurrentDirectory(
  204. + const base::FilePath& cwd) {
  205. + current_directory_ = cwd;
  206. +}
  207. +
  208. mojom::ChildProcess* UtilityProcessHost::GetChildProcess() {
  209. return static_cast<ChildProcessHostImpl*>(process_->GetHost())
  210. ->child_process();
  211. @@ -460,9 +480,22 @@ bool UtilityProcessHost::StartProcess() {
  212. }
  213. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
  214. +#if BUILDFLAG(IS_WIN)
  215. + file_data_->stdout_handle = std::move(stdout_handle_);
  216. + file_data_->stderr_handle = std::move(stderr_handle_);
  217. +#elif BUILDFLAG(IS_POSIX)
  218. + if (!fds_to_remap_.empty()) {
  219. + for (const auto& remapped_fd : fds_to_remap_) {
  220. + file_data_->additional_remapped_fds.emplace(
  221. + remapped_fd.second, remapped_fd.first);
  222. + }
  223. + }
  224. +#endif
  225. +
  226. std::unique_ptr<UtilitySandboxedProcessLauncherDelegate> delegate =
  227. std::make_unique<UtilitySandboxedProcessLauncherDelegate>(
  228. - sandbox_type_, env_, *cmd_line);
  229. + sandbox_type_, env_, current_directory_, *cmd_line,
  230. + inherit_environment_);
  231. #if BUILDFLAG(IS_WIN)
  232. if (!preload_libraries_.empty()) {
  233. diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
  234. index 01a921c772f769c64ac97bfc5e74862a801e3e61..9bfc30138a01520d59760a49d15dd4819feb0556 100644
  235. --- a/content/browser/utility_process_host.h
  236. +++ b/content/browser/utility_process_host.h
  237. @@ -35,6 +35,10 @@
  238. #include "mojo/public/cpp/system/message_pipe.h"
  239. #endif
  240. +#if BUILDFLAG(IS_WIN)
  241. +#include "base/win/scoped_handle.h"
  242. +#endif
  243. +
  244. namespace base {
  245. class Thread;
  246. } // namespace base
  247. @@ -104,9 +108,13 @@ class CONTENT_EXPORT UtilityProcessHost
  248. // Returns information about the utility child process.
  249. const ChildProcessData& GetData();
  250. -#if BUILDFLAG(IS_POSIX)
  251. +
  252. + // Set/Unset environment variables.
  253. void SetEnv(const base::EnvironmentMap& env);
  254. -#endif
  255. +
  256. + // Clear the environment for the new process before processing
  257. + // changes from SetEnv.
  258. + void ClearEnvironment();
  259. // Starts the utility process.
  260. bool Start();
  261. @@ -154,6 +162,16 @@ class CONTENT_EXPORT UtilityProcessHost
  262. void SetZygoteForTesting(ZygoteCommunication* handle);
  263. #endif // BUILDFLAG(USE_ZYGOTE)
  264. +#if BUILDFLAG(IS_WIN)
  265. + void SetStdioHandles(base::win::ScopedHandle stdout_handle,
  266. + base::win::ScopedHandle stderr_handle);
  267. +#elif BUILDFLAG(IS_POSIX)
  268. + void SetAdditionalFds(base::FileHandleMappingVector mapping);
  269. +#endif
  270. +
  271. + // Sets the working directory of the process.
  272. + void SetCurrentDirectory(const base::FilePath& cwd);
  273. +
  274. // Returns a control interface for the running child process.
  275. mojom::ChildProcess* GetChildProcess();
  276. @@ -209,6 +227,22 @@ class CONTENT_EXPORT UtilityProcessHost
  277. std::optional<raw_ptr<ZygoteCommunication>> zygote_for_testing_;
  278. #endif // BUILDFLAG(USE_ZYGOTE)
  279. +#if BUILDFLAG(IS_WIN)
  280. + // Specifies the handles for redirection of stdout and stderr.
  281. + base::win::ScopedHandle stdout_handle_;
  282. + base::win::ScopedHandle stderr_handle_;
  283. +#elif BUILDFLAG(IS_POSIX)
  284. + // Specifies file descriptors to propagate into the child process
  285. + // based on the mapping.
  286. + base::FileHandleMappingVector fds_to_remap_;
  287. +#endif
  288. +
  289. + // If not empty, change to this directory before executing the new process.
  290. + base::FilePath current_directory_;
  291. +
  292. + // Inherit enviroment from parent process.
  293. + bool inherit_environment_ = true;
  294. +
  295. // Indicates whether the process has been successfully launched yet, or if
  296. // launch failed.
  297. enum class LaunchState {
  298. diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc
  299. index 2f3977d62535e299ef3b5954b9d67291afae2a57..edc825c691f7b55cd38fa31a9229fdf02bb5ff24 100644
  300. --- a/content/browser/utility_sandbox_delegate.cc
  301. +++ b/content/browser/utility_sandbox_delegate.cc
  302. @@ -29,13 +29,15 @@ UtilitySandboxedProcessLauncherDelegate::
  303. UtilitySandboxedProcessLauncherDelegate(
  304. sandbox::mojom::Sandbox sandbox_type,
  305. const base::EnvironmentMap& env,
  306. - const base::CommandLine& cmd_line)
  307. + const base::FilePath& cwd,
  308. + const base::CommandLine& cmd_line,
  309. + bool inherit_environment)
  310. :
  311. -#if BUILDFLAG(IS_POSIX)
  312. env_(env),
  313. -#endif
  314. + current_directory_(cwd),
  315. sandbox_type_(sandbox_type),
  316. - cmd_line_(cmd_line) {
  317. + cmd_line_(cmd_line),
  318. + inherit_environment_(inherit_environment) {
  319. #if DCHECK_IS_ON()
  320. bool supported_sandbox_type =
  321. sandbox_type_ == sandbox::mojom::Sandbox::kNoSandbox ||
  322. @@ -97,11 +99,17 @@ UtilitySandboxedProcessLauncherDelegate::GetSandboxType() {
  323. return sandbox_type_;
  324. }
  325. -#if BUILDFLAG(IS_POSIX)
  326. base::EnvironmentMap UtilitySandboxedProcessLauncherDelegate::GetEnvironment() {
  327. return env_;
  328. }
  329. -#endif // BUILDFLAG(IS_POSIX)
  330. +
  331. +bool UtilitySandboxedProcessLauncherDelegate::ShouldInheritEnvironment() {
  332. + return inherit_environment_;
  333. +}
  334. +
  335. +base::FilePath UtilitySandboxedProcessLauncherDelegate::GetCurrentDirectory() {
  336. + return current_directory_;
  337. +}
  338. #if BUILDFLAG(USE_ZYGOTE)
  339. ZygoteCommunication* UtilitySandboxedProcessLauncherDelegate::GetZygote() {
  340. diff --git a/content/browser/utility_sandbox_delegate.h b/content/browser/utility_sandbox_delegate.h
  341. index 0e07a9799748f30c5768651f44b5e5aa52c514f3..b1915bcad540f0c90b71677e59083a11461519f2 100644
  342. --- a/content/browser/utility_sandbox_delegate.h
  343. +++ b/content/browser/utility_sandbox_delegate.h
  344. @@ -28,7 +28,9 @@ class UtilitySandboxedProcessLauncherDelegate
  345. public:
  346. UtilitySandboxedProcessLauncherDelegate(sandbox::mojom::Sandbox sandbox_type,
  347. const base::EnvironmentMap& env,
  348. - const base::CommandLine& cmd_line);
  349. + const base::FilePath& cwd,
  350. + const base::CommandLine& cmd_line,
  351. + bool inherit_environment);
  352. ~UtilitySandboxedProcessLauncherDelegate() override;
  353. sandbox::mojom::Sandbox GetSandboxType() override;
  354. @@ -55,18 +57,16 @@ class UtilitySandboxedProcessLauncherDelegate
  355. ZygoteCommunication* GetZygote() override;
  356. #endif // BUILDFLAG(USE_ZYGOTE)
  357. -#if BUILDFLAG(IS_POSIX)
  358. base::EnvironmentMap GetEnvironment() override;
  359. -#endif // BUILDFLAG(IS_POSIX)
  360. + bool ShouldInheritEnvironment() override;
  361. + base::FilePath GetCurrentDirectory() override;
  362. #if BUILDFLAG(USE_ZYGOTE)
  363. void SetZygote(ZygoteCommunication* handle);
  364. #endif // BUILDFLAG(USE_ZYGOTE_HANDLE)
  365. private:
  366. -#if BUILDFLAG(IS_POSIX)
  367. base::EnvironmentMap env_;
  368. -#endif // BUILDFLAG(IS_POSIX)
  369. #if BUILDFLAG(IS_WIN)
  370. std::vector<base::FilePath> preload_libraries_;
  371. @@ -77,8 +77,10 @@ class UtilitySandboxedProcessLauncherDelegate
  372. std::optional<raw_ptr<ZygoteCommunication>> zygote_;
  373. #endif // BUILDFLAG(USE_ZYGOTE)
  374. + base::FilePath current_directory_;
  375. sandbox::mojom::Sandbox sandbox_type_;
  376. base::CommandLine cmd_line_;
  377. + bool inherit_environment_;
  378. };
  379. } // namespace content
  380. diff --git a/content/common/sandbox_init_win.cc b/content/common/sandbox_init_win.cc
  381. index 498f60227d13eb2e476413f88eaa58cc0babf461..619639ad5d22a1121b0e0d5f2c9e3c10394cdbd7 100644
  382. --- a/content/common/sandbox_init_win.cc
  383. +++ b/content/common/sandbox_init_win.cc
  384. @@ -23,7 +23,7 @@ namespace content {
  385. sandbox::ResultCode StartSandboxedProcess(
  386. SandboxedProcessLauncherDelegate* delegate,
  387. const base::CommandLine& target_command_line,
  388. - const base::HandlesToInheritVector& handles_to_inherit,
  389. + const base::LaunchOptions* options,
  390. base::Process* process) {
  391. std::string type_str =
  392. target_command_line.GetSwitchValueASCII(switches::kProcessType);
  393. @@ -45,7 +45,7 @@ sandbox::ResultCode StartSandboxedProcess(
  394. }
  395. return sandbox::policy::SandboxWin::StartSandboxedProcess(
  396. - full_command_line, type_str, handles_to_inherit, delegate, process);
  397. + full_command_line, type_str, options, delegate, process);
  398. }
  399. } // namespace content
  400. diff --git a/content/public/browser/service_process_host.cc b/content/public/browser/service_process_host.cc
  401. index e6bd27288a8d29dcf263a0677d2629d0aa7cf7c4..24d5acf41ea3fb825d813a040644aef1c9d6d4ee 100644
  402. --- a/content/public/browser/service_process_host.cc
  403. +++ b/content/public/browser/service_process_host.cc
  404. @@ -52,12 +52,45 @@ ServiceProcessHost::Options::WithExtraCommandLineSwitches(
  405. return *this;
  406. }
  407. +#if BUILDFLAG(IS_WIN)
  408. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithStdoutHandle(
  409. + base::win::ScopedHandle handle) {
  410. + stdout_handle = std::move(handle);
  411. + return *this;
  412. +}
  413. +
  414. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithStderrHandle(
  415. + base::win::ScopedHandle handle) {
  416. + stderr_handle = std::move(handle);
  417. + return *this;
  418. +}
  419. +#elif BUILDFLAG(IS_POSIX)
  420. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithAdditionalFds(
  421. + base::FileHandleMappingVector mapping) {
  422. + fds_to_remap = std::move(mapping);
  423. + return *this;
  424. +}
  425. +#endif
  426. +
  427. ServiceProcessHost::Options& ServiceProcessHost::Options::WithProcessCallback(
  428. base::OnceCallback<void(const base::Process&)> callback) {
  429. process_callback = std::move(callback);
  430. return *this;
  431. }
  432. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithCurrentDirectory(
  433. + const base::FilePath& cwd) {
  434. + current_directory = cwd;
  435. + return *this;
  436. +}
  437. +
  438. +ServiceProcessHost::Options& ServiceProcessHost::Options::WithEnvironment(
  439. + const base::EnvironmentMap& env, bool new_environment) {
  440. + environment = env;
  441. + clear_environment = new_environment;
  442. + return *this;
  443. +}
  444. +
  445. #if BUILDFLAG(IS_WIN)
  446. ServiceProcessHost::Options&
  447. ServiceProcessHost::Options::WithPreloadedLibraries(
  448. diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
  449. index b737083c3a3a80ae408c69d4831fb7a0304d93ff..425845c33523135988c646bd75465b9a33d658ba 100644
  450. --- a/content/public/browser/service_process_host.h
  451. +++ b/content/public/browser/service_process_host.h
  452. @@ -14,6 +14,7 @@
  453. #include "base/command_line.h"
  454. #include "base/functional/callback.h"
  455. #include "base/observer_list_types.h"
  456. +#include "base/process/launch.h"
  457. #include "base/process/process_handle.h"
  458. #include "base/strings/string_piece.h"
  459. #include "content/common/content_export.h"
  460. @@ -29,6 +30,10 @@
  461. #include "base/types/pass_key.h"
  462. #endif // BUILDFLAG(IS_WIN)
  463. +#if BUILDFLAG(IS_WIN)
  464. +#include "base/win/scoped_handle.h"
  465. +#endif
  466. +
  467. namespace base {
  468. class Process;
  469. } // namespace base
  470. @@ -94,11 +99,30 @@ class CONTENT_EXPORT ServiceProcessHost {
  471. // Specifies extra command line switches to append before launch.
  472. Options& WithExtraCommandLineSwitches(std::vector<std::string> switches);
  473. +#if BUILDFLAG(IS_WIN)
  474. + // Specifies the handles for redirection of stdout and stderr.
  475. + Options& WithStdoutHandle(base::win::ScopedHandle stdout_handle);
  476. + Options& WithStderrHandle(base::win::ScopedHandle stderr_handle);
  477. +#elif BUILDFLAG(IS_POSIX)
  478. + // Specifies file descriptors to propagate into the child process
  479. + // based on the mapping.
  480. + Options& WithAdditionalFds(base::FileHandleMappingVector mapping);
  481. +#endif
  482. +
  483. // Specifies a callback to be invoked with service process once it's
  484. // launched. Will be on UI thread.
  485. Options& WithProcessCallback(
  486. base::OnceCallback<void(const base::Process&)>);
  487. + // Specifies the working directory for the launched process.
  488. + Options& WithCurrentDirectory(const base::FilePath& cwd);
  489. +
  490. + // Specifies the environment that should be applied to the process.
  491. + // |new_environment| controls whether the process should inherit
  492. + // environment from the parent process.
  493. + Options& WithEnvironment(const base::EnvironmentMap& environment,
  494. + bool new_environment);
  495. +
  496. #if BUILDFLAG(IS_WIN)
  497. // Specifies libraries to preload before the sandbox is locked down. Paths
  498. // should be absolute paths. Libraries will be preloaded before sandbox
  499. @@ -125,11 +149,20 @@ class CONTENT_EXPORT ServiceProcessHost {
  500. std::optional<GURL> site;
  501. std::optional<int> child_flags;
  502. std::vector<std::string> extra_switches;
  503. +#if BUILDFLAG(IS_WIN)
  504. + base::win::ScopedHandle stdout_handle;
  505. + base::win::ScopedHandle stderr_handle;
  506. +#elif BUILDFLAG(IS_POSIX)
  507. + base::FileHandleMappingVector fds_to_remap;
  508. +#endif
  509. base::OnceCallback<void(const base::Process&)> process_callback;
  510. #if BUILDFLAG(IS_WIN)
  511. std::vector<base::FilePath> preload_libraries;
  512. bool pin_user32;
  513. #endif // BUILDFLAG(IS_WIN)
  514. + base::FilePath current_directory;
  515. + base::EnvironmentMap environment;
  516. + bool clear_environment = false;
  517. };
  518. // An interface which can be implemented and registered/unregistered with
  519. diff --git a/content/public/common/sandbox_init_win.h b/content/public/common/sandbox_init_win.h
  520. index 9bb4b30ba0f5d37ec2b28f0848d94f34c24f9423..b614fef01ee5cdf81b7112be721b851c454756a2 100644
  521. --- a/content/public/common/sandbox_init_win.h
  522. +++ b/content/public/common/sandbox_init_win.h
  523. @@ -29,7 +29,7 @@ class SandboxedProcessLauncherDelegate;
  524. CONTENT_EXPORT sandbox::ResultCode StartSandboxedProcess(
  525. SandboxedProcessLauncherDelegate* delegate,
  526. const base::CommandLine& target_command_line,
  527. - const base::HandlesToInheritVector& handles_to_inherit,
  528. + const base::LaunchOptions* options,
  529. base::Process* process);
  530. } // namespace content
  531. diff --git a/content/public/common/sandboxed_process_launcher_delegate.cc b/content/public/common/sandboxed_process_launcher_delegate.cc
  532. index 9c1aa450f32b6812d4a87cd0b9ee0dfb1a9557f4..3360302b4511ed914ac2d5756dcc7edf7e675631 100644
  533. --- a/content/public/common/sandboxed_process_launcher_delegate.cc
  534. +++ b/content/public/common/sandboxed_process_launcher_delegate.cc
  535. @@ -68,11 +68,17 @@ ZygoteCommunication* SandboxedProcessLauncherDelegate::GetZygote() {
  536. }
  537. #endif // BUILDFLAG(USE_ZYGOTE)
  538. -#if BUILDFLAG(IS_POSIX)
  539. base::EnvironmentMap SandboxedProcessLauncherDelegate::GetEnvironment() {
  540. return base::EnvironmentMap();
  541. }
  542. -#endif // BUILDFLAG(IS_POSIX)
  543. +
  544. +bool SandboxedProcessLauncherDelegate::ShouldInheritEnvironment() {
  545. + return true;
  546. +}
  547. +
  548. +base::FilePath SandboxedProcessLauncherDelegate::GetCurrentDirectory() {
  549. + return base::FilePath();
  550. +}
  551. #if BUILDFLAG(IS_MAC)
  552. diff --git a/content/public/common/sandboxed_process_launcher_delegate.h b/content/public/common/sandboxed_process_launcher_delegate.h
  553. index cb43aa14c9742f3788ae58c3e49b890cd532f327..6a738f7aade504f2ff3bb6647a0da8f8d1933de2 100644
  554. --- a/content/public/common/sandboxed_process_launcher_delegate.h
  555. +++ b/content/public/common/sandboxed_process_launcher_delegate.h
  556. @@ -6,6 +6,7 @@
  557. #define CONTENT_PUBLIC_COMMON_SANDBOXED_PROCESS_LAUNCHER_DELEGATE_H_
  558. #include "base/environment.h"
  559. +#include "base/files/file_path.h"
  560. #include "base/files/scoped_file.h"
  561. #include "base/process/process.h"
  562. #include "build/build_config.h"
  563. @@ -57,10 +58,14 @@ class CONTENT_EXPORT SandboxedProcessLauncherDelegate
  564. virtual ZygoteCommunication* GetZygote();
  565. #endif // BUILDFLAG(USE_ZYGOTE)
  566. -#if BUILDFLAG(IS_POSIX)
  567. // Override this if the process needs a non-empty environment map.
  568. virtual base::EnvironmentMap GetEnvironment();
  569. -#endif // BUILDFLAG(IS_POSIX)
  570. +
  571. + // Override this if the process should not inherit parent environment.
  572. + virtual bool ShouldInheritEnvironment();
  573. +
  574. + // Specifies the directory to change to before executing the process.
  575. + virtual base::FilePath GetCurrentDirectory();
  576. #if BUILDFLAG(IS_MAC)
  577. // Whether or not to disclaim TCC responsibility for the process, defaults to
  578. diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc
  579. index 6bf94fa65c5b69bedd4e19973ffa275521bc331b..512e97a8124bb3809fea9128d1446cf22e49f25c 100644
  580. --- a/sandbox/policy/win/sandbox_win.cc
  581. +++ b/sandbox/policy/win/sandbox_win.cc
  582. @@ -747,11 +747,9 @@ base::win::ScopedHandle CreateUnsandboxedJob() {
  583. // command line flag.
  584. ResultCode LaunchWithoutSandbox(
  585. const base::CommandLine& cmd_line,
  586. - const base::HandlesToInheritVector& handles_to_inherit,
  587. + base::LaunchOptions options,
  588. SandboxDelegate* delegate,
  589. base::Process* process) {
  590. - base::LaunchOptions options;
  591. - options.handles_to_inherit = handles_to_inherit;
  592. // Network process runs in a job even when unsandboxed. This is to ensure it
  593. // does not outlive the browser, which could happen if there is a lot of I/O
  594. // on process shutdown, in which case TerminateProcess can fail. See
  595. @@ -971,7 +969,7 @@ bool SandboxWin::InitTargetServices(TargetServices* target_services) {
  596. ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  597. const base::CommandLine& cmd_line,
  598. const std::string& process_type,
  599. - const base::HandlesToInheritVector& handles_to_inherit,
  600. + const base::LaunchOptions* options,
  601. SandboxDelegate* delegate,
  602. TargetPolicy* policy) {
  603. const base::CommandLine& launcher_process_command_line =
  604. @@ -985,7 +983,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  605. }
  606. // Add any handles to be inherited to the policy.
  607. - for (HANDLE handle : handles_to_inherit)
  608. + for (HANDLE handle : options->handles_to_inherit)
  609. policy->AddHandleToShare(handle);
  610. if (!policy->GetConfig()->IsConfigured()) {
  611. @@ -1000,6 +998,13 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  612. // have no effect. These calls can fail with SBOX_ERROR_BAD_PARAMS.
  613. policy->SetStdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE));
  614. policy->SetStderrHandle(GetStdHandle(STD_ERROR_HANDLE));
  615. +#else
  616. + if (options->stdout_handle != nullptr && options->stdout_handle != INVALID_HANDLE_VALUE) {
  617. + policy->SetStdoutHandle(options->stdout_handle);
  618. + }
  619. + if (options->stderr_handle != nullptr && options->stderr_handle != INVALID_HANDLE_VALUE) {
  620. + policy->SetStderrHandle(options->stderr_handle);
  621. + }
  622. #endif
  623. if (!delegate->PreSpawnTarget(policy))
  624. @@ -1012,7 +1017,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess(
  625. ResultCode SandboxWin::StartSandboxedProcess(
  626. const base::CommandLine& cmd_line,
  627. const std::string& process_type,
  628. - const base::HandlesToInheritVector& handles_to_inherit,
  629. + const base::LaunchOptions* options,
  630. SandboxDelegate* delegate,
  631. base::Process* process) {
  632. SandboxLaunchTimer timer;
  633. @@ -1020,7 +1025,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
  634. // Avoid making a policy if we won't use it.
  635. if (IsUnsandboxedProcess(delegate->GetSandboxType(), cmd_line,
  636. *base::CommandLine::ForCurrentProcess())) {
  637. - return LaunchWithoutSandbox(cmd_line, handles_to_inherit, delegate,
  638. + return LaunchWithoutSandbox(cmd_line, *options, delegate,
  639. process);
  640. }
  641. @@ -1028,7 +1033,7 @@ ResultCode SandboxWin::StartSandboxedProcess(
  642. timer.OnPolicyCreated();
  643. ResultCode result = GeneratePolicyForSandboxedProcess(
  644. - cmd_line, process_type, handles_to_inherit, delegate, policy.get());
  645. + cmd_line, process_type, options, delegate, policy.get());
  646. if (SBOX_ALL_OK != result)
  647. return result;
  648. timer.OnPolicyGenerated();
  649. diff --git a/sandbox/policy/win/sandbox_win.h b/sandbox/policy/win/sandbox_win.h
  650. index 54d808db3a0a2aff198e132fae02c8649a0b547e..e1f5321298e634a310afc10773b93fedbad22431 100644
  651. --- a/sandbox/policy/win/sandbox_win.h
  652. +++ b/sandbox/policy/win/sandbox_win.h
  653. @@ -53,7 +53,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
  654. static ResultCode StartSandboxedProcess(
  655. const base::CommandLine& cmd_line,
  656. const std::string& process_type,
  657. - const base::HandlesToInheritVector& handles_to_inherit,
  658. + const base::LaunchOptions* options,
  659. SandboxDelegate* delegate,
  660. base::Process* process);
  661. @@ -67,7 +67,7 @@ class SANDBOX_POLICY_EXPORT SandboxWin {
  662. static ResultCode GeneratePolicyForSandboxedProcess(
  663. const base::CommandLine& cmd_line,
  664. const std::string& process_type,
  665. - const base::HandlesToInheritVector& handles_to_inherit,
  666. + const base::LaunchOptions* options,
  667. SandboxDelegate* delegate,
  668. TargetPolicy* policy);