diff options
Diffstat (limited to 'chromium/services/service_manager')
48 files changed, 213 insertions, 2504 deletions
diff --git a/chromium/services/service_manager/embedder/main.cc b/chromium/services/service_manager/embedder/main.cc index f9c275cdd78..d277d1eea17 100644 --- a/chromium/services/service_manager/embedder/main.cc +++ b/chromium/services/service_manager/embedder/main.cc @@ -361,8 +361,7 @@ int Main(const MainParams& params) { mojo_config.is_broker_process = true; } mojo_config.max_message_num_bytes = kMaximumMojoMessageSize; - delegate->OverrideMojoConfiguration(&mojo_config); - mojo::core::Init(mojo_config); + delegate->InitializeMojo(&mojo_config); ui::RegisterPathProvider(); diff --git a/chromium/services/service_manager/embedder/main_delegate.cc b/chromium/services/service_manager/embedder/main_delegate.cc index 439504e5012..65dec35a7a6 100644 --- a/chromium/services/service_manager/embedder/main_delegate.cc +++ b/chromium/services/service_manager/embedder/main_delegate.cc @@ -24,8 +24,7 @@ ProcessType MainDelegate::OverrideProcessType() { return ProcessType::kDefault; } -void MainDelegate::OverrideMojoConfiguration( - mojo::core::Configuration* config) {} +void MainDelegate::InitializeMojo(mojo::core::Configuration* config) {} std::vector<Manifest> MainDelegate::GetServiceManifests() { return std::vector<Manifest>(); diff --git a/chromium/services/service_manager/embedder/main_delegate.h b/chromium/services/service_manager/embedder/main_delegate.h index 70f9a3ed232..abced50cb03 100644 --- a/chromium/services/service_manager/embedder/main_delegate.h +++ b/chromium/services/service_manager/embedder/main_delegate.h @@ -71,8 +71,9 @@ class COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER) MainDelegate { // return |ProcessType::kDefault| to avoid overriding. virtual ProcessType OverrideProcessType(); - // Allows the embedder to override the process-wide Mojop configuration. - virtual void OverrideMojoConfiguration(mojo::core::Configuration* config); + // Allows the embedder to override the process-wide Mojo configuration and + // initialization. + virtual void InitializeMojo(mojo::core::Configuration* config); // Gets the list of service manifests with which to initialize the Service // Manager. This list must describe the complete set of usable services in diff --git a/chromium/services/service_manager/embedder/switches.cc b/chromium/services/service_manager/embedder/switches.cc index 8337a14af77..7bc83d1a551 100644 --- a/chromium/services/service_manager/embedder/switches.cc +++ b/chromium/services/service_manager/embedder/switches.cc @@ -58,9 +58,6 @@ const char kServiceRequestChannelToken[] = "service-request-channel-token"; // global descriptor table. const char kSharedFiles[] = "shared-files"; -// The prefix used when starting the zygote process. (i.e. 'gdb --args') -const char kZygoteCmdPrefix[] = "zygote-cmd-prefix"; - // Causes the process to run as a zygote. const char kZygoteProcess[] = "zygote"; diff --git a/chromium/services/service_manager/embedder/switches.h b/chromium/services/service_manager/embedder/switches.h index 548165e5d12..3b6690aa501 100644 --- a/chromium/services/service_manager/embedder/switches.h +++ b/chromium/services/service_manager/embedder/switches.h @@ -38,9 +38,6 @@ COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) extern const char kSharedFiles[]; COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) -extern const char kZygoteCmdPrefix[]; - -COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) extern const char kZygoteProcess[]; } // namespace switches diff --git a/chromium/services/service_manager/public/cpp/binder_registry.h b/chromium/services/service_manager/public/cpp/binder_registry.h index 15ddeac97cd..2144d87dff2 100644 --- a/chromium/services/service_manager/public/cpp/binder_registry.h +++ b/chromium/services/service_manager/public/cpp/binder_registry.h @@ -10,6 +10,7 @@ #include <string> #include "base/callback.h" +#include "base/logging.h" #include "base/memory/weak_ptr.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/system/message_pipe.h" @@ -27,19 +28,6 @@ class BinderRegistryWithArgs { BinderRegistryWithArgs() {} ~BinderRegistryWithArgs() = default; - // Adds an interface inferring the interface name via the templated - // parameter Interface::Name_ - // Usage example: //services/service_manager/README.md#OnBindInterface - template <typename Interface> - void AddInterface( - const base::RepeatingCallback<void(mojo::InterfaceRequest<Interface>, - BinderArgs...)>& callback, - const scoped_refptr<base::SequencedTaskRunner>& task_runner = nullptr) { - SetInterfaceBinder( - Interface::Name_, - std::make_unique<CallbackBinder<Interface, BinderArgs...>>( - callback, task_runner)); - } template <typename Interface> void AddInterface( const base::RepeatingCallback<void(mojo::PendingReceiver<Interface>, diff --git a/chromium/services/service_manager/public/cpp/connector.h b/chromium/services/service_manager/public/cpp/connector.h index a3b4953978d..0453141851d 100644 --- a/chromium/services/service_manager/public/cpp/connector.h +++ b/chromium/services/service_manager/public/cpp/connector.h @@ -192,19 +192,6 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT Connector { } template <typename Interface> - void BindInterface(const ServiceFilter& filter, - mojo::InterfacePtr<Interface>* ptr) { - BindInterface(filter, mojo::MakeRequest(ptr)); - } - - template <typename Interface> - void BindInterface(const std::string& service_name, - mojo::InterfacePtr<Interface>* ptr) { - return BindInterface(ServiceFilter::ByName(service_name), - mojo::MakeRequest(ptr)); - } - - template <typename Interface> void BindInterface(const std::string& service_name, mojo::PendingReceiver<Interface> receiver) { return BindInterface(ServiceFilter::ByName(service_name), diff --git a/chromium/services/service_manager/public/cpp/interface_binder.h b/chromium/services/service_manager/public/cpp/interface_binder.h index 96e12e88d31..ac357f663ec 100644 --- a/chromium/services/service_manager/public/cpp/interface_binder.h +++ b/chromium/services/service_manager/public/cpp/interface_binder.h @@ -9,7 +9,6 @@ #include <utility> #include "base/bind.h" -#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/system/message_pipe.h" @@ -31,8 +30,8 @@ class InterfaceBinder { virtual ~InterfaceBinder() {} // Asks the InterfaceBinder to bind an implementation of the specified - // interface to the request passed via |handle|. If the InterfaceBinder binds - // an implementation it must take ownership of the request handle. + // interface to the receiver passed via |handle|. If the InterfaceBinder binds + // an implementation it must take ownership of the receiver handle. virtual void BindInterface(const std::string& interface_name, mojo::ScopedMessagePipeHandle handle, BinderArgs... args) = 0; @@ -42,18 +41,12 @@ template <typename Interface, typename... BinderArgs> class CallbackBinder : public InterfaceBinder<BinderArgs...> { public: using BindCallback = - base::RepeatingCallback<void(mojo::InterfaceRequest<Interface>, + base::RepeatingCallback<void(mojo::PendingReceiver<Interface>, BinderArgs...)>; CallbackBinder(const BindCallback& callback, const scoped_refptr<base::SequencedTaskRunner>& task_runner) : callback_(callback), task_runner_(task_runner) {} - CallbackBinder( - const base::RepeatingCallback<void(mojo::PendingReceiver<Interface>, - BinderArgs...)>& callback, - const scoped_refptr<base::SequencedTaskRunner>& task_runner) - : CallbackBinder(base::BindRepeating(&RunBindReceiverCallback, callback), - task_runner) {} ~CallbackBinder() override = default; private: @@ -61,28 +54,28 @@ class CallbackBinder : public InterfaceBinder<BinderArgs...> { void BindInterface(const std::string& interface_name, mojo::ScopedMessagePipeHandle handle, BinderArgs... args) override { - mojo::InterfaceRequest<Interface> request(std::move(handle)); + mojo::PendingReceiver<Interface> receiver(std::move(handle)); if (task_runner_) { task_runner_->PostTask( FROM_HERE, base::BindOnce(&CallbackBinder::RunCallback, callback_, - std::move(request), args...)); + std::move(receiver), args...)); } else { - RunCallback(callback_, std::move(request), args...); + RunCallback(callback_, std::move(receiver), args...); } } static void RunCallback(const BindCallback& callback, - mojo::InterfaceRequest<Interface> request, + mojo::PendingReceiver<Interface> receiver, BinderArgs... args) { - callback.Run(std::move(request), args...); + callback.Run(std::move(receiver), args...); } static void RunBindReceiverCallback( const base::RepeatingCallback<void(mojo::PendingReceiver<Interface>, BinderArgs...)>& callback, - mojo::InterfaceRequest<Interface> request, + mojo::PendingReceiver<Interface> receiver, BinderArgs... args) { - callback.Run(std::move(request), args...); + callback.Run(std::move(receiver), args...); } const BindCallback callback_; diff --git a/chromium/services/service_manager/public/cpp/interface_provider.h b/chromium/services/service_manager/public/cpp/interface_provider.h index 6b5f693afc4..9d65071c00c 100644 --- a/chromium/services/service_manager/public/cpp/interface_provider.h +++ b/chromium/services/service_manager/public/cpp/interface_provider.h @@ -16,7 +16,7 @@ namespace service_manager { // Encapsulates a mojo::PendingRemote|Remote<mojom::InterfaceProvider> // implemented in a remote application. Provides two main features: -// - a typesafe GetInterface() method for binding InterfacePtrs. +// - a typesafe GetInterface() method for binding Interface remotes. // - a testing API that allows local callbacks to be registered that bind // requests for remote interfaces. // An instance of this class is used by the GetInterface() methods on @@ -87,18 +87,11 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT InterfaceProvider { base::WeakPtr<InterfaceProvider> GetWeakPtr(); - // Binds a passed in interface pointer to an implementation of the interface - // in the remote application using MakeRequest. The interface pointer can - // immediately be used to start sending requests to the remote interface. - // Uses templated parameters in order to work with weak interfaces in blink. - template <typename... Args> - void GetInterface(Args&&... args) { - GetInterface(MakeRequest(std::forward<Args>(args)...)); - } - template <typename Interface> - void GetInterface(mojo::InterfaceRequest<Interface> request) { - GetInterfaceByName(Interface::Name_, std::move(request.PassMessagePipe())); - } + // Binds a passed in pending receiver to an implementation of the interface in + // the remote application. The mojo remote associated to the interface in the + // local application can immediately be used to start sending requests to the + // remote interface. Uses templated parameters in order to work with weak + // interfaces in blink. template <typename Interface> void GetInterface(mojo::PendingReceiver<Interface> receiver) { GetInterfaceByName(Interface::Name_, receiver.PassPipe()); @@ -106,23 +99,7 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT InterfaceProvider { void GetInterfaceByName(const std::string& name, mojo::ScopedMessagePipeHandle request_handle); - // Returns a callback to GetInterface<Interface>(). This can be passed to - // BinderRegistry::AddInterface() to forward requests. - template <typename Interface> - base::RepeatingCallback<void(mojo::InterfaceRequest<Interface>)> - CreateInterfaceFactory() { - return base::BindRepeating( - &InterfaceProvider::BindInterfaceRequestFromSource<Interface>, - GetWeakPtr()); - } - private: - template <typename Interface> - void BindInterfaceRequestFromSource( - mojo::InterfaceRequest<Interface> request) { - GetInterface<Interface>(std::move(request)); - } - void SetBinderForName( const std::string& name, base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle)> binder) { diff --git a/chromium/services/service_manager/public/cpp/local_interface_provider.h b/chromium/services/service_manager/public/cpp/local_interface_provider.h index abf1f739a6f..10e4e840ed1 100644 --- a/chromium/services/service_manager/public/cpp/local_interface_provider.h +++ b/chromium/services/service_manager/public/cpp/local_interface_provider.h @@ -6,8 +6,6 @@ #define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_INTERFACE_PROVIDER_BASE_H_ #include "base/macros.h" -#include "mojo/public/cpp/bindings/interface_ptr.h" -#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/system/message_pipe.h" #include "services/service_manager/public/cpp/export.h" @@ -18,19 +16,6 @@ class LocalInterfaceProvider { public: virtual ~LocalInterfaceProvider() = default; - // Binds |ptr| to an implementation of Interface in the remote application. - // |ptr| can immediately be used to start sending requests to the remote - // interface. - template <typename Interface> - void GetInterface(mojo::InterfacePtr<Interface>* ptr) { - mojo::MessagePipe pipe; - ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u)); - GetInterface(Interface::Name_, std::move(pipe.handle1)); - } - template <typename Interface> - void GetInterface(mojo::InterfaceRequest<Interface> request) { - GetInterface(Interface::Name_, std::move(request.PassMessagePipe())); - } template <typename Interface> void GetInterface(mojo::PendingReceiver<Interface> receiver) { GetInterface(Interface::Name_, std::move(receiver.PassPipe())); diff --git a/chromium/services/service_manager/sandbox/BUILD.gn b/chromium/services/service_manager/sandbox/BUILD.gn index 0e9bfbf0327..21749ad3322 100644 --- a/chromium/services/service_manager/sandbox/BUILD.gn +++ b/chromium/services/service_manager/sandbox/BUILD.gn @@ -79,6 +79,8 @@ component("sandbox") { sources += [ "linux/bpf_ime_policy_linux.cc", "linux/bpf_ime_policy_linux.h", + "linux/bpf_tts_policy_linux.cc", + "linux/bpf_tts_policy_linux.h", ] } if (is_mac) { diff --git a/chromium/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc b/chromium/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc index 2747e169d6a..0d178b90d10 100644 --- a/chromium/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc +++ b/chromium/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc @@ -28,10 +28,10 @@ #include "base/command_line.h" #include "base/containers/span.h" #include "base/files/file_util.h" -#include "base/fuchsia/default_context.h" #include "base/fuchsia/default_job.h" #include "base/fuchsia/filtered_service_directory.h" #include "base/fuchsia/fuchsia_logging.h" +#include "base/fuchsia/process_context.h" #include "base/path_service.h" #include "base/process/launch.h" #include "base/process/process.h" @@ -167,7 +167,7 @@ SandboxPolicyFuchsia::SandboxPolicyFuchsia(service_manager::SandboxType type) { service_directory_task_runner_ = base::ThreadTaskRunnerHandle::Get(); service_directory_ = std::make_unique<base::fuchsia::FilteredServiceDirectory>( - base::fuchsia::ComponentContextForCurrentProcess()->svc().get()); + base::ComponentContextForProcess()->svc().get()); for (const char* service_name : kDefaultServices) { service_directory_->AddService(service_name); } diff --git a/chromium/services/service_manager/sandbox/linux/bpf_tts_policy_linux.cc b/chromium/services/service_manager/sandbox/linux/bpf_tts_policy_linux.cc new file mode 100644 index 00000000000..812072395ec --- /dev/null +++ b/chromium/services/service_manager/sandbox/linux/bpf_tts_policy_linux.cc @@ -0,0 +1,34 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/service_manager/sandbox/linux/bpf_tts_policy_linux.h" + +#include <sys/socket.h> + +#include "sandbox/linux/bpf_dsl/bpf_dsl.h" +#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" +#include "sandbox/linux/syscall_broker/broker_process.h" +#include "sandbox/linux/system_headers/linux_syscalls.h" +#include "services/service_manager/sandbox/linux/sandbox_linux.h" + +using sandbox::bpf_dsl::Allow; +using sandbox::bpf_dsl::ResultExpr; +using sandbox::bpf_dsl::Trap; +using sandbox::syscall_broker::BrokerProcess; + +namespace service_manager { + +TtsProcessPolicy::TtsProcessPolicy() {} + +TtsProcessPolicy::~TtsProcessPolicy() {} + +ResultExpr TtsProcessPolicy::EvaluateSyscall(int sysno) const { + auto* broker_process = SandboxLinux::GetInstance()->broker_process(); + if (broker_process->IsSyscallAllowed(sysno)) + return Trap(BrokerProcess::SIGSYS_Handler, broker_process); + + return BPFBasePolicy::EvaluateSyscall(sysno); +} + +} // namespace service_manager diff --git a/chromium/services/service_manager/sandbox/linux/bpf_tts_policy_linux.h b/chromium/services/service_manager/sandbox/linux/bpf_tts_policy_linux.h new file mode 100644 index 00000000000..a562a68cfce --- /dev/null +++ b/chromium/services/service_manager/sandbox/linux/bpf_tts_policy_linux.h @@ -0,0 +1,27 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_SERVICE_MANAGER_SANDBOX_LINUX_BPF_TTS_POLICY_LINUX_H_ +#define SERVICES_SERVICE_MANAGER_SANDBOX_LINUX_BPF_TTS_POLICY_LINUX_H_ + +#include "sandbox/linux/bpf_dsl/bpf_dsl.h" +#include "services/service_manager/sandbox/export.h" +#include "services/service_manager/sandbox/linux/bpf_base_policy_linux.h" + +namespace service_manager { + +class SERVICE_MANAGER_SANDBOX_EXPORT TtsProcessPolicy : public BPFBasePolicy { + public: + TtsProcessPolicy(); + ~TtsProcessPolicy() override; + + sandbox::bpf_dsl::ResultExpr EvaluateSyscall(int sysno) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(TtsProcessPolicy); +}; + +} // namespace service_manager + +#endif // SERVICES_SERVICE_MANAGER_SANDBOX_LINUX_BPF_TTS_POLICY_LINUX_H_ diff --git a/chromium/services/service_manager/sandbox/linux/sandbox_linux.h b/chromium/services/service_manager/sandbox/linux/sandbox_linux.h index 9f67272c5e2..6a17f9edb63 100644 --- a/chromium/services/service_manager/sandbox/linux/sandbox_linux.h +++ b/chromium/services/service_manager/sandbox/linux/sandbox_linux.h @@ -9,7 +9,7 @@ #include <string> #include <vector> -#include "base/logging.h" +#include "base/check_op.h" #include "base/macros.h" #include "base/posix/global_descriptors.h" #include "sandbox/linux/syscall_broker/broker_command.h" diff --git a/chromium/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc b/chromium/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc index e2f22540a5a..1c16d68df91 100644 --- a/chromium/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc +++ b/chromium/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc @@ -54,6 +54,7 @@ #if defined(OS_CHROMEOS) #include "services/service_manager/sandbox/linux/bpf_ime_policy_linux.h" +#include "services/service_manager/sandbox/linux/bpf_tts_policy_linux.h" #endif // defined(OS_CHROMEOS) using sandbox::BaselinePolicy; @@ -185,6 +186,8 @@ std::unique_ptr<BPFBasePolicy> SandboxSeccompBPF::PolicyForSandboxType( #if defined(OS_CHROMEOS) case SandboxType::kIme: return std::make_unique<ImeProcessPolicy>(); + case SandboxType::kTts: + return std::make_unique<TtsProcessPolicy>(); #endif // defined(OS_CHROMEOS) case SandboxType::kZygoteIntermediateSandbox: case SandboxType::kNoSandbox: @@ -228,6 +231,7 @@ void SandboxSeccompBPF::RunSandboxSanityChecks( } break; #if defined(OS_CHROMEOS) case SandboxType::kIme: + case SandboxType::kTts: #endif // defined(OS_CHROMEOS) case SandboxType::kAudio: case SandboxType::kSharingService: diff --git a/chromium/services/service_manager/sandbox/sandbox_type.cc b/chromium/services/service_manager/sandbox/sandbox_type.cc index 9ea1cccb467..de79b63b7de 100644 --- a/chromium/services/service_manager/sandbox/sandbox_type.cc +++ b/chromium/services/service_manager/sandbox/sandbox_type.cc @@ -8,6 +8,7 @@ #include "base/check.h" #include "base/feature_list.h" +#include "base/logging.h" #include "base/notreached.h" #include "services/service_manager/sandbox/features.h" #include "services/service_manager/sandbox/switches.h" @@ -26,6 +27,7 @@ bool IsUnsandboxedSandboxType(SandboxType sandbox_type) { service_manager::features::kXRSandbox); case SandboxType::kProxyResolver: case SandboxType::kPdfConversion: + case SandboxType::kIconReader: return false; #endif case SandboxType::kAudio: @@ -57,6 +59,7 @@ bool IsUnsandboxedSandboxType(SandboxType sandbox_type) { #endif #if defined(OS_CHROMEOS) case SandboxType::kIme: + case SandboxType::kTts: #endif #if !defined(OS_MACOSX) case SandboxType::kSharingService: @@ -116,9 +119,11 @@ void SetCommandLineFlagsForSandboxType(base::CommandLine* command_line, case SandboxType::kXrCompositing: case SandboxType::kProxyResolver: case SandboxType::kPdfConversion: + case SandboxType::kIconReader: #endif // defined(OS_WIN) #if defined(OS_CHROMEOS) case SandboxType::kIme: + case SandboxType::kTts: #endif // defined(OS_CHROMEOS) #if !defined(OS_MACOSX) case SandboxType::kSharingService: @@ -237,10 +242,14 @@ std::string StringFromUtilitySandboxType(SandboxType sandbox_type) { return switches::kProxyResolverSandbox; case SandboxType::kPdfConversion: return switches::kPdfConversionSandbox; + case SandboxType::kIconReader: + return switches::kIconReaderSandbox; #endif // defined(OS_WIN) #if defined(OS_CHROMEOS) case SandboxType::kIme: return switches::kImeSandbox; + case SandboxType::kTts: + return switches::kTtsSandbox; #endif // defined(OS_CHROMEOS) // The following are not utility processes so should not occur. case SandboxType::kRenderer: @@ -287,6 +296,8 @@ SandboxType UtilitySandboxTypeFromString(const std::string& sandbox_string) { return SandboxType::kProxyResolver; if (sandbox_string == switches::kPdfConversionSandbox) return SandboxType::kPdfConversion; + if (sandbox_string == switches::kIconReaderSandbox) + return SandboxType::kIconReader; #endif if (sandbox_string == switches::kAudioSandbox) return SandboxType::kAudio; @@ -297,6 +308,8 @@ SandboxType UtilitySandboxTypeFromString(const std::string& sandbox_string) { #if defined(OS_CHROMEOS) if (sandbox_string == switches::kImeSandbox) return SandboxType::kIme; + if (sandbox_string == switches::kTtsSandbox) + return SandboxType::kTts; #endif // defined(OS_CHROMEOS) return SandboxType::kUtility; } diff --git a/chromium/services/service_manager/sandbox/sandbox_type.h b/chromium/services/service_manager/sandbox/sandbox_type.h index 0eb1e615939..b35e3950ccf 100644 --- a/chromium/services/service_manager/sandbox/sandbox_type.h +++ b/chromium/services/service_manager/sandbox/sandbox_type.h @@ -30,6 +30,9 @@ enum class SandboxType { // The PDF conversion service process used in printing. kPdfConversion, + + // The icon reader service. + kIconReader, #endif #if defined(OS_FUCHSIA) @@ -69,6 +72,8 @@ enum class SandboxType { #if defined(OS_CHROMEOS) kIme, + // Text-to-speech. + kTts, #endif // defined(OS_CHROMEOS) #if defined(OS_LINUX) diff --git a/chromium/services/service_manager/sandbox/switches.cc b/chromium/services/service_manager/sandbox/switches.cc index 863638ae365..e635d4e8eed 100644 --- a/chromium/services/service_manager/sandbox/switches.cc +++ b/chromium/services/service_manager/sandbox/switches.cc @@ -36,10 +36,12 @@ const char kVideoCaptureSandbox[] = "video_capture"; const char kPdfConversionSandbox[] = "pdf_conversion"; const char kProxyResolverSandbox[] = "proxy_resolver"; const char kXrCompositingSandbox[] = "xr_compositing"; +const char kIconReaderSandbox[] = "icon_reader"; #endif // OS_WIN #if defined(OS_CHROMEOS) const char kImeSandbox[] = "ime"; +const char kTtsSandbox[] = "tts"; #endif // OS_CHROMEOS // Flags owned by the service manager sandbox. @@ -80,6 +82,7 @@ const char kGpuSandboxAllowSysVShm[] = "gpu-sandbox-allow-sysv-shm"; const char kGpuSandboxFailuresFatal[] = "gpu-sandbox-failures-fatal"; // Disables the sandbox for all process types that are normally sandboxed. +// Meant to be used as a browser-level switch for testing purposes only. const char kNoSandbox[] = "no-sandbox"; #if defined(OS_LINUX) diff --git a/chromium/services/service_manager/sandbox/switches.h b/chromium/services/service_manager/sandbox/switches.h index 0deedde8296..6d66ab6c4f2 100644 --- a/chromium/services/service_manager/sandbox/switches.h +++ b/chromium/services/service_manager/sandbox/switches.h @@ -35,10 +35,12 @@ SERVICE_MANAGER_SANDBOX_EXPORT extern const char kVideoCaptureSandbox[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kPdfConversionSandbox[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kProxyResolverSandbox[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kXrCompositingSandbox[]; +SERVICE_MANAGER_SANDBOX_EXPORT extern const char kIconReaderSandbox[]; #endif // OS_WIN #if defined(OS_CHROMEOS) SERVICE_MANAGER_SANDBOX_EXPORT extern const char kImeSandbox[]; +SERVICE_MANAGER_SANDBOX_EXPORT extern const char kTtsSandbox[]; #endif // OS_CHROMEOS // Flags owned by the service manager sandbox. diff --git a/chromium/services/service_manager/sandbox/win/sandbox_diagnostics.h b/chromium/services/service_manager/sandbox/win/sandbox_diagnostics.h index 5470fe1ada6..1f89e7ee7a9 100644 --- a/chromium/services/service_manager/sandbox/win/sandbox_diagnostics.h +++ b/chromium/services/service_manager/sandbox/win/sandbox_diagnostics.h @@ -14,7 +14,6 @@ #include <vector> #include "base/callback.h" -#include "base/logging.h" #include "base/sequenced_task_runner.h" #include "base/values.h" #include "sandbox/constants.h" diff --git a/chromium/services/service_manager/sandbox/win/sandbox_win.cc b/chromium/services/service_manager/sandbox/win/sandbox_win.cc index a05106e2611..cde75bd0710 100644 --- a/chromium/services/service_manager/sandbox/win/sandbox_win.cc +++ b/chromium/services/service_manager/sandbox/win/sandbox_win.cc @@ -33,6 +33,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/system/sys_info.h" +#include "base/trace_event/trace_arguments.h" #include "base/trace_event/trace_event.h" #include "base/win/iat_patch_function.h" #include "base/win/scoped_handle.h" @@ -44,6 +45,7 @@ #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/sandbox_nt_util.h" #include "sandbox/win/src/sandbox_policy_base.h" +#include "sandbox/win/src/sandbox_policy_diagnostic.h" #include "sandbox/win/src/win_utils.h" #include "services/service_manager/sandbox/features.h" #include "services/service_manager/sandbox/sandbox_type.h" @@ -150,6 +152,26 @@ const wchar_t* const kTroublesomeDlls[] = { const base::Feature kEnableCsrssLockdownFeature{ "EnableCsrssLockdown", base::FEATURE_DISABLED_BY_DEFAULT}; +// Helps emit trace events for sandbox policy. This mediates memory between +// chrome.exe and chrome.dll. +class PolicyTraceHelper : public base::trace_event::ConvertableToTraceFormat { + public: + PolicyTraceHelper(sandbox::TargetPolicy* policy) { + // |info| must live until JsonString() output is copied. + std::unique_ptr<sandbox::PolicyInfo> info = policy->GetPolicyInfo(); + json_string_ = std::string(info->JsonString()); + } + ~PolicyTraceHelper() override = default; + + // ConvertableToTraceFormat. + void AppendAsTraceFormat(std::string* out) const override { + out->append(json_string_); + } + + private: + std::string json_string_; +}; // PolicyTraceHelper + #if !defined(NACL_WIN64) // Adds the policy rules for the path and path\ with the semantic |access|. // If |children| is set to true, we need to add the wildcard rules to also @@ -599,14 +621,15 @@ base::string16 GetAppContainerProfileName( sandbox_type == SandboxType::kXrCompositing); auto sha1 = base::SHA1HashString(appcontainer_id); std::string sandbox_base_name = (sandbox_type == SandboxType::kXrCompositing) - ? std::string("chrome.sandbox.xrdevice") - : std::string("chrome.sandbox.gpu"); + ? std::string("cr.sb.xr") + : std::string("cr.sb.gpu"); std::string profile_name = base::StrCat( {sandbox_base_name, base::HexEncode(sha1.data(), sha1.size())}); // CreateAppContainerProfile requires that the profile name is at most 64 - // characters. The size of sha1 is a constant 40, so validate that the base - // names are sufficiently short that the total length is valid. - DCHECK_LE(profile_name.length(), 64U); + // characters but 50 on WCOS systems. The size of sha1 is a constant 40, + // so validate that the base names are sufficiently short that the total + // length is valid on all systems. + DCHECK_LE(profile_name.length(), 50U); return base::UTF8ToWide(profile_name); } @@ -845,6 +868,7 @@ bool SandboxWin::InitTargetServices(sandbox::TargetServices* target_services) { return sandbox::SBOX_ALL_OK == result; } +// static sandbox::ResultCode SandboxWin::StartSandboxedProcess( base::CommandLine* cmd_line, const std::string& process_type, @@ -929,7 +953,8 @@ sandbox::ResultCode SandboxWin::StartSandboxedProcess( if (!cmd_line->HasSwitch(switches::kAllowThirdPartyModules)) mitigations |= sandbox::MITIGATION_FORCE_MS_SIGNED_BINS; if (sandbox_type == SandboxType::kNetwork || - sandbox_type == SandboxType::kAudio) { + sandbox_type == SandboxType::kAudio || + sandbox_type == SandboxType::kIconReader) { mitigations |= sandbox::MITIGATION_DYNAMIC_CODE_DISABLE; } // TODO(wfh): Relax strict handle checks for network process until root cause @@ -1017,20 +1042,17 @@ sandbox::ResultCode SandboxWin::StartSandboxedProcess( cmd_line->GetCommandLineString().c_str(), policy, &last_warning, &last_error, &temp_process_info); - // TODO(1059129) Remove logging and underlying plumbing on expiry. - // This must be logged after spawning the process as the policy - // memory is not committed until the target process is attached to - // the sandbox policy. Max is kPolMemSize from sandbox_policy_base.cc. - if (result == sandbox::SBOX_ALL_OK) { - UMA_HISTOGRAM_CUSTOM_COUNTS("Process.Sandbox.PolicyGlobalSizeOnSuccess", - policy->GetPolicyGlobalSize(), 16, 14 * 4096, - 50); - } - base::win::ScopedProcessInformation target(temp_process_info); TRACE_EVENT_END0("startup", "StartProcessWithAccess::LAUNCHPROCESS"); + // Trace policy as processes are started. Useful for both failure and success. + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("sandbox"), "processLaunch", + TRACE_EVENT_SCOPE_PROCESS, "sandboxType", + GetSandboxTypeInEnglish(delegate->GetSandboxType()), + "policy", + std::make_unique<PolicyTraceHelper>(policy.get())); + if (sandbox::SBOX_ALL_OK != result) { base::UmaHistogramSparse("Process.Sandbox.Launch.Error", last_error); if (result == sandbox::SBOX_ERROR_GENERIC) @@ -1057,6 +1079,7 @@ sandbox::ResultCode SandboxWin::StartSandboxedProcess( return sandbox::SBOX_ALL_OK; } +// static sandbox::ResultCode SandboxWin::GetPolicyDiagnostics( base::OnceCallback<void(base::Value)> response) { CHECK(g_broker_services); @@ -1072,4 +1095,44 @@ void BlocklistAddOneDllForTesting(const wchar_t* module_name, BlocklistAddOneDll(module_name, check_in_browser, policy); } +// static +std::string SandboxWin::GetSandboxTypeInEnglish(SandboxType sandbox_type) { + switch (sandbox_type) { + case SandboxType::kNoSandbox: + return "Unsandboxed"; + case SandboxType::kNoSandboxAndElevatedPrivileges: + return "Unsandboxed (Elevated)"; + case SandboxType::kXrCompositing: + return "XR Compositing"; + case SandboxType::kRenderer: + return "Renderer"; + case SandboxType::kUtility: + return "Utility"; + case SandboxType::kGpu: + return "GPU"; + case SandboxType::kPpapi: + return "PPAPI"; + case SandboxType::kNetwork: + return "Network"; + case SandboxType::kCdm: + return "CDM"; + case SandboxType::kPrintCompositor: + return "Print Compositor"; + case SandboxType::kAudio: + return "Audio"; + case SandboxType::kSpeechRecognition: + return "Speech Recognition"; + case SandboxType::kProxyResolver: + return "Proxy Resolver"; + case SandboxType::kPdfConversion: + return "PDF Conversion"; + case SandboxType::kSharingService: + return "Sharing"; + case SandboxType::kVideoCapture: + return "Video Capture"; + case SandboxType::kIconReader: + return "Icon Reader"; + } +} + } // namespace service_manager diff --git a/chromium/services/service_manager/sandbox/win/sandbox_win.h b/chromium/services/service_manager/sandbox/win/sandbox_win.h index b39b213ec05..6614a82461e 100644 --- a/chromium/services/service_manager/sandbox/win/sandbox_win.h +++ b/chromium/services/service_manager/sandbox/win/sandbox_win.h @@ -87,6 +87,9 @@ class SERVICE_MANAGER_SANDBOX_EXPORT SandboxWin { // will be an empty value if an error is encountered. static sandbox::ResultCode GetPolicyDiagnostics( base::OnceCallback<void(base::Value)> response); + + // Provides a friendly name for the sandbox for chrome://sandbox and tracing. + static std::string GetSandboxTypeInEnglish(SandboxType sandbox_type); }; SERVICE_MANAGER_SANDBOX_EXPORT diff --git a/chromium/services/service_manager/service_instance.h b/chromium/services/service_manager/service_instance.h index 513d58c9acb..20a3700f130 100644 --- a/chromium/services/service_manager/service_instance.h +++ b/chromium/services/service_manager/service_instance.h @@ -12,7 +12,6 @@ #include <string> #include "base/containers/unique_ptr_adapters.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" diff --git a/chromium/services/service_manager/service_manager.cc b/chromium/services/service_manager/service_manager.cc index cb0a52ba8bd..ceb1ea74f24 100644 --- a/chromium/services/service_manager/service_manager.cc +++ b/chromium/services/service_manager/service_manager.cc @@ -86,9 +86,8 @@ class DefaultServiceProcessHost : public ServiceProcessHost { #else // TODO(https://crbug.com/781334): Support sandboxing. CHECK_EQ(sandbox_type, SandboxType::kNoSandbox); - return launcher_ - .Start(identity, SandboxType::kNoSandbox, std::move(callback)) - .PassInterface(); + return launcher_.Start(identity, SandboxType::kNoSandbox, + std::move(callback)); #endif // defined(OS_IOS) } diff --git a/chromium/services/service_manager/service_process_launcher.cc b/chromium/services/service_manager/service_process_launcher.cc index a87a5339a24..2a738f1ab64 100644 --- a/chromium/services/service_manager/service_process_launcher.cc +++ b/chromium/services/service_manager/service_process_launcher.cc @@ -93,9 +93,10 @@ ServiceProcessLauncher::~ServiceProcessLauncher() { FROM_HERE, base::BindOnce(&ProcessState::StopInBackground, state_)); } -mojom::ServicePtr ServiceProcessLauncher::Start(const Identity& target, - SandboxType sandbox_type, - ProcessReadyCallback callback) { +mojo::PendingRemote<mojom::Service> ServiceProcessLauncher::Start( + const Identity& target, + SandboxType sandbox_type, + ProcessReadyCallback callback) { DCHECK(!state_); const base::CommandLine& parent_command_line = @@ -139,7 +140,7 @@ mojom::ServicePtr ServiceProcessLauncher::Start(const Identity& target, channel.PrepareToPassRemoteEndpoint(&handle_passing_info, child_command_line.get()); mojo::OutgoingInvitation invitation; - mojom::ServicePtr client = + auto client = PassServiceRequestOnCommandLine(&invitation, child_command_line.get()); if (delegate_) { @@ -160,14 +161,15 @@ mojom::ServicePtr ServiceProcessLauncher::Start(const Identity& target, } // static -mojom::ServicePtr ServiceProcessLauncher::PassServiceRequestOnCommandLine( +mojo::PendingRemote<mojom::Service> +ServiceProcessLauncher::PassServiceRequestOnCommandLine( mojo::OutgoingInvitation* invitation, base::CommandLine* command_line) { const auto attachment_name = base::NumberToString(base::RandUint64()); command_line->AppendSwitchASCII(switches::kServiceRequestAttachmentName, attachment_name); - return mojom::ServicePtr{ - mojom::ServicePtrInfo{invitation->AttachMessagePipe(attachment_name), 0}}; + return mojo::PendingRemote<mojom::Service>( + invitation->AttachMessagePipe(attachment_name), 0); } base::ProcessId ServiceProcessLauncher::ProcessState::LaunchInBackground( diff --git a/chromium/services/service_manager/service_process_launcher.h b/chromium/services/service_manager/service_process_launcher.h index 12ad8867691..1b0b04ff5c5 100644 --- a/chromium/services/service_manager/service_process_launcher.h +++ b/chromium/services/service_manager/service_process_launcher.h @@ -15,6 +15,7 @@ #include "base/memory/weak_ptr.h" #include "base/process/process.h" #include "base/sequenced_task_runner.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "services/service_manager/public/mojom/service.mojom.h" #include "services/service_manager/sandbox/sandbox_type.h" #include "services/service_manager/service_process_launcher_delegate.h" @@ -47,9 +48,9 @@ class ServiceProcessLauncher { // |Start()|s the child process; calls |DidStart()| (on the thread on which // |Start()| was called) when the child has been started (or failed to start). - mojom::ServicePtr Start(const Identity& target, - SandboxType sandbox_type, - ProcessReadyCallback callback); + mojo::PendingRemote<mojom::Service> Start(const Identity& target, + SandboxType sandbox_type, + ProcessReadyCallback callback); // Exposed publicly for use in tests. Creates a new Service pipe, passing the // ServiceRequest end through |*invitation| with an identifier stashed in @@ -57,7 +58,7 @@ class ServiceProcessLauncher { // from the invitation. // // Returns the corresponding ServicePtr endpoint. - static mojom::ServicePtr PassServiceRequestOnCommandLine( + static mojo::PendingRemote<mojom::Service> PassServiceRequestOnCommandLine( mojo::OutgoingInvitation* invitation, base::CommandLine* command_line); diff --git a/chromium/services/service_manager/zygote/BUILD.gn b/chromium/services/service_manager/zygote/BUILD.gn deleted file mode 100644 index da276ffcc78..00000000000 --- a/chromium/services/service_manager/zygote/BUILD.gn +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/buildflag_header.gni") -import("//build/config/nacl/config.gni") -import("//services/service_manager/zygote/common/zygote_features.gni") - -if (is_linux) { - component("zygote") { - if (is_nacl_nonsfi) { - # When running the nacl toolchain is_linux is false so *_linux.cc files are - # excluded. Reset the filter so they are included. - set_sources_assignment_filter([]) - } - - sources = [ - "common/common_sandbox_support_linux.cc", - "common/common_sandbox_support_linux.h", - "common/zygote_fork_delegate_linux.h", - "common/zygote_handle.h", - "host/zygote_communication_linux.cc", - "host/zygote_communication_linux.h", - "host/zygote_host_impl_linux.cc", - "host/zygote_host_impl_linux.h", - "zygote_linux.cc", - "zygote_linux.h", - "zygote_main.h", - "zygote_main_linux.cc", - ] - - if (use_zygote_handle) { - sources += [ - "common/zygote_handle.h", - "host/zygote_handle_linux.cc", - ] - } - - public_deps = [ - ":zygote_buildflags", - ":zygote_util", - ] - - deps = [ - "//base", - "//base:i18n", - "//ipc", - "//sandbox", - "//services/service_manager/embedder", - "//services/service_manager/sandbox", - "//third_party/icu", - ] - - defines = [ "IS_SERVICE_MANAGER_ZYGOTE_IMPL" ] - } -} - -source_set("zygote_util") { - if (is_nacl_nonsfi) { - # When running the nacl toolchain is_linux is false so *_linux.cc files are - # excluded. Reset the filter so they are included. - set_sources_assignment_filter([]) - } - - sources = [ - "common/send_zygote_child_ping_linux.cc", - "common/send_zygote_child_ping_linux.h", - "common/zygote_commands_linux.h", - ] - - deps = [ - "//base", - "//services/service_manager/sandbox:sanitizer_buildflags", - ] - - defines = [ "IS_SERVICE_MANAGER_ZYGOTE_IMPL" ] -} - -buildflag_header("zygote_buildflags") { - header = "common/zygote_buildflags.h" - flags = [ "USE_ZYGOTE_HANDLE=$use_zygote_handle" ] -} diff --git a/chromium/services/service_manager/zygote/DEPS b/chromium/services/service_manager/zygote/DEPS deleted file mode 100644 index ec69c8f59a8..00000000000 --- a/chromium/services/service_manager/zygote/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+sandbox", -] diff --git a/chromium/services/service_manager/zygote/OWNERS b/chromium/services/service_manager/zygote/OWNERS deleted file mode 100644 index d38314f3fdd..00000000000 --- a/chromium/services/service_manager/zygote/OWNERS +++ /dev/null @@ -1,7 +0,0 @@ -jln@chromium.org -palmer@chromium.org -rsesek@chromium.org -tsepez@chromium.org - -# TEAM: security-dev@chromium.org -# COMPONENT: Internals>Sandbox diff --git a/chromium/services/service_manager/zygote/common/common_sandbox_support_linux.cc b/chromium/services/service_manager/zygote/common/common_sandbox_support_linux.cc deleted file mode 100644 index 742fab4472b..00000000000 --- a/chromium/services/service_manager/zygote/common/common_sandbox_support_linux.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/common/common_sandbox_support_linux.h" - -#include "base/pickle.h" -#include "base/posix/global_descriptors.h" -#include "base/posix/unix_domain_socket.h" -#include "services/service_manager/embedder/descriptors.h" -#include "services/service_manager/sandbox/linux/sandbox_linux.h" - -namespace service_manager { - -#if !defined(OS_NACL_NONSFI) -int SharedMemoryIPCSupport::MakeSharedMemorySegment(size_t length, - bool executable) { - base::Pickle request; - request.WriteInt( - service_manager::SandboxLinux::METHOD_MAKE_SHARED_MEMORY_SEGMENT); - request.WriteUInt32(length); - request.WriteBool(executable); - uint8_t reply_buf[10]; - int result_fd; - ssize_t result = base::UnixDomainSocket::SendRecvMsg( - GetSandboxFD(), reply_buf, sizeof(reply_buf), &result_fd, request); - if (result == -1) - return -1; - return result_fd; -} -#endif - -int GetSandboxFD() { - return service_manager::kSandboxIPCChannel + - base::GlobalDescriptors::kBaseDescriptor; -} - -} // namespace service_manager diff --git a/chromium/services/service_manager/zygote/common/common_sandbox_support_linux.h b/chromium/services/service_manager/zygote/common/common_sandbox_support_linux.h deleted file mode 100644 index 051d8ba0318..00000000000 --- a/chromium/services/service_manager/zygote/common/common_sandbox_support_linux.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_COMMON_SANDBOX_SUPPORT_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_COMMON_SANDBOX_SUPPORT_LINUX_H_ - -#include <stddef.h> - -#include "base/component_export.h" -#include "build/build_config.h" - -class NaClListener; - -namespace service_manager { - -#if !defined(OS_NACL_NONSFI) -// TODO(crbug.com/982879): Remove this when NaCl is unshipped. -class COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) SharedMemoryIPCSupport { - private: - friend class ::NaClListener; - - // Returns a file descriptor for a shared memory segment. The - // executable flag indicates that the caller intends to use mprotect - // with PROT_EXEC after making a mapping, but not that it intends to - // mmap with PROT_EXEC in the first place. (Some systems, such as - // ChromeOS, disallow PROT_EXEC in mmap on /dev/shm files but do allow - // PROT_EXEC in mprotect on mappings from such files. This function - // can yield an object that has that constraint.) - static int MakeSharedMemorySegment(size_t length, bool executable); - - SharedMemoryIPCSupport() = delete; -}; -#endif - -// Gets the well-known file descriptor on which we expect to find the -// sandbox IPC channel. -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) int GetSandboxFD(); - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_COMMON_SANDBOX_SUPPORT_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/common/send_zygote_child_ping_linux.cc b/chromium/services/service_manager/zygote/common/send_zygote_child_ping_linux.cc deleted file mode 100644 index 1245398f52c..00000000000 --- a/chromium/services/service_manager/zygote/common/send_zygote_child_ping_linux.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/common/send_zygote_child_ping_linux.h" - -#include <vector> - -#include "base/posix/unix_domain_socket.h" -#include "services/service_manager/zygote/common/zygote_commands_linux.h" - -namespace service_manager { - -bool SendZygoteChildPing(int fd) { - return base::UnixDomainSocket::SendMsg(fd, kZygoteChildPingMessage, - sizeof(kZygoteChildPingMessage), - std::vector<int>()); -} - -} // namespace service_manager diff --git a/chromium/services/service_manager/zygote/common/send_zygote_child_ping_linux.h b/chromium/services/service_manager/zygote/common/send_zygote_child_ping_linux.h deleted file mode 100644 index 66aff241a95..00000000000 --- a/chromium/services/service_manager/zygote/common/send_zygote_child_ping_linux.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_SEND_ZYGOTE_CHILD_PING_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_SEND_ZYGOTE_CHILD_PING_LINUX_H_ - -#include "base/component_export.h" - -namespace service_manager { - -// Sends a zygote child "ping" message to browser process via socket |fd|. -// Returns true on success. -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) bool SendZygoteChildPing(int fd); - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_SEND_ZYGOTE_CHILD_PING_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/common/zygote_commands_linux.h b/chromium/services/service_manager/zygote/common/zygote_commands_linux.h deleted file mode 100644 index b1d7c718a8d..00000000000 --- a/chromium/services/service_manager/zygote/common/zygote_commands_linux.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_COMMANDS_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_COMMANDS_LINUX_H_ - -#include <stddef.h> - -#include "base/posix/global_descriptors.h" - -namespace service_manager { - -// Contents of the initial message sent from the zygote to the browser right -// after it starts. -static const char kZygoteBootMessage[] = "ZYGOTE_BOOT"; - -// Contents of the initial message sent from the zygote to the browser when it -// is ready to go. -static const char kZygoteHelloMessage[] = "ZYGOTE_OK"; - -// Message sent by zygote children to the browser so the browser can discover -// the sending child's process ID. -static const char kZygoteChildPingMessage[] = "CHILD_PING"; - -// Maximum allowable length for messages sent to the zygote. -const size_t kZygoteMaxMessageLength = 12288; - -// File descriptors initialized by the Zygote Host -const int kZygoteSocketPairFd = base::GlobalDescriptors::kBaseDescriptor; - -// These are the command codes used on the wire between the browser and the -// zygote. -enum { - // Fork off a new renderer. - kZygoteCommandFork = 0, - - // Reap a renderer child. - kZygoteCommandReap = 1, - - // Check what happened to a child process. - kZygoteCommandGetTerminationStatus = 2, - - // Read a bitmask of kSandboxLinux* - kZygoteCommandGetSandboxStatus = 3, - - // Not a real zygote command, but a subcommand used during the zygote fork - // protocol. Sends the child's PID as seen from the browser process. - kZygoteCommandForkRealPID = 4 -}; - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_COMMANDS_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/common/zygote_features.gni b/chromium/services/service_manager/zygote/common/zygote_features.gni deleted file mode 100644 index c7580b35ff3..00000000000 --- a/chromium/services/service_manager/zygote/common/zygote_features.gni +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -use_zygote_handle = is_posix && !is_android && !is_mac diff --git a/chromium/services/service_manager/zygote/common/zygote_fork_delegate_linux.h b/chromium/services/service_manager/zygote/common/zygote_fork_delegate_linux.h deleted file mode 100644 index aec457b8750..00000000000 --- a/chromium/services/service_manager/zygote/common/zygote_fork_delegate_linux.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_FORK_DELEGATE_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_FORK_DELEGATE_LINUX_H_ - -#include <unistd.h> - -#include <string> -#include <vector> - -// TODO(jln) base::TerminationStatus should be forward declared when switching -// to C++11. -#include "base/process/kill.h" - -namespace service_manager { - -// The ZygoteForkDelegate allows the Chrome Linux zygote to delegate -// fork operations to another class that knows how to do some -// specialized version of fork. -class ZygoteForkDelegate { - public: - // A ZygoteForkDelegate is created during Chrome linux zygote - // initialization, and provides "fork()" functionality as an - // alternative to forking the zygote. A new delegate is passed in - // as an argument to ZygoteMain(). - virtual ~ZygoteForkDelegate() {} - - // Initialization happens in the zygote after it has been - // started by ZygoteMain. - // If |enable_layer1_sandbox| is true, the delegate must enable a - // layer-1 sandbox such as the setuid sandbox. - virtual void Init(int sandboxdesc, bool enable_layer1_sandbox) = 0; - - // After Init, supply a UMA_HISTOGRAM_ENUMERATION the delegate would like - // reported to the browser process. (Note: Because these reports are - // piggy-backed onto fork responses that don't otherwise contain UMA reports, - // this method may not be called until much later.) - virtual void InitialUMA(std::string* uma_name, - int* uma_sample, - int* uma_boundary_value) = 0; - - // Returns 'true' if the delegate would like to handle a given fork - // request. Otherwise returns false. Optionally, fills in uma_name et al - // with a report the helper wants to make via UMA_HISTOGRAM_ENUMERATION. - virtual bool CanHelp(const std::string& process_type, - std::string* uma_name, - int* uma_sample, - int* uma_boundary_value) = 0; - - // Indexes of FDs in the vector passed to Fork(). - enum { - // Used to pass in the descriptor for talking to the Browser. - // Because the children use ChannelMojo, this is actually the Mojo fd. - kBrowserFDIndex, - // The PID oracle is used in the protocol for discovering the - // child process's real PID from within the SUID sandbox. - // The child process is required to write to the socket after - // successfully forking. - kPIDOracleFDIndex, - kNumPassedFDs // Number of FDs in the vector passed to Fork(). - }; - - // Delegate forks, returning a -1 on failure. Outside the - // suid sandbox, Fork() returns the Linux process ID. - // This method is not aware of any potential pid namespaces, so it'll - // return a raw pid just like fork() would. - // Delegate is responsible for communicating the channel ID to the - // newly created child process. - virtual pid_t Fork(const std::string& process_type, - const std::vector<int>& fds, - const std::string& channel_id) = 0; - - // The fork delegate must also assume the role of waiting for its children - // since the caller will not be their parents and cannot do it. |pid| here - // should be a pid that has been returned by the Fork() method. i.e. This - // method is completely unaware of eventual PID namespaces due to sandboxing. - // |known_dead| indicates that the process is already dead and that a - // blocking wait() should be performed. In this case, GetTerminationStatus() - // will send a SIGKILL to the target process first. - virtual bool GetTerminationStatus(pid_t pid, - bool known_dead, - base::TerminationStatus* status, - int* exit_code) = 0; -}; - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_FORK_DELEGATE_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/common/zygote_handle.h b/chromium/services/service_manager/zygote/common/zygote_handle.h deleted file mode 100644 index 07efadf6807..00000000000 --- a/chromium/services/service_manager/zygote/common/zygote_handle.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_HANDLE_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_HANDLE_H_ - -#include "base/callback.h" -#include "base/command_line.h" -#include "base/component_export.h" -#include "base/files/scoped_file.h" -#include "build/build_config.h" -#include "services/service_manager/zygote/common/zygote_buildflags.h" - -#if !BUILDFLAG(USE_ZYGOTE_HANDLE) -#error "Can not use zygote handles without USE_ZYGOTE_HANDLE" -#endif - -namespace service_manager { - -#if defined(OS_POSIX) -class ZygoteCommunication; -using ZygoteHandle = ZygoteCommunication*; -#else -// Perhaps other ports may USE_ZYGOTE_HANDLE here somdeday. -#error "Can not use zygote handles on this platform" -#endif // defined(OS_POSIX) - -using ZygoteLaunchCallback = - base::OnceCallback<pid_t(base::CommandLine*, base::ScopedFD*)>; - -// Allocates and initializes the global generic zygote process, and returns the -// ZygoteHandle used to communicate with it. |launch_cb| is a callback that -// should actually launch the process, after adding additional command line -// switches to the ones composed by this function. It returns the pid created, -// and provides a control fd for it. -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) -ZygoteHandle CreateGenericZygote(ZygoteLaunchCallback launch_cb); -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) ZygoteHandle GetGenericZygote(); - -// Similar to the above but for creating an unsandboxed zygote from which -// processes which need non-generic sandboxes can be derived. -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) -ZygoteHandle CreateUnsandboxedZygote(ZygoteLaunchCallback launch_cb); -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) ZygoteHandle GetUnsandboxedZygote(); - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_COMMON_ZYGOTE_HANDLE_H_ diff --git a/chromium/services/service_manager/zygote/host/zygote_communication_linux.cc b/chromium/services/service_manager/zygote/host/zygote_communication_linux.cc deleted file mode 100644 index a3a1fc73bea..00000000000 --- a/chromium/services/service_manager/zygote/host/zygote_communication_linux.cc +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/host/zygote_communication_linux.h" - -#include <string.h> -#include <sys/socket.h> - -#include "base/base_switches.h" -#include "base/command_line.h" -#include "base/i18n/unicodestring.h" -#include "base/logging.h" -#include "base/metrics/histogram_functions.h" -#include "base/path_service.h" -#include "base/pickle.h" -#include "base/posix/eintr_wrapper.h" -#include "base/posix/unix_domain_socket.h" -#include "base/stl_util.h" -#include "services/service_manager/embedder/result_codes.h" -#include "services/service_manager/embedder/switches.h" -#include "services/service_manager/sandbox/switches.h" -#include "services/service_manager/zygote/common/zygote_commands_linux.h" -#include "third_party/icu/source/i18n/unicode/timezone.h" - -namespace service_manager { - -ZygoteCommunication::ZygoteCommunication(ZygoteType type) - : type_(type), - pid_(), - sandbox_status_(0), - have_read_sandbox_status_word_(false), - init_(false) {} - -ZygoteCommunication::~ZygoteCommunication() {} - -bool ZygoteCommunication::SendMessage(const base::Pickle& data, - const std::vector<int>* fds) { - DCHECK(control_fd_.is_valid()); - CHECK(data.size() <= kZygoteMaxMessageLength) - << "Trying to send too-large message to zygote (sending " << data.size() - << " bytes, max is " << kZygoteMaxMessageLength << ")"; - CHECK(!fds || fds->size() <= base::UnixDomainSocket::kMaxFileDescriptors) - << "Trying to send message with too many file descriptors to zygote " - << "(sending " << fds->size() << ", max is " - << base::UnixDomainSocket::kMaxFileDescriptors << ")"; - - return base::UnixDomainSocket::SendMsg(control_fd_.get(), data.data(), - data.size(), - fds ? *fds : std::vector<int>()); -} - -ssize_t ZygoteCommunication::ReadSandboxStatus() { - DCHECK(control_fd_.is_valid()); - // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, - // but don't wait for the reply. Thus, the first time that we read from the - // zygote, we get the reply to that request. - ssize_t bytes_read = HANDLE_EINTR( - read(control_fd_.get(), &sandbox_status_, sizeof(sandbox_status_))); - if (bytes_read != sizeof(sandbox_status_)) { - return -1; - } - return bytes_read; -} - -ssize_t ZygoteCommunication::ReadReply(void* buf, size_t buf_len) { - DCHECK(control_fd_.is_valid()); - if (!have_read_sandbox_status_word_) { - if (ReadSandboxStatus() == -1) { - return -1; - } - have_read_sandbox_status_word_ = true; - base::UmaHistogramSparse("Linux.SandboxStatus", sandbox_status_); - } - - return HANDLE_EINTR(read(control_fd_.get(), buf, buf_len)); -} - -pid_t ZygoteCommunication::ForkRequest( - const std::vector<std::string>& argv, - const base::FileHandleMappingVector& mapping, - const std::string& process_type) { - DCHECK(init_); - - base::Pickle pickle; - int raw_socks[2]; - PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks)); - base::ScopedFD my_sock(raw_socks[0]); - base::ScopedFD peer_sock(raw_socks[1]); - CHECK(base::UnixDomainSocket::EnableReceiveProcessId(my_sock.get())); - - pickle.WriteInt(kZygoteCommandFork); - pickle.WriteString(process_type); - pickle.WriteInt(argv.size()); - for (std::vector<std::string>::const_iterator i = argv.begin(); - i != argv.end(); ++i) - pickle.WriteString(*i); - std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createDefault()); - icu::UnicodeString timezone_id; - pickle.WriteString16( - base::i18n::UnicodeStringToString16(timezone->getID(timezone_id))); - - // Fork requests contain one file descriptor for the PID oracle, and one - // more for each file descriptor mapping for the child process. - const size_t num_fds_to_send = 1 + mapping.size(); - pickle.WriteInt(num_fds_to_send); - - std::vector<int> fds; - - // First FD to send is peer_sock. - // TODO(morrita): Ideally, this should be part of the mapping so that - // PosixFileDescriptorInfo can manages its lifetime. - fds.push_back(peer_sock.get()); - - // The rest come from mapping. - for (const auto& item : mapping) { - fds.push_back(item.first); - pickle.WriteUInt32(item.second); - } - - // Sanity check that we've populated |fds| correctly. - DCHECK_EQ(num_fds_to_send, fds.size()); - - pid_t pid; - { - base::AutoLock lock(control_lock_); - if (!SendMessage(pickle, &fds)) - return base::kNullProcessHandle; - peer_sock.reset(); - - { - char buf[sizeof(kZygoteChildPingMessage) + 1]; - std::vector<base::ScopedFD> recv_fds; - base::ProcessId real_pid; - - ssize_t n = base::UnixDomainSocket::RecvMsgWithPid( - my_sock.get(), buf, sizeof(buf), &recv_fds, &real_pid); - if (n != sizeof(kZygoteChildPingMessage) || - 0 != memcmp(buf, kZygoteChildPingMessage, - sizeof(kZygoteChildPingMessage))) { - // Zygote children should still be trustworthy when they're supposed to - // ping us, so something's broken if we don't receive a valid ping. - LOG(ERROR) << "Did not receive ping from zygote child"; - NOTREACHED(); - real_pid = -1; - } - my_sock.reset(); - - // Always send PID back to zygote. - base::Pickle pid_pickle; - pid_pickle.WriteInt(kZygoteCommandForkRealPID); - pid_pickle.WriteInt(real_pid); - if (!SendMessage(pid_pickle, nullptr)) - return base::kNullProcessHandle; - } - - // Read the reply, which pickles the PID and an optional UMA enumeration. - static const unsigned kMaxReplyLength = 2048; - char buf[kMaxReplyLength]; - const ssize_t len = ReadReply(buf, sizeof(buf)); - - base::Pickle reply_pickle(buf, len); - base::PickleIterator iter(reply_pickle); - if (len <= 0 || !iter.ReadInt(&pid)) - return base::kNullProcessHandle; - - // If there is a nonempty UMA name string, then there is a UMA - // enumeration to record. - std::string uma_name; - int uma_sample; - int uma_boundary_value; - if (iter.ReadString(&uma_name) && !uma_name.empty() && - iter.ReadInt(&uma_sample) && iter.ReadInt(&uma_boundary_value)) { - // We cannot use the UMA_HISTOGRAM_ENUMERATION macro here, - // because that's only for when the name is the same every time. - // Here we're using whatever name we got from the other side. - // But since it's likely that the same one will be used repeatedly - // (even though it's not guaranteed), we cache it here. - static base::HistogramBase* uma_histogram; - if (!uma_histogram || uma_histogram->histogram_name() != uma_name) { - uma_histogram = base::LinearHistogram::FactoryGet( - uma_name, 1, uma_boundary_value, uma_boundary_value + 1, - base::HistogramBase::kUmaTargetedHistogramFlag); - } - uma_histogram->Add(uma_sample); - } - - if (pid <= 0) - return base::kNullProcessHandle; - } - - ZygoteChildBorn(pid); - return pid; -} - -void ZygoteCommunication::EnsureProcessTerminated(pid_t process) { - DCHECK(init_); - base::Pickle pickle; - - pickle.WriteInt(kZygoteCommandReap); - pickle.WriteInt(process); - if (!SendMessage(pickle, nullptr)) - LOG(ERROR) << "Failed to send Reap message to zygote"; - ZygoteChildDied(process); -} - -void ZygoteCommunication::ZygoteChildBorn(pid_t process) { - base::AutoLock lock(child_tracking_lock_); - bool new_element_inserted = - list_of_running_zygote_children_.insert(process).second; - DCHECK(new_element_inserted); -} - -void ZygoteCommunication::ZygoteChildDied(pid_t process) { - base::AutoLock lock(child_tracking_lock_); - size_t num_erased = list_of_running_zygote_children_.erase(process); - DCHECK_EQ(1U, num_erased); -} - -void ZygoteCommunication::Init( - base::OnceCallback<pid_t(base::CommandLine*, base::ScopedFD*)> launcher) { - CHECK(!init_); - - base::FilePath chrome_path; - CHECK(base::PathService::Get(base::FILE_EXE, &chrome_path)); - - base::CommandLine cmd_line(chrome_path); - cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess); - - if (type_ == ZygoteType::kUnsandboxed) - cmd_line.AppendSwitch(switches::kNoZygoteSandbox); - - const base::CommandLine& browser_command_line = - *base::CommandLine::ForCurrentProcess(); - if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) { - cmd_line.PrependWrapper( - browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix)); - } - // Append any switches from the service manager that need to be forwarded on - // to the zygote/renderers. - static const char* const kForwardSwitches[] = { - service_manager::switches::kAllowSandboxDebugging, - service_manager::switches::kDisableInProcessStackTraces, - service_manager::switches::kDisableSeccompFilterSandbox, - service_manager::switches::kNoSandbox, - }; - cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches, - base::size(kForwardSwitches)); - - pid_ = std::move(launcher).Run(&cmd_line, &control_fd_); - - base::Pickle pickle; - pickle.WriteInt(kZygoteCommandGetSandboxStatus); - if (!SendMessage(pickle, nullptr)) - LOG(FATAL) << "Cannot communicate with zygote"; - - init_ = true; -} - -base::TerminationStatus ZygoteCommunication::GetTerminationStatus( - base::ProcessHandle handle, - bool known_dead, - int* exit_code) { - DCHECK(init_); - base::Pickle pickle; - pickle.WriteInt(kZygoteCommandGetTerminationStatus); - pickle.WriteBool(known_dead); - pickle.WriteInt(handle); - - static const unsigned kMaxMessageLength = 128; - char buf[kMaxMessageLength]; - ssize_t len; - { - base::AutoLock lock(control_lock_); - if (!SendMessage(pickle, nullptr)) - LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; - len = ReadReply(buf, sizeof(buf)); - } - - // Set this now to handle the error cases. - if (exit_code) - *exit_code = RESULT_CODE_NORMAL_EXIT; - int status = base::TERMINATION_STATUS_NORMAL_TERMINATION; - - if (len == -1) { - PLOG(WARNING) << "Error reading message from zygote"; - } else if (len == 0) { - LOG(WARNING) << "Socket closed prematurely."; - } else { - base::Pickle read_pickle(buf, len); - int tmp_status, tmp_exit_code; - base::PickleIterator iter(read_pickle); - if (!iter.ReadInt(&tmp_status) || !iter.ReadInt(&tmp_exit_code)) { - LOG(WARNING) - << "Error parsing GetTerminationStatus response from zygote."; - } else { - if (exit_code) - *exit_code = tmp_exit_code; - status = tmp_status; - } - } - - if (status != base::TERMINATION_STATUS_STILL_RUNNING) { - ZygoteChildDied(handle); - } - return static_cast<base::TerminationStatus>(status); -} - -int ZygoteCommunication::GetSandboxStatus() { - if (have_read_sandbox_status_word_) { - return sandbox_status_; - } - if (ReadSandboxStatus() == -1) { - return 0; - } - have_read_sandbox_status_word_ = true; - base::UmaHistogramSparse("Linux.SandboxStatus", sandbox_status_); - return sandbox_status_; -} - -} // namespace service_manager diff --git a/chromium/services/service_manager/zygote/host/zygote_communication_linux.h b/chromium/services/service_manager/zygote/host/zygote_communication_linux.h deleted file mode 100644 index 77878c78bbf..00000000000 --- a/chromium/services/service_manager/zygote/host/zygote_communication_linux.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_HOST_ZYGOTE_COMMUNICATION_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_HOST_ZYGOTE_COMMUNICATION_LINUX_H_ - -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include <sys/types.h> - -#include "base/callback.h" -#include "base/component_export.h" -#include "base/files/scoped_file.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "base/process/process_handle.h" -#include "base/synchronization/lock.h" - -namespace base { -class Pickle; -} // namespace base - -namespace service_manager { - -// Handles interprocess communication with the Linux zygote process. The zygote -// does not use standard Chrome IPC or mojo, see: -// https://chromium.googlesource.com/chromium/src/+/master/docs/linux/sandbox_ipc.md -class COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) ZygoteCommunication { - public: - enum class ZygoteType { kSandboxed, kUnsandboxed }; - explicit ZygoteCommunication(ZygoteType type); - ~ZygoteCommunication(); - - void Init( - base::OnceCallback<pid_t(base::CommandLine*, base::ScopedFD*)> launcher); - - // Tries to start a process of type indicated by process_type. - // Returns its pid on success, otherwise base::kNullProcessHandle; - pid_t ForkRequest(const std::vector<std::string>& command_line, - const base::FileHandleMappingVector& mapping, - const std::string& process_type); - - void EnsureProcessTerminated(pid_t process); - - // Should be called every time a Zygote child died. - void ZygoteChildDied(pid_t process); - - // Get the termination status (and, optionally, the exit code) of - // the process. |exit_code| is set to the exit code of the child - // process. (|exit_code| may be NULL.) - // Unfortunately the Zygote can not accurately figure out if a process - // is already dead without waiting synchronously for it. - // |known_dead| should be set to true when we already know that the process - // is dead. When |known_dead| is false, processes could be seen as - // still running, even when they're not. When |known_dead| is true, the - // process will be SIGKILL-ed first (which should have no effect if it was - // really dead). This is to prevent a waiting waitpid() from blocking in - // a single-threaded Zygote. See https://crbug.com/157458. - base::TerminationStatus GetTerminationStatus(base::ProcessHandle handle, - bool known_dead, - int* exit_code); - - // Returns the sandbox status of this zygote. - int GetSandboxStatus(); - - private: - // Should be called every time a Zygote child is born. - void ZygoteChildBorn(pid_t process); - - // Read the reply from the zygote. - ssize_t ReadReply(void* buf, size_t buf_len); - - // Sends |data| to the zygote via |control_fd_|. If |fds| is non-NULL, the - // included file descriptors will also be passed. The caller is responsible - // for acquiring |control_lock_|. - bool SendMessage(const base::Pickle& data, const std::vector<int>* fds); - - // Get the sandbox status from the zygote. - ssize_t ReadSandboxStatus(); - - // Indicates whether the Zygote starts unsandboxed or not. - const ZygoteType type_; - - base::ScopedFD control_fd_; // the socket to the zygote. - // A lock protecting all communication with the zygote. This lock must be - // acquired before sending a command and released after the result has been - // received. - base::Lock control_lock_; - // The pid of the zygote. - pid_t pid_; - // The list of running zygote children. - std::set<pid_t> list_of_running_zygote_children_; - // The lock to guard the list of running zygote children. - base::Lock child_tracking_lock_; - int sandbox_status_; - bool have_read_sandbox_status_word_; - // Set to true when the zygote is initialized successfully. - bool init_; -}; - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_HOST_ZYGOTE_COMMUNICATION_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/host/zygote_handle_linux.cc b/chromium/services/service_manager/zygote/host/zygote_handle_linux.cc deleted file mode 100644 index 30f135244be..00000000000 --- a/chromium/services/service_manager/zygote/host/zygote_handle_linux.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/common/zygote_handle.h" - -#include "services/service_manager/zygote/host/zygote_communication_linux.h" - -namespace service_manager { -namespace { - -// Intentionally leaked. -ZygoteHandle g_generic_zygote = nullptr; -ZygoteHandle g_unsandboxed_zygote = nullptr; - -} // namespace - -ZygoteHandle CreateGenericZygote(ZygoteLaunchCallback launch_cb) { - CHECK(!g_generic_zygote); - g_generic_zygote = - new ZygoteCommunication(ZygoteCommunication::ZygoteType::kSandboxed); - g_generic_zygote->Init(std::move(launch_cb)); - return g_generic_zygote; -} - -ZygoteHandle GetGenericZygote() { - CHECK(g_generic_zygote); - return g_generic_zygote; -} - -ZygoteHandle CreateUnsandboxedZygote(ZygoteLaunchCallback launch_cb) { - CHECK(!g_unsandboxed_zygote); - g_unsandboxed_zygote = - new ZygoteCommunication(ZygoteCommunication::ZygoteType::kUnsandboxed); - g_unsandboxed_zygote->Init(std::move(launch_cb)); - return g_unsandboxed_zygote; -} - -ZygoteHandle GetUnsandboxedZygote() { - CHECK(g_unsandboxed_zygote); - return g_unsandboxed_zygote; -} - -} // namespace service_manager diff --git a/chromium/services/service_manager/zygote/host/zygote_host_impl_linux.cc b/chromium/services/service_manager/zygote/host/zygote_host_impl_linux.cc deleted file mode 100644 index 08ecc3c80c0..00000000000 --- a/chromium/services/service_manager/zygote/host/zygote_host_impl_linux.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/host/zygote_host_impl_linux.h" - -#include <stdlib.h> -#include <sys/socket.h> -#include <sys/types.h> - -#include "base/allocator/allocator_extension.h" -#include "base/files/file_enumerator.h" -#include "base/posix/unix_domain_socket.h" -#include "base/process/kill.h" -#include "base/process/memory.h" -#include "base/strings/string_number_conversions.h" -#include "build/build_config.h" -#include "sandbox/linux/services/credentials.h" -#include "sandbox/linux/services/namespace_sandbox.h" -#include "sandbox/linux/suid/client/setuid_sandbox_host.h" -#include "sandbox/linux/suid/common/sandbox.h" -#include "services/service_manager/sandbox/linux/sandbox_linux.h" -#include "services/service_manager/sandbox/switches.h" -#include "services/service_manager/zygote/common/zygote_commands_linux.h" - -namespace service_manager { - -namespace { - -// Receive a fixed message on fd and return the sender's PID. -// Returns true if the message received matches the expected message. -bool ReceiveFixedMessage(int fd, - const char* expect_msg, - size_t expect_len, - base::ProcessId* sender_pid) { - // Allocate an extra byte of buffer space so we can check that we received - // exactly |expect_len| bytes, and the message wasn't just truncated to fit. - char buf[expect_len + 1]; - std::vector<base::ScopedFD> fds_vec; - - const ssize_t len = base::UnixDomainSocket::RecvMsgWithPid( - fd, buf, sizeof(buf), &fds_vec, sender_pid); - if (static_cast<size_t>(len) != expect_len) - return false; - if (memcmp(buf, expect_msg, expect_len) != 0) - return false; - if (!fds_vec.empty()) - return false; - return true; -} - -} // namespace - -// static -ZygoteHost* ZygoteHost::GetInstance() { - return ZygoteHostImpl::GetInstance(); -} - -ZygoteHostImpl::ZygoteHostImpl() - : use_namespace_sandbox_(false), - use_suid_sandbox_(false), - use_suid_sandbox_for_adj_oom_score_(false), - sandbox_binary_(), - zygote_pids_lock_(), - zygote_pids_() {} - -ZygoteHostImpl::~ZygoteHostImpl() {} - -// static -ZygoteHostImpl* ZygoteHostImpl::GetInstance() { - return base::Singleton<ZygoteHostImpl>::get(); -} - -void ZygoteHostImpl::Init(const base::CommandLine& command_line) { - if (command_line.HasSwitch(service_manager::switches::kNoSandbox)) { - return; - } - - // Exit early if running as root without --no-sandbox. See - // https://crbug.com/638180. - // When running as root with the sandbox enabled, the browser process - // crashes on zygote initialization. Running as root with the sandbox - // is not supported, and if Chrome were able to display UI it would be showing - // an error message. With the zygote crashing it doesn't even get to that, - // so print an error message on the console. - uid_t uid = 0; - gid_t gid = 0; - if (!sandbox::Credentials::GetRESIds(&uid, &gid) || uid == 0) { - LOG(ERROR) << "Running as root without --" - << service_manager::switches::kNoSandbox - << " is not supported. See https://crbug.com/638180."; - exit(EXIT_FAILURE); - } - - { - std::unique_ptr<sandbox::SetuidSandboxHost> setuid_sandbox_host( - sandbox::SetuidSandboxHost::Create()); - sandbox_binary_ = setuid_sandbox_host->GetSandboxBinaryPath().value(); - } - - if (!command_line.HasSwitch( - service_manager::switches::kDisableNamespaceSandbox) && - sandbox::Credentials::CanCreateProcessInNewUserNS()) { - use_namespace_sandbox_ = true; - } else if (!command_line.HasSwitch( - service_manager::switches::kDisableSetuidSandbox) && - !sandbox_binary_.empty()) { - use_suid_sandbox_ = true; - - // Use the SUID sandbox for adjusting OOM scores when we are using - // the setuid sandbox. This is needed beacuse the processes are - // non-dumpable, so /proc/pid/oom_score_adj can only be written by - // root. - use_suid_sandbox_for_adj_oom_score_ = use_suid_sandbox_; - } else { - LOG(FATAL) - << "No usable sandbox! Update your kernel or see " - "https://chromium.googlesource.com/chromium/src/+/master/" - "docs/linux/suid_sandbox_development.md for more information on " - "developing with the SUID sandbox. " - "If you want to live dangerously and need an immediate workaround, " - "you can try using --" - << service_manager::switches::kNoSandbox << "."; - } -} - -void ZygoteHostImpl::AddZygotePid(pid_t pid) { - base::AutoLock lock(zygote_pids_lock_); - zygote_pids_.insert(pid); -} - -bool ZygoteHostImpl::IsZygotePid(pid_t pid) { - base::AutoLock lock(zygote_pids_lock_); - return zygote_pids_.find(pid) != zygote_pids_.end(); -} - -void ZygoteHostImpl::SetRendererSandboxStatus(int status) { - renderer_sandbox_status_ = status; -} - -int ZygoteHostImpl::GetRendererSandboxStatus() const { - return renderer_sandbox_status_; -} - -pid_t ZygoteHostImpl::LaunchZygote( - base::CommandLine* cmd_line, - base::ScopedFD* control_fd, - base::FileHandleMappingVector additional_remapped_fds) { - int fds[2]; - CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)); - CHECK(base::UnixDomainSocket::EnableReceiveProcessId(fds[0])); - - base::LaunchOptions options; - options.fds_to_remap = std::move(additional_remapped_fds); - options.fds_to_remap.emplace_back(fds[1], kZygoteSocketPairFd); - - const bool is_sandboxed_zygote = - !cmd_line->HasSwitch(service_manager::switches::kNoZygoteSandbox); - - base::ScopedFD dummy_fd; - if (is_sandboxed_zygote && use_suid_sandbox_) { - std::unique_ptr<sandbox::SetuidSandboxHost> sandbox_host( - sandbox::SetuidSandboxHost::Create()); - sandbox_host->PrependWrapper(cmd_line); - sandbox_host->SetupLaunchOptions(&options, &dummy_fd); - sandbox_host->SetupLaunchEnvironment(); - } - - base::Process process = - (is_sandboxed_zygote && use_namespace_sandbox_) - ? sandbox::NamespaceSandbox::LaunchProcess(*cmd_line, options) - : base::LaunchProcess(*cmd_line, options); - CHECK(process.IsValid()) << "Failed to launch zygote process"; - - dummy_fd.reset(); - close(fds[1]); - control_fd->reset(fds[0]); - - pid_t pid = process.Pid(); - - if (is_sandboxed_zygote && (use_namespace_sandbox_ || use_suid_sandbox_)) { - // The namespace and SUID sandbox will execute the zygote in a new - // PID namespace, and the main zygote process will then fork from - // there. Watch now our elaborate dance to find and validate the - // zygote's PID. - - // First we receive a message from the zygote boot process. - base::ProcessId boot_pid; - CHECK(ReceiveFixedMessage(fds[0], kZygoteBootMessage, - sizeof(kZygoteBootMessage), &boot_pid)); - - // Within the PID namespace, the zygote boot process thinks it's PID 1, - // but its real PID can never be 1. This gives us a reliable test that - // the kernel is translating the sender's PID to our namespace. - CHECK_GT(boot_pid, 1) - << "Received invalid process ID for zygote; kernel might be too old? " - "See crbug.com/357670 or try using --" - << service_manager::switches::kNoSandbox << " to workaround."; - - // Now receive the message that the zygote's ready to go, along with the - // main zygote process's ID. - pid_t real_pid; - CHECK(ReceiveFixedMessage(fds[0], kZygoteHelloMessage, - sizeof(kZygoteHelloMessage), &real_pid)); - CHECK_GT(real_pid, 1); - - if (real_pid != pid) { - // Reap the sandbox. - base::EnsureProcessGetsReaped(std::move(process)); - } - pid = real_pid; - } - - AddZygotePid(pid); - return pid; -} - -#if !defined(OS_OPENBSD) -void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, - int score) { - // 1) You can't change the oom_score_adj of a non-dumpable process - // (EPERM) unless you're root. Because of this, we can't set the - // oom_adj from the browser process. - // - // 2) We can't set the oom_score_adj before entering the sandbox - // because the zygote is in the sandbox and the zygote is as - // critical as the browser process. Its oom_adj value shouldn't - // be changed. - // - // 3) A non-dumpable process can't even change its own oom_score_adj - // because it's root owned 0644. The sandboxed processes don't - // even have /proc, but one could imagine passing in a descriptor - // from outside. - // - // So, in the normal case, we use the SUID binary to change it for us. - // However, Fedora (and other SELinux systems) don't like us touching other - // process's oom_score_adj (or oom_adj) values - // (https://bugzilla.redhat.com/show_bug.cgi?id=581256). - // - // The offical way to get the SELinux mode is selinux_getenforcemode, but I - // don't want to add another library to the build as it's sure to cause - // problems with other, non-SELinux distros. - // - // So we just check for files in /selinux. This isn't foolproof, but it's not - // bad and it's easy. - - static bool selinux; - static bool selinux_valid = false; - - if (!selinux_valid) { - const base::FilePath kSelinuxPath("/selinux"); - base::FileEnumerator en(kSelinuxPath, false, base::FileEnumerator::FILES); - bool has_selinux_files = !en.Next().empty(); - - selinux = - has_selinux_files && access(kSelinuxPath.value().c_str(), X_OK) == 0; - selinux_valid = true; - } - - if (!use_suid_sandbox_for_adj_oom_score_) { - if (!base::AdjustOOMScore(pid, score)) - PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid; - return; - } - - if (selinux) - return; - - // If heap profiling is running, these processes are not exiting, at least - // on ChromeOS. The easiest thing to do is not launch them when profiling. - // TODO(stevenjb): Investigate further and fix. - if (base::allocator::IsHeapProfilerRunning()) - return; - - std::vector<std::string> adj_oom_score_cmdline; - adj_oom_score_cmdline.push_back(sandbox_binary_); - adj_oom_score_cmdline.push_back(sandbox::kAdjustOOMScoreSwitch); - adj_oom_score_cmdline.push_back(base::NumberToString(pid)); - adj_oom_score_cmdline.push_back(base::NumberToString(score)); - - // sandbox_helper_process is a setuid binary. - base::LaunchOptions options; - options.allow_new_privs = true; - - base::Process sandbox_helper_process = - base::LaunchProcess(adj_oom_score_cmdline, options); - if (sandbox_helper_process.IsValid()) - base::EnsureProcessGetsReaped(std::move(sandbox_helper_process)); -} -#endif - -} // namespace service_manager diff --git a/chromium/services/service_manager/zygote/host/zygote_host_impl_linux.h b/chromium/services/service_manager/zygote/host/zygote_host_impl_linux.h deleted file mode 100644 index 64d6c45680d..00000000000 --- a/chromium/services/service_manager/zygote/host/zygote_host_impl_linux.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_HOST_ZYGOTE_HOST_IMPL_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_HOST_ZYGOTE_HOST_IMPL_LINUX_H_ - -#include <sys/types.h> - -#include <set> -#include <string> - -#include "base/command_line.h" -#include "base/component_export.h" -#include "base/files/scoped_file.h" -#include "base/process/launch.h" -#include "base/process/process_handle.h" -#include "base/synchronization/lock.h" - -#include "services/service_manager/zygote/zygote_host_linux.h" - -namespace base { -template <typename Type> -struct DefaultSingletonTraits; -} // namespace base - -namespace service_manager { - -class COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) ZygoteHostImpl - : public ZygoteHost { - public: - // Returns the singleton instance. - static ZygoteHostImpl* GetInstance(); - - void Init(const base::CommandLine& cmd_line); - - // Returns whether or not this pid is the pid of a zygote. - bool IsZygotePid(pid_t pid) override; - - void SetRendererSandboxStatus(int status); - int GetRendererSandboxStatus() const override; - - pid_t LaunchZygote(base::CommandLine* cmd_line, - base::ScopedFD* control_fd, - base::FileHandleMappingVector additional_remapped_fds); - - void AdjustRendererOOMScore(base::ProcessHandle process_handle, - int score) override; - bool HasZygote() { return !zygote_pids_.empty(); } - - private: - friend struct base::DefaultSingletonTraits<ZygoteHostImpl>; - - ZygoteHostImpl(); - ~ZygoteHostImpl() override; - - // Tells the ZygoteHost the PIDs of all the zygotes. - void AddZygotePid(pid_t pid); - - int renderer_sandbox_status_; - - bool use_namespace_sandbox_; - bool use_suid_sandbox_; - bool use_suid_sandbox_for_adj_oom_score_; - std::string sandbox_binary_; - - // This lock protects the |zygote_pids_| set. - base::Lock zygote_pids_lock_; - // This is a set of PIDs representing all the running zygotes. - std::set<pid_t> zygote_pids_; -}; - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_HOST_ZYGOTE_HOST_IMPL_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/zygote_host_linux.h b/chromium/services/service_manager/zygote/zygote_host_linux.h deleted file mode 100644 index 8e6416debe6..00000000000 --- a/chromium/services/service_manager/zygote/zygote_host_linux.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_HOST_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_HOST_LINUX_H_ - -#include <unistd.h> - -#include "base/component_export.h" -#include "base/process/process.h" - -namespace service_manager { - -// https://chromium.googlesource.com/chromium/src/+/master/docs/linux/zygote.md - -// The zygote host is an interface, in the browser process, to the zygote -// process. -class ZygoteHost { - public: - // Returns the singleton instance. - static COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) ZygoteHost* GetInstance(); - - virtual ~ZygoteHost() {} - - // Returns the pid of the Zygote process. - virtual bool IsZygotePid(pid_t pid) = 0; - - // Returns an int which is a bitmask of kSandboxLinux* values. Only valid - // after the first render has been forked. - virtual int GetRendererSandboxStatus() const = 0; - - // Adjust the OOM score of the given renderer's PID. The allowed - // range for the score is [0, 1000], where higher values are more - // likely to be killed by the OOM killer. - virtual void AdjustRendererOOMScore(base::ProcessHandle process_handle, - int score) = 0; -}; - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_HOST_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/zygote_linux.cc b/chromium/services/service_manager/zygote/zygote_linux.cc deleted file mode 100644 index aa601ab28d7..00000000000 --- a/chromium/services/service_manager/zygote/zygote_linux.cc +++ /dev/null @@ -1,659 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/zygote_linux.h" - -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <signal.h> -#include <stdint.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include <utility> - -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/linux_util.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/pickle.h" -#include "base/posix/eintr_wrapper.h" -#include "base/posix/global_descriptors.h" -#include "base/posix/unix_domain_socket.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "base/process/process.h" -#include "base/process/process_handle.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "ipc/ipc_channel.h" -#include "sandbox/linux/services/credentials.h" -#include "sandbox/linux/services/namespace_sandbox.h" -#include "services/service_manager/embedder/descriptors.h" -#include "services/service_manager/embedder/result_codes.h" -#include "services/service_manager/embedder/set_process_title.h" -#include "services/service_manager/embedder/switches.h" -#include "services/service_manager/sandbox/linux/sandbox_linux.h" -#include "services/service_manager/sandbox/sandbox.h" -#include "services/service_manager/zygote/common/send_zygote_child_ping_linux.h" -#include "services/service_manager/zygote/common/zygote_commands_linux.h" -#include "services/service_manager/zygote/common/zygote_fork_delegate_linux.h" -#include "third_party/icu/source/i18n/unicode/timezone.h" - -// See -// https://chromium.googlesource.com/chromium/src/+/master/docs/linux/zygote.md - -namespace service_manager { - -namespace { - -// NOP function. See below where this handler is installed. -void SIGCHLDHandler(int signal) {} - -int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) { - for (size_t index = 0; index < fd_mapping.size(); ++index) { - if (fd_mapping[index].key == key) - return fd_mapping[index].fd; - } - return -1; -} - -void KillAndReap(pid_t pid, ZygoteForkDelegate* helper) { - if (helper) { - // Helper children may be forked in another PID namespace, so |pid| might - // be meaningless to us; or we just might not be able to directly send it - // signals. So we can't kill it. - // Additionally, we're not its parent, so we can't reap it anyway. - // TODO(mdempsky): Extend the ZygoteForkDelegate API to handle this. - LOG(WARNING) << "Unable to kill or reap helper children"; - return; - } - - // Kill the child process in case it's not already dead, so we can safely - // perform a blocking wait. - PCHECK(0 == kill(pid, SIGKILL)); - PCHECK(pid == HANDLE_EINTR(waitpid(pid, nullptr, 0))); -} - -} // namespace - -Zygote::Zygote(int sandbox_flags, - std::vector<std::unique_ptr<ZygoteForkDelegate>> helpers, - const base::GlobalDescriptors::Descriptor& ipc_backchannel) - : sandbox_flags_(sandbox_flags), - helpers_(std::move(helpers)), - initial_uma_index_(0), - to_reap_(), - ipc_backchannel_(ipc_backchannel) {} - -Zygote::~Zygote() {} - -bool Zygote::ProcessRequests() { - // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the - // browser on it. - // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. - // See - // https://chromium.googlesource.com/chromium/src/+/master/docs/linux/sandbox_ipc.md - - // We need to accept SIGCHLD, even though our handler is a no-op because - // otherwise we cannot wait on children. (According to POSIX 2001.) - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = &SIGCHLDHandler; - PCHECK(sigaction(SIGCHLD, &action, nullptr) == 0); - - // Block SIGCHLD until a child might be ready to reap. - sigset_t sigset; - sigset_t orig_sigmask; - PCHECK(sigemptyset(&sigset) == 0); - PCHECK(sigaddset(&sigset, SIGCHLD) == 0); - PCHECK(sigprocmask(SIG_BLOCK, &sigset, &orig_sigmask) == 0); - - if (UsingSUIDSandbox() || UsingNSSandbox()) { - // Let the ZygoteHost know we are ready to go. - // The receiving code is in - // content/browser/zygote_host/zygote_host_impl_linux.cc. - bool r = base::UnixDomainSocket::SendMsg( - kZygoteSocketPairFd, kZygoteHelloMessage, sizeof(kZygoteHelloMessage), - std::vector<int>()); -#if defined(OS_CHROMEOS) - LOG_IF(WARNING, !r) << "Sending zygote magic failed"; - // Exit normally on chromeos because session manager may send SIGTERM - // right after the process starts and it may fail to send zygote magic - // number to browser process. - if (!r) - _exit(service_manager::RESULT_CODE_NORMAL_EXIT); -#else - CHECK(r) << "Sending zygote magic failed"; -#endif - } - - sigset_t ppoll_sigmask = orig_sigmask; - PCHECK(sigdelset(&ppoll_sigmask, SIGCHLD) == 0); - struct pollfd pfd; - pfd.fd = kZygoteSocketPairFd; - pfd.events = POLLIN; - - struct timespec timeout; - timeout.tv_sec = 2; - timeout.tv_nsec = 0; - - for (;;) { - struct timespec* timeout_ptr = nullptr; - if (!to_reap_.empty()) - timeout_ptr = &timeout; - int rc = ppoll(&pfd, 1, timeout_ptr, &ppoll_sigmask); - PCHECK(rc >= 0 || errno == EINTR); - ReapChildren(); - - if (pfd.revents & POLLIN) { - // This function call can return multiple times, once per fork(). - if (HandleRequestFromBrowser(kZygoteSocketPairFd)) { - PCHECK(sigprocmask(SIG_SETMASK, &orig_sigmask, nullptr) == 0); - return true; - } - } - } - // The loop should not be exited unless a request was successfully processed. - NOTREACHED(); - return false; -} - -bool Zygote::ReapChild(const base::TimeTicks& now, ZygoteProcessInfo* child) { - pid_t pid = child->internal_pid; - pid_t r = HANDLE_EINTR(waitpid(pid, nullptr, WNOHANG)); - if (r > 0) { - if (r != pid) { - DLOG(ERROR) << "While waiting for " << pid - << " to terminate, " - "waitpid returned " - << r; - } - return r == pid; - } - if ((now - child->time_of_reap_request).InSeconds() < 2) { - return false; - } - // If the process has been requested reaped >= 2 seconds ago, kill it. - if (!child->sent_sigkill) { - if (kill(pid, SIGKILL) != 0) - DPLOG(ERROR) << "Sending SIGKILL to process " << pid << " failed"; - - child->sent_sigkill = true; - } - return false; -} - -void Zygote::ReapChildren() { - base::TimeTicks now = base::TimeTicks::Now(); - std::vector<ZygoteProcessInfo>::iterator it = to_reap_.begin(); - while (it != to_reap_.end()) { - if (ReapChild(now, &(*it))) { - it = to_reap_.erase(it); - } else { - it++; - } - } -} - -bool Zygote::GetProcessInfo(base::ProcessHandle pid, - ZygoteProcessInfo* process_info) { - DCHECK(process_info); - const ZygoteProcessMap::const_iterator it = process_info_map_.find(pid); - if (it == process_info_map_.end()) { - return false; - } - *process_info = it->second; - return true; -} - -bool Zygote::UsingSUIDSandbox() const { - return sandbox_flags_ & service_manager::SandboxLinux::kSUID; -} - -bool Zygote::UsingNSSandbox() const { - return sandbox_flags_ & service_manager::SandboxLinux::kUserNS; -} - -bool Zygote::HandleRequestFromBrowser(int fd) { - std::vector<base::ScopedFD> fds; - char buf[kZygoteMaxMessageLength]; - const ssize_t len = - base::UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); - - if (len == 0 || (len == -1 && errno == ECONNRESET)) { - // EOF from the browser. We should die. - // TODO(eugenis): call __sanititizer_cov_dump() here to obtain code - // coverage for the Zygote. Currently it's not possible because of - // confusion over who is responsible for closing the file descriptor. - _exit(0); - return false; - } - - if (len == -1) { - PLOG(ERROR) << "Error reading message from browser"; - return false; - } - - base::Pickle pickle(buf, len); - base::PickleIterator iter(pickle); - - int kind; - if (iter.ReadInt(&kind)) { - switch (kind) { - case kZygoteCommandFork: - // This function call can return multiple times, once per fork(). - return HandleForkRequest(fd, iter, std::move(fds)); - - case kZygoteCommandReap: - if (!fds.empty()) - break; - HandleReapRequest(fd, iter); - return false; - case kZygoteCommandGetTerminationStatus: - if (!fds.empty()) - break; - HandleGetTerminationStatus(fd, iter); - return false; - case kZygoteCommandGetSandboxStatus: - HandleGetSandboxStatus(fd, iter); - return false; - case kZygoteCommandForkRealPID: - // This shouldn't happen in practice, but some failure paths in - // HandleForkRequest (e.g., if ReadArgsAndFork fails during depickling) - // could leave this command pending on the socket. - LOG(ERROR) << "Unexpected real PID message from browser"; - NOTREACHED(); - return false; - default: - NOTREACHED(); - break; - } - } - - LOG(WARNING) << "Error parsing message from browser"; - return false; -} - -void Zygote::HandleReapRequest(int fd, base::PickleIterator iter) { - base::ProcessId child; - - if (!iter.ReadInt(&child)) { - LOG(WARNING) << "Error parsing reap request from browser"; - return; - } - - ZygoteProcessInfo child_info; - if (!GetProcessInfo(child, &child_info)) { - LOG(ERROR) << "Child not found!"; - NOTREACHED(); - return; - } - child_info.time_of_reap_request = base::TimeTicks::Now(); - - if (!child_info.started_from_helper) { - to_reap_.push_back(child_info); - } else { - // For processes from the helper, send a GetTerminationStatus request - // with known_dead set to true. - // This is not perfect, as the process may be killed instantly, but is - // better than ignoring the request. - base::TerminationStatus status; - int exit_code; - bool got_termination_status = - GetTerminationStatus(child, true /* known_dead */, &status, &exit_code); - DCHECK(got_termination_status); - } - process_info_map_.erase(child); -} - -bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, - bool known_dead, - base::TerminationStatus* status, - int* exit_code) { - ZygoteProcessInfo child_info; - if (!GetProcessInfo(real_pid, &child_info)) { - LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID " << real_pid; - NOTREACHED(); - return false; - } - // We know about |real_pid|. - const base::ProcessHandle child = child_info.internal_pid; - if (child_info.started_from_helper) { - if (!child_info.started_from_helper->GetTerminationStatus( - child, known_dead, status, exit_code)) { - return false; - } - } else { - // Handle the request directly. - if (known_dead) { - *status = base::GetKnownDeadTerminationStatus(child, exit_code); - } else { - // We don't know if the process is dying, so get its status but don't - // wait. - *status = base::GetTerminationStatus(child, exit_code); - } - } - // Successfully got a status for |real_pid|. - if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { - // Time to forget about this process. - process_info_map_.erase(real_pid); - } - - if (WIFEXITED(*exit_code)) { - const int exit_status = WEXITSTATUS(*exit_code); - if (exit_status == sandbox::NamespaceSandbox::SignalExitCode(SIGINT) || - exit_status == sandbox::NamespaceSandbox::SignalExitCode(SIGTERM)) { - *status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED; - } - } - - return true; -} - -void Zygote::HandleGetTerminationStatus(int fd, base::PickleIterator iter) { - bool known_dead; - base::ProcessHandle child_requested; - - if (!iter.ReadBool(&known_dead) || !iter.ReadInt(&child_requested)) { - LOG(WARNING) << "Error parsing GetTerminationStatus request " - << "from browser"; - return; - } - - base::TerminationStatus status; - int exit_code; - - bool got_termination_status = - GetTerminationStatus(child_requested, known_dead, &status, &exit_code); - if (!got_termination_status) { - // Assume that if we can't find the child in the sandbox, then - // it terminated normally. - NOTREACHED(); - status = base::TERMINATION_STATUS_NORMAL_TERMINATION; - exit_code = service_manager::RESULT_CODE_NORMAL_EXIT; - } - - base::Pickle write_pickle; - write_pickle.WriteInt(static_cast<int>(status)); - write_pickle.WriteInt(exit_code); - ssize_t written = - HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); - if (written != static_cast<ssize_t>(write_pickle.size())) - PLOG(ERROR) << "write"; -} - -int Zygote::ForkWithRealPid(const std::string& process_type, - const base::GlobalDescriptors::Mapping& fd_mapping, - const std::string& channel_id, - base::ScopedFD pid_oracle, - std::string* uma_name, - int* uma_sample, - int* uma_boundary_value) { - ZygoteForkDelegate* helper = nullptr; - for (auto i = helpers_.begin(); i != helpers_.end(); ++i) { - if ((*i)->CanHelp(process_type, uma_name, uma_sample, uma_boundary_value)) { - helper = i->get(); - break; - } - } - - base::ScopedFD read_pipe, write_pipe; - base::ProcessId pid = 0; - if (helper) { - int mojo_channel_fd = LookUpFd(fd_mapping, kMojoIPCChannel); - if (mojo_channel_fd < 0) { - DLOG(ERROR) << "Failed to find kMojoIPCChannel in FD mapping"; - return -1; - } - std::vector<int> fds; - fds.push_back(mojo_channel_fd); // kBrowserFDIndex - fds.push_back(pid_oracle.get()); // kPIDOracleFDIndex - pid = helper->Fork(process_type, fds, channel_id); - - // Helpers should never return in the child process. - CHECK_NE(pid, 0); - } else { - PCHECK(base::CreatePipe(&read_pipe, &write_pipe)); - if (sandbox_flags_ & service_manager::SandboxLinux::kPIDNS && - sandbox_flags_ & service_manager::SandboxLinux::kUserNS) { - pid = sandbox::NamespaceSandbox::ForkInNewPidNamespace( - /*drop_capabilities_in_child=*/true); - } else { - pid = sandbox::Credentials::ForkAndDropCapabilitiesInChild(); - } - } - - if (pid == 0) { - // In the child process. - - // If the process is the init process inside a PID namespace, it must have - // explicit signal handlers. - if (getpid() == 1) { - static const int kTerminationSignals[] = { - SIGINT, SIGTERM, SIGHUP, SIGQUIT, SIGABRT, SIGPIPE, SIGUSR1, SIGUSR2}; - for (const int sig : kTerminationSignals) { - sandbox::NamespaceSandbox::InstallTerminationSignalHandler( - sig, sandbox::NamespaceSandbox::SignalExitCode(sig)); - } - } - - write_pipe.reset(); - - // Ping the PID oracle socket so the browser can find our PID. - CHECK(SendZygoteChildPing(pid_oracle.get())); - - // Now read back our real PID from the zygote. - base::ProcessId real_pid; - if (!base::ReadFromFD(read_pipe.get(), reinterpret_cast<char*>(&real_pid), - sizeof(real_pid))) { - LOG(FATAL) << "Failed to synchronise with parent zygote process"; - } - if (real_pid <= 0) { - LOG(FATAL) << "Invalid pid from parent zygote"; - } - // Sandboxed processes need to send the global, non-namespaced PID when - // setting up an IPC channel to their parent. - IPC::Channel::SetGlobalPid(real_pid); - // Force the real PID so chrome event data have a PID that corresponds - // to system trace event data. - base::trace_event::TraceLog::GetInstance()->SetProcessID( - static_cast<int>(real_pid)); - base::InitUniqueIdForProcessInPidNamespace(real_pid); - return 0; - } - - // In the parent process. - if (pid < 0) { - // Fork failed. - return -1; - } - - read_pipe.reset(); - pid_oracle.reset(); - - // Always receive a real PID from the zygote host, though it might - // be invalid (see below). - base::ProcessId real_pid = -1; - { - std::vector<base::ScopedFD> recv_fds; - char buf[kZygoteMaxMessageLength]; - const ssize_t len = base::UnixDomainSocket::RecvMsg( - kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds); - - if (len > 0) { - CHECK(recv_fds.empty()); - - base::Pickle pickle(buf, len); - base::PickleIterator iter(pickle); - - int kind; - CHECK(iter.ReadInt(&kind)); - CHECK(kind == kZygoteCommandForkRealPID); - CHECK(iter.ReadInt(&real_pid)); - } - } - - // If we successfully forked a child, but it crashed without sending - // a message to the browser, the browser won't have found its PID. - if (real_pid < 0) { - KillAndReap(pid, helper); - return -1; - } - - // If we're not using a helper, send the PID back to the child process. - if (!helper) { - ssize_t written = - HANDLE_EINTR(write(write_pipe.get(), &real_pid, sizeof(real_pid))); - if (written != sizeof(real_pid)) { - KillAndReap(pid, helper); - return -1; - } - } - - // Now set-up this process to be tracked by the Zygote. - if (process_info_map_.find(real_pid) != process_info_map_.end()) { - LOG(ERROR) << "Already tracking PID " << real_pid; - NOTREACHED(); - } - process_info_map_[real_pid].internal_pid = pid; - process_info_map_[real_pid].started_from_helper = helper; - - return real_pid; -} - -base::ProcessId Zygote::ReadArgsAndFork(base::PickleIterator iter, - std::vector<base::ScopedFD> fds, - std::string* uma_name, - int* uma_sample, - int* uma_boundary_value) { - std::vector<std::string> args; - int argc = 0; - int numfds = 0; - base::GlobalDescriptors::Mapping mapping; - std::string process_type; - std::string channel_id; - const std::string channel_id_prefix = - std::string("--") + - service_manager::switches::kServiceRequestChannelToken + std::string("="); - - if (!iter.ReadString(&process_type)) - return -1; - if (!iter.ReadInt(&argc)) - return -1; - - for (int i = 0; i < argc; ++i) { - std::string arg; - if (!iter.ReadString(&arg)) - return -1; - args.push_back(arg); - if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) - channel_id = arg.substr(channel_id_prefix.length()); - } - - // timezone_id is obtained from ICU in zygote host so that it can't be - // invalid. For an unknown reason, if an invalid ID is passed down here, the - // worst result would be that timezone would be set to Etc/Unknown. - base::string16 timezone_id; - if (!iter.ReadString16(&timezone_id)) - return -1; - icu::TimeZone::adoptDefault(icu::TimeZone::createTimeZone( - icu::UnicodeString(FALSE, timezone_id.data(), timezone_id.length()))); - - if (!iter.ReadInt(&numfds)) - return -1; - if (numfds != static_cast<int>(fds.size())) - return -1; - - // First FD is the PID oracle socket. - if (fds.size() < 1) - return -1; - base::ScopedFD pid_oracle(std::move(fds[0])); - - // Remaining FDs are for the global descriptor mapping. - for (int i = 1; i < numfds; ++i) { - base::GlobalDescriptors::Key key; - if (!iter.ReadUInt32(&key)) - return -1; - mapping.push_back(base::GlobalDescriptors::Descriptor(key, fds[i].get())); - } - - mapping.push_back(ipc_backchannel_); - - // Returns twice, once per process. - base::ProcessId child_pid = - ForkWithRealPid(process_type, mapping, channel_id, std::move(pid_oracle), - uma_name, uma_sample, uma_boundary_value); - if (!child_pid) { - // This is the child process. - - // Our socket from the browser. - PCHECK(0 == IGNORE_EINTR(close(kZygoteSocketPairFd))); - - // Pass ownership of file descriptors from fds to GlobalDescriptors. - for (base::ScopedFD& fd : fds) - ignore_result(fd.release()); - base::GlobalDescriptors::GetInstance()->Reset(mapping); - - // Reset the process-wide command line to our new command line. - base::CommandLine::Reset(); - base::CommandLine::Init(0, nullptr); - base::CommandLine::ForCurrentProcess()->InitFromArgv(args); - - // Update the process title. The argv was already cached by the call to - // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here - // (we don't have the original argv at this point). - service_manager::SetProcessTitleFromCommandLine(nullptr); - } else if (child_pid < 0) { - LOG(ERROR) << "Zygote could not fork: process_type " << process_type - << " numfds " << numfds << " child_pid " << child_pid; - } - return child_pid; -} - -bool Zygote::HandleForkRequest(int fd, - base::PickleIterator iter, - std::vector<base::ScopedFD> fds) { - std::string uma_name; - int uma_sample; - int uma_boundary_value; - base::ProcessId child_pid = ReadArgsAndFork(iter, std::move(fds), &uma_name, - &uma_sample, &uma_boundary_value); - if (child_pid == 0) - return true; - // If there's no UMA report for this particular fork, then check if any - // helpers have an initial UMA report for us to send instead. - while (uma_name.empty() && initial_uma_index_ < helpers_.size()) { - helpers_[initial_uma_index_++]->InitialUMA(&uma_name, &uma_sample, - &uma_boundary_value); - } - // Must always send reply, as ZygoteHost blocks while waiting for it. - base::Pickle reply_pickle; - reply_pickle.WriteInt(child_pid); - reply_pickle.WriteString(uma_name); - if (!uma_name.empty()) { - reply_pickle.WriteInt(uma_sample); - reply_pickle.WriteInt(uma_boundary_value); - } - if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != - static_cast<ssize_t>(reply_pickle.size())) - PLOG(ERROR) << "write"; - return false; -} - -bool Zygote::HandleGetSandboxStatus(int fd, base::PickleIterator iter) { - if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != - sizeof(sandbox_flags_)) { - PLOG(ERROR) << "write"; - } - - return false; -} - -} // namespace service_manager diff --git a/chromium/services/service_manager/zygote/zygote_linux.h b/chromium/services/service_manager/zygote/zygote_linux.h deleted file mode 100644 index 840aa17a093..00000000000 --- a/chromium/services/service_manager/zygote/zygote_linux.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_LINUX_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_LINUX_H_ - -#include <stddef.h> - -#include <memory> -#include <string> -#include <vector> - -#include "base/containers/small_map.h" -#include "base/files/scoped_file.h" -#include "base/posix/global_descriptors.h" -#include "base/process/kill.h" -#include "base/process/process.h" -#include "base/process/process_handle.h" -#include "base/time/time.h" - -namespace base { -class PickleIterator; -} - -namespace service_manager { - -class ZygoteForkDelegate; - -// This is the object which implements the zygote. The ZygoteMain function, -// which is called from ChromeMain, simply constructs one of these objects and -// runs it. -class Zygote { - public: - Zygote(int sandbox_flags, - std::vector<std::unique_ptr<ZygoteForkDelegate>> helpers, - const base::GlobalDescriptors::Descriptor& ipc_backchannel); - ~Zygote(); - - bool ProcessRequests(); - - private: - struct ZygoteProcessInfo { - // Pid from inside the Zygote's PID namespace. - base::ProcessHandle internal_pid; - // Keeps track of which fork delegate helper the process was started from. - ZygoteForkDelegate* started_from_helper; - // Records when the browser requested the zygote to reap this process. - base::TimeTicks time_of_reap_request; - // Notes whether the zygote has sent SIGKILL to this process. - bool sent_sigkill; - }; - using ZygoteProcessMap = - base::small_map<std::map<base::ProcessHandle, ZygoteProcessInfo>>; - - // Retrieve a ZygoteProcessInfo from the process_info_map_. - // Returns true and write to process_info if |pid| can be found, return - // false otherwise. - bool GetProcessInfo(base::ProcessHandle pid, ZygoteProcessInfo* process_info); - - // Returns true if the SUID sandbox is active. - bool UsingSUIDSandbox() const; - // Returns true if the NS sandbox is active. - bool UsingNSSandbox() const; - - // --------------------------------------------------------------------------- - // Requests from the browser... - - // Read and process a request from the browser. Returns true if we are in a - // new process and thus need to unwind back into ChromeMain. - bool HandleRequestFromBrowser(int fd); - - void HandleReapRequest(int fd, base::PickleIterator iter); - - // Get the termination status of |real_pid|. |real_pid| is the PID as it - // appears outside of the sandbox. - // Return true if it managed to get the termination status and return the - // status in |status| and the exit code in |exit_code|. - bool GetTerminationStatus(base::ProcessHandle real_pid, - bool known_dead, - base::TerminationStatus* status, - int* exit_code); - - void HandleGetTerminationStatus(int fd, base::PickleIterator iter); - - // This is equivalent to fork(), except that, when using the SUID sandbox, it - // returns the real PID of the child process as it appears outside the - // sandbox, rather than returning the PID inside the sandbox. The child's - // real PID is determined by having it call - // service_manager::SendZygoteChildPing(int) using the |pid_oracle| - // descriptor. - // Finally, when using a ZygoteForkDelegate helper, |uma_name|, |uma_sample|, - // and |uma_boundary_value| may be set if the helper wants to make a UMA - // report via UMA_HISTOGRAM_ENUMERATION. - int ForkWithRealPid(const std::string& process_type, - const base::GlobalDescriptors::Mapping& fd_mapping, - const std::string& channel_id, - base::ScopedFD pid_oracle, - std::string* uma_name, - int* uma_sample, - int* uma_boundary_value); - - // Unpacks process type and arguments from |iter| and forks a new process. - // Returns -1 on error, otherwise returns twice, returning 0 to the child - // process and the child process ID to the parent process, like fork(). - base::ProcessId ReadArgsAndFork(base::PickleIterator iter, - std::vector<base::ScopedFD> fds, - std::string* uma_name, - int* uma_sample, - int* uma_boundary_value); - - // Handle a 'fork' request from the browser: this means that the browser - // wishes to start a new renderer. Returns true if we are in a new process, - // otherwise writes the child_pid back to the browser via |fd|. Writes a - // child_pid of -1 on error. - bool HandleForkRequest(int fd, - base::PickleIterator iter, - std::vector<base::ScopedFD> fds); - - bool HandleGetSandboxStatus(int fd, base::PickleIterator iter); - - // Attempt to reap the child process by calling waitpid, and return - // whether successful. If the process has not terminated within - // 2 seconds of its reap request, send it SIGKILL. - bool ReapChild(const base::TimeTicks& now, ZygoteProcessInfo* child); - - // Attempt to reap all outstanding children in |to_reap_|. - void ReapChildren(); - - // The Zygote needs to keep some information about each process. Most - // notably what the PID of the process is inside the PID namespace of - // the Zygote and whether or not a process was started by the - // ZygoteForkDelegate helper. - ZygoteProcessMap process_info_map_; - - const int sandbox_flags_; - std::vector<std::unique_ptr<ZygoteForkDelegate>> helpers_; - - // Count of how many fork delegates for which we've invoked InitialUMA(). - size_t initial_uma_index_; - - // The vector contains the child processes that need to be reaped. - std::vector<ZygoteProcessInfo> to_reap_; - - // Sandbox IPC channel for renderers to invoke services from the browser. See - // https://chromium.googlesource.com/chromium/src/+/master/docs/linux/sandbox_ipc.md - base::GlobalDescriptors::Descriptor ipc_backchannel_; -}; - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_LINUX_H_ diff --git a/chromium/services/service_manager/zygote/zygote_main.h b/chromium/services/service_manager/zygote/zygote_main.h deleted file mode 100644 index 8de1e6abc32..00000000000 --- a/chromium/services/service_manager/zygote/zygote_main.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_MAIN_H_ -#define SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_MAIN_H_ - -#include <memory> -#include <vector> - -#include "base/component_export.h" -#include "build/build_config.h" - -namespace service_manager { - -class ZygoteForkDelegate; - -// |delegate| must outlive this call. -COMPONENT_EXPORT(SERVICE_MANAGER_ZYGOTE) -bool ZygoteMain( - std::vector<std::unique_ptr<ZygoteForkDelegate>> fork_delegates); - -} // namespace service_manager - -#endif // SERVICES_SERVICE_MANAGER_ZYGOTE_ZYGOTE_MAIN_H_ diff --git a/chromium/services/service_manager/zygote/zygote_main_linux.cc b/chromium/services/service_manager/zygote/zygote_main_linux.cc deleted file mode 100644 index cf9ec082e69..00000000000 --- a/chromium/services/service_manager/zygote/zygote_main_linux.cc +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/service_manager/zygote/zygote_main.h" - -#include <dlfcn.h> -#include <fcntl.h> -#include <pthread.h> -#include <signal.h> -#include <stddef.h> -#include <stdint.h> -#include <string.h> -#include <sys/prctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include <utility> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/posix/eintr_wrapper.h" -#include "base/posix/unix_domain_socket.h" -#include "base/rand_util.h" -#include "base/strings/safe_sprintf.h" -#include "base/strings/string_number_conversions.h" -#include "base/system/sys_info.h" -#include "build/build_config.h" -#include "sandbox/linux/services/credentials.h" -#include "sandbox/linux/services/init_process_reaper.h" -#include "sandbox/linux/services/libc_interceptor.h" -#include "sandbox/linux/services/namespace_sandbox.h" -#include "sandbox/linux/services/thread_helpers.h" -#include "sandbox/linux/suid/client/setuid_sandbox_client.h" -#include "services/service_manager/embedder/descriptors.h" -#include "services/service_manager/embedder/switches.h" -#include "services/service_manager/sandbox/linux/sandbox_debug_handling_linux.h" -#include "services/service_manager/sandbox/linux/sandbox_linux.h" -#include "services/service_manager/sandbox/sandbox.h" -#include "services/service_manager/sandbox/switches.h" -#include "services/service_manager/zygote/common/common_sandbox_support_linux.h" -#include "services/service_manager/zygote/common/zygote_commands_linux.h" -#include "services/service_manager/zygote/common/zygote_fork_delegate_linux.h" -#include "services/service_manager/zygote/zygote_linux.h" -#include "third_party/icu/source/i18n/unicode/timezone.h" - -namespace service_manager { - -namespace { - -void CloseFds(const std::vector<int>& fds) { - for (const auto& it : fds) { - PCHECK(0 == IGNORE_EINTR(close(it))); - } -} - -base::OnceClosure ClosureFromTwoClosures(base::OnceClosure one, - base::OnceClosure two) { - return base::BindOnce( - [](base::OnceClosure one, base::OnceClosure two) { - if (!one.is_null()) - std::move(one).Run(); - if (!two.is_null()) - std::move(two).Run(); - }, - std::move(one), std::move(two)); -} - -} // namespace - -// This function triggers the static and lazy construction of objects that need -// to be created before imposing the sandbox. -static void ZygotePreSandboxInit() { - base::RandUint64(); - - base::SysInfo::AmountOfPhysicalMemory(); - base::SysInfo::NumberOfProcessors(); - - // ICU DateFormat class (used in base/time_format.cc) needs to get the - // Olson timezone ID by accessing the zoneinfo files on disk. After - // TimeZone::createDefault is called once here, the timezone ID is - // cached and there's no more need to access the file system. - std::unique_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault()); -} - -static bool CreateInitProcessReaper( - base::OnceClosure post_fork_parent_callback) { - // The current process becomes init(1), this function returns from a - // newly created process. - if (!sandbox::CreateInitProcessReaper(std::move(post_fork_parent_callback))) { - LOG(ERROR) << "Error creating an init process to reap zombies"; - return false; - } - return true; -} - -// Enter the setuid sandbox. This requires the current process to have been -// created through the setuid sandbox. -static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox, - base::OnceClosure post_fork_parent_callback) { - DCHECK(setuid_sandbox); - DCHECK(setuid_sandbox->IsSuidSandboxChild()); - - // Use the SUID sandbox. This still allows the seccomp sandbox to - // be enabled by the process later. - - if (!setuid_sandbox->IsSuidSandboxUpToDate()) { - LOG(WARNING) << "You are using a wrong version of the setuid binary!\n" - "Please read " - "https://chromium.googlesource.com/chromium/src/+/master/" - "docs/linux/suid_sandbox_development.md." - "\n\n"; - } - - if (!setuid_sandbox->ChrootMe()) - return false; - - if (setuid_sandbox->IsInNewPIDNamespace()) { - CHECK_EQ(1, getpid()) - << "The SUID sandbox created a new PID namespace but Zygote " - "is not the init process. Please, make sure the SUID " - "binary is up to date."; - } - - if (getpid() == 1) { - // The setuid sandbox has created a new PID namespace and we need - // to assume the role of init. - CHECK(CreateInitProcessReaper(std::move(post_fork_parent_callback))); - } - - CHECK(service_manager::SandboxDebugHandling::SetDumpableStatusAndHandlers()); - return true; -} - -static void DropAllCapabilities(int proc_fd) { - CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd)); -} - -static void EnterNamespaceSandbox(service_manager::SandboxLinux* linux_sandbox, - base::OnceClosure post_fork_parent_callback) { - linux_sandbox->EngageNamespaceSandbox(true /* from_zygote */); - if (getpid() == 1) { - CHECK(CreateInitProcessReaper(ClosureFromTwoClosures( - base::BindOnce(DropAllCapabilities, linux_sandbox->proc_fd()), - std::move(post_fork_parent_callback)))); - } -} - -static void EnterLayerOneSandbox(service_manager::SandboxLinux* linux_sandbox, - const bool using_layer1_sandbox, - base::OnceClosure post_fork_parent_callback) { - DCHECK(linux_sandbox); - - ZygotePreSandboxInit(); - -// Check that the pre-sandbox initialization didn't spawn threads. -// It's not just our code which may do so - some system-installed libraries -// are known to be culprits, e.g. lttng. -#if !defined(THREAD_SANITIZER) - CHECK(sandbox::ThreadHelpers::IsSingleThreaded()); -#endif - - sandbox::SetuidSandboxClient* setuid_sandbox = - linux_sandbox->setuid_sandbox_client(); - if (setuid_sandbox->IsSuidSandboxChild()) { - CHECK( - EnterSuidSandbox(setuid_sandbox, std::move(post_fork_parent_callback))) - << "Failed to enter setuid sandbox"; - } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) { - EnterNamespaceSandbox(linux_sandbox, std::move(post_fork_parent_callback)); - } else { - CHECK(!using_layer1_sandbox); - } -} - -bool ZygoteMain( - std::vector<std::unique_ptr<ZygoteForkDelegate>> fork_delegates) { - sandbox::SetAmZygoteOrRenderer(true, GetSandboxFD()); - - auto* linux_sandbox = service_manager::SandboxLinux::GetInstance(); - - // Skip pre-initializing sandbox when sandbox is disabled for - // https://crbug.com/444900. - if (!base::CommandLine::ForCurrentProcess()->HasSwitch( - service_manager::switches::kNoSandbox) && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - service_manager::switches::kNoZygoteSandbox)) { - // This will pre-initialize the various sandboxes that need it. - linux_sandbox->PreinitializeSandbox(); - } - - const bool using_setuid_sandbox = - linux_sandbox->setuid_sandbox_client()->IsSuidSandboxChild(); - const bool using_namespace_sandbox = - sandbox::NamespaceSandbox::InNewUserNamespace(); - const bool using_layer1_sandbox = - using_setuid_sandbox || using_namespace_sandbox; - - if (using_setuid_sandbox) { - linux_sandbox->setuid_sandbox_client()->CloseDummyFile(); - } - - if (using_layer1_sandbox) { - // Let the ZygoteHost know we're booting up. - if (!base::UnixDomainSocket::SendMsg( - kZygoteSocketPairFd, kZygoteBootMessage, sizeof(kZygoteBootMessage), - std::vector<int>())) { - // This is not a CHECK failure because the browser process could either - // crash or quickly exit while the zygote is starting. In either case a - // zygote crash is not useful. https://crbug.com/692227 - PLOG(ERROR) << "Failed sending zygote boot message"; - _exit(1); - } - } - - VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size() - << " fork delegates"; - for (const auto& fork_delegate : fork_delegates) { - fork_delegate->Init(GetSandboxFD(), using_layer1_sandbox); - } - - // Turn on the first layer of the sandbox if the configuration warrants it. - EnterLayerOneSandbox( - linux_sandbox, using_layer1_sandbox, - base::BindOnce(CloseFds, linux_sandbox->GetFileDescriptorsToClose())); - - const int sandbox_flags = linux_sandbox->GetStatus(); - const bool setuid_sandbox_engaged = - !!(sandbox_flags & service_manager::SandboxLinux::kSUID); - CHECK_EQ(using_setuid_sandbox, setuid_sandbox_engaged); - - const bool namespace_sandbox_engaged = - !!(sandbox_flags & service_manager::SandboxLinux::kUserNS); - CHECK_EQ(using_namespace_sandbox, namespace_sandbox_engaged); - - Zygote zygote(sandbox_flags, std::move(fork_delegates), - base::GlobalDescriptors::Descriptor( - static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); - - // This function call can return multiple times, once per fork(). - return zygote.ProcessRequests(); -} - -} // namespace service_manager |