1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "SocketProcessChild.h"
7 #include "SocketProcessLogging.h"
8 
9 #include "base/task.h"
10 #include "InputChannelThrottleQueueChild.h"
11 #include "HttpTransactionChild.h"
12 #include "HttpConnectionMgrChild.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/dom/MemoryReportRequest.h"
15 #include "mozilla/ipc/CrashReporterClient.h"
16 #include "mozilla/ipc/BackgroundChild.h"
17 #include "mozilla/ipc/BackgroundParent.h"
18 #include "mozilla/ipc/FileDescriptorSetChild.h"
19 #include "mozilla/ipc/IPCStreamAlloc.h"
20 #include "mozilla/ipc/ProcessChild.h"
21 #include "mozilla/net/AltSvcTransactionChild.h"
22 #include "mozilla/net/BackgroundDataBridgeParent.h"
23 #include "mozilla/net/DNSRequestChild.h"
24 #include "mozilla/net/DNSRequestParent.h"
25 #include "mozilla/net/TRRServiceChild.h"
26 #include "mozilla/ipc/PChildToParentStreamChild.h"
27 #include "mozilla/ipc/PParentToChildStreamChild.h"
28 #include "mozilla/Preferences.h"
29 #include "mozilla/Telemetry.h"
30 #include "nsDebugImpl.h"
31 #include "nsHttpConnectionInfo.h"
32 #include "nsHttpHandler.h"
33 #include "nsIDNSService.h"
34 #include "nsIHttpActivityObserver.h"
35 #include "nsNSSComponent.h"
36 #include "nsThreadManager.h"
37 #include "ProcessUtils.h"
38 #include "SocketProcessBridgeParent.h"
39 
40 #if defined(XP_WIN)
41 #  include <process.h>
42 #else
43 #  include <unistd.h>
44 #endif
45 
46 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
47 #  include "mozilla/Sandbox.h"
48 #endif
49 
50 #ifdef MOZ_GECKO_PROFILER
51 #  include "ChildProfilerController.h"
52 #endif
53 
54 #ifdef MOZ_WEBRTC
55 #  include "mozilla/net/WebrtcTCPSocketChild.h"
56 #endif
57 
58 namespace mozilla {
59 namespace net {
60 
61 using namespace ipc;
62 
63 SocketProcessChild* sSocketProcessChild;
64 
SocketProcessChild()65 SocketProcessChild::SocketProcessChild()
66     : mShuttingDown(false), mMutex("SocketProcessChild::mMutex") {
67   LOG(("CONSTRUCT SocketProcessChild::SocketProcessChild\n"));
68   nsDebugImpl::SetMultiprocessMode("Socket");
69 
70   MOZ_COUNT_CTOR(SocketProcessChild);
71   sSocketProcessChild = this;
72 }
73 
~SocketProcessChild()74 SocketProcessChild::~SocketProcessChild() {
75   LOG(("DESTRUCT SocketProcessChild::SocketProcessChild\n"));
76   MOZ_COUNT_DTOR(SocketProcessChild);
77   sSocketProcessChild = nullptr;
78 }
79 
80 /* static */
GetSingleton()81 SocketProcessChild* SocketProcessChild::GetSingleton() {
82   return sSocketProcessChild;
83 }
84 
85 #if defined(XP_MACOSX)
86 extern "C" {
87 void CGSShutdownServerConnections();
88 };
89 #endif
90 
Init(base::ProcessId aParentPid,const char * aParentBuildID,MessageLoop * aIOLoop,UniquePtr<IPC::Channel> aChannel)91 bool SocketProcessChild::Init(base::ProcessId aParentPid,
92                               const char* aParentBuildID, MessageLoop* aIOLoop,
93                               UniquePtr<IPC::Channel> aChannel) {
94   if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
95     return false;
96   }
97   if (NS_WARN_IF(!Open(std::move(aChannel), aParentPid, aIOLoop))) {
98     return false;
99   }
100   // This must be sent before any IPDL message, which may hit sentinel
101   // errors due to parent and content processes having different
102   // versions.
103   MessageChannel* channel = GetIPCChannel();
104   if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) {
105     // We need to quit this process if the buildID doesn't match the parent's.
106     // This can occur when an update occurred in the background.
107     ProcessChild::QuickExit();
108   }
109 
110   // Init crash reporter support.
111   CrashReporterClient::InitSingleton(this);
112 
113   if (NS_FAILED(NS_InitMinimalXPCOM())) {
114     return false;
115   }
116 
117   BackgroundChild::Startup();
118   SetThisProcessName("Socket Process");
119 #if defined(XP_MACOSX)
120   // Close all current connections to the WindowServer. This ensures that the
121   // Activity Monitor will not label the socket process as "Not responding"
122   // because it's not running a native event loop. See bug 1384336.
123   CGSShutdownServerConnections();
124 #endif  // XP_MACOSX
125   return true;
126 }
127 
ActorDestroy(ActorDestroyReason aWhy)128 void SocketProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
129   LOG(("SocketProcessChild::ActorDestroy\n"));
130 
131   mShuttingDown = true;
132 
133   if (AbnormalShutdown == aWhy) {
134     NS_WARNING("Shutting down Socket process early due to a crash!");
135     ProcessChild::QuickExit();
136   }
137 
138 #ifdef MOZ_GECKO_PROFILER
139   if (mProfilerController) {
140     mProfilerController->Shutdown();
141     mProfilerController = nullptr;
142   }
143 #endif
144 
145   CrashReporterClient::DestroySingleton();
146   XRE_ShutdownChildProcess();
147 }
148 
CleanUp()149 void SocketProcessChild::CleanUp() {
150   LOG(("SocketProcessChild::CleanUp\n"));
151 
152   for (auto iter = mSocketProcessBridgeParentMap.Iter(); !iter.Done();
153        iter.Next()) {
154     if (!iter.Data()->Closed()) {
155       iter.Data()->Close();
156     }
157   }
158   NS_ShutdownXPCOM(nullptr);
159 }
160 
RecvPreferenceUpdate(const Pref & aPref)161 IPCResult SocketProcessChild::RecvPreferenceUpdate(const Pref& aPref) {
162   Preferences::SetPreference(aPref);
163   return IPC_OK();
164 }
165 
RecvRequestMemoryReport(const uint32_t & aGeneration,const bool & aAnonymize,const bool & aMinimizeMemoryUsage,const Maybe<ipc::FileDescriptor> & aDMDFile)166 mozilla::ipc::IPCResult SocketProcessChild::RecvRequestMemoryReport(
167     const uint32_t& aGeneration, const bool& aAnonymize,
168     const bool& aMinimizeMemoryUsage,
169     const Maybe<ipc::FileDescriptor>& aDMDFile) {
170   nsPrintfCString processName("Socket (pid %u)", (unsigned)getpid());
171 
172   mozilla::dom::MemoryReportRequestClient::Start(
173       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
174       [&](const MemoryReport& aReport) {
175         Unused << GetSingleton()->SendAddMemoryReport(aReport);
176       },
177       [&](const uint32_t& aGeneration) {
178         return GetSingleton()->SendFinishMemoryReport(aGeneration);
179       });
180   return IPC_OK();
181 }
182 
RecvSetOffline(const bool & aOffline)183 mozilla::ipc::IPCResult SocketProcessChild::RecvSetOffline(
184     const bool& aOffline) {
185   LOG(("SocketProcessChild::RecvSetOffline aOffline=%d\n", aOffline));
186 
187   nsCOMPtr<nsIIOService> io(do_GetIOService());
188   NS_ASSERTION(io, "IO Service can not be null");
189 
190   io->SetOffline(aOffline);
191 
192   return IPC_OK();
193 }
194 
RecvInitLinuxSandbox(const Maybe<ipc::FileDescriptor> & aBrokerFd)195 mozilla::ipc::IPCResult SocketProcessChild::RecvInitLinuxSandbox(
196     const Maybe<ipc::FileDescriptor>& aBrokerFd) {
197 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
198   int fd = -1;
199   if (aBrokerFd.isSome()) {
200     fd = aBrokerFd.value().ClonePlatformHandle().release();
201   }
202   SetSocketProcessSandbox(fd);
203 #endif  // XP_LINUX && MOZ_SANDBOX
204   return IPC_OK();
205 }
206 
RecvInitSocketProcessBridgeParent(const ProcessId & aContentProcessId,Endpoint<mozilla::net::PSocketProcessBridgeParent> && aEndpoint)207 mozilla::ipc::IPCResult SocketProcessChild::RecvInitSocketProcessBridgeParent(
208     const ProcessId& aContentProcessId,
209     Endpoint<mozilla::net::PSocketProcessBridgeParent>&& aEndpoint) {
210   MOZ_ASSERT(NS_IsMainThread());
211   MOZ_ASSERT(!mSocketProcessBridgeParentMap.Get(aContentProcessId, nullptr));
212 
213   mSocketProcessBridgeParentMap.Put(
214       aContentProcessId, MakeRefPtr<SocketProcessBridgeParent>(
215                              aContentProcessId, std::move(aEndpoint)));
216   return IPC_OK();
217 }
218 
RecvInitProfiler(Endpoint<PProfilerChild> && aEndpoint)219 mozilla::ipc::IPCResult SocketProcessChild::RecvInitProfiler(
220     Endpoint<PProfilerChild>&& aEndpoint) {
221 #ifdef MOZ_GECKO_PROFILER
222   mProfilerController =
223       mozilla::ChildProfilerController::Create(std::move(aEndpoint));
224 #endif
225   return IPC_OK();
226 }
227 
RecvSocketProcessTelemetryPing()228 mozilla::ipc::IPCResult SocketProcessChild::RecvSocketProcessTelemetryPing() {
229   const uint32_t kExpectedUintValue = 42;
230   Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_SOCKET_ONLY_UINT,
231                        kExpectedUintValue);
232   return IPC_OK();
233 }
234 
DestroySocketProcessBridgeParent(ProcessId aId)235 void SocketProcessChild::DestroySocketProcessBridgeParent(ProcessId aId) {
236   MOZ_ASSERT(NS_IsMainThread());
237 
238   mSocketProcessBridgeParentMap.Remove(aId);
239 }
240 
AllocPWebrtcTCPSocketChild(const Maybe<TabId> & tabId)241 PWebrtcTCPSocketChild* SocketProcessChild::AllocPWebrtcTCPSocketChild(
242     const Maybe<TabId>& tabId) {
243   // We don't allocate here: instead we always use IPDL constructor that takes
244   // an existing object
245   MOZ_ASSERT_UNREACHABLE(
246       "AllocPWebrtcTCPSocketChild should not be called on"
247       " socket child");
248   return nullptr;
249 }
250 
DeallocPWebrtcTCPSocketChild(PWebrtcTCPSocketChild * aActor)251 bool SocketProcessChild::DeallocPWebrtcTCPSocketChild(
252     PWebrtcTCPSocketChild* aActor) {
253 #ifdef MOZ_WEBRTC
254   WebrtcTCPSocketChild* child = static_cast<WebrtcTCPSocketChild*>(aActor);
255   child->ReleaseIPDLReference();
256 #endif
257   return true;
258 }
259 
260 already_AddRefed<PHttpTransactionChild>
AllocPHttpTransactionChild()261 SocketProcessChild::AllocPHttpTransactionChild() {
262   RefPtr<HttpTransactionChild> actor = new HttpTransactionChild();
263   return actor.forget();
264 }
265 
AllocPFileDescriptorSetChild(const FileDescriptor & aFD)266 PFileDescriptorSetChild* SocketProcessChild::AllocPFileDescriptorSetChild(
267     const FileDescriptor& aFD) {
268   return new FileDescriptorSetChild(aFD);
269 }
270 
DeallocPFileDescriptorSetChild(PFileDescriptorSetChild * aActor)271 bool SocketProcessChild::DeallocPFileDescriptorSetChild(
272     PFileDescriptorSetChild* aActor) {
273   delete aActor;
274   return true;
275 }
276 
277 PChildToParentStreamChild*
AllocPChildToParentStreamChild()278 SocketProcessChild::AllocPChildToParentStreamChild() {
279   MOZ_CRASH("PChildToParentStreamChild actors should be manually constructed!");
280 }
281 
DeallocPChildToParentStreamChild(PChildToParentStreamChild * aActor)282 bool SocketProcessChild::DeallocPChildToParentStreamChild(
283     PChildToParentStreamChild* aActor) {
284   delete aActor;
285   return true;
286 }
287 
288 PParentToChildStreamChild*
AllocPParentToChildStreamChild()289 SocketProcessChild::AllocPParentToChildStreamChild() {
290   return mozilla::ipc::AllocPParentToChildStreamChild();
291 }
292 
DeallocPParentToChildStreamChild(PParentToChildStreamChild * aActor)293 bool SocketProcessChild::DeallocPParentToChildStreamChild(
294     PParentToChildStreamChild* aActor) {
295   delete aActor;
296   return true;
297 }
298 
299 PChildToParentStreamChild*
SendPChildToParentStreamConstructor(PChildToParentStreamChild * aActor)300 SocketProcessChild::SendPChildToParentStreamConstructor(
301     PChildToParentStreamChild* aActor) {
302   MOZ_ASSERT(NS_IsMainThread());
303   return PSocketProcessChild::SendPChildToParentStreamConstructor(aActor);
304 }
305 
SendPFileDescriptorSetConstructor(const FileDescriptor & aFD)306 PFileDescriptorSetChild* SocketProcessChild::SendPFileDescriptorSetConstructor(
307     const FileDescriptor& aFD) {
308   MOZ_ASSERT(NS_IsMainThread());
309   return PSocketProcessChild::SendPFileDescriptorSetConstructor(aFD);
310 }
311 
312 already_AddRefed<PHttpConnectionMgrChild>
AllocPHttpConnectionMgrChild()313 SocketProcessChild::AllocPHttpConnectionMgrChild() {
314   LOG(("SocketProcessChild::AllocPHttpConnectionMgrChild \n"));
315   if (!gHttpHandler) {
316     nsresult rv;
317     nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
318     if (NS_FAILED(rv)) {
319       return nullptr;
320     }
321 
322     nsCOMPtr<nsIProtocolHandler> handler;
323     rv = ios->GetProtocolHandler("http", getter_AddRefs(handler));
324     if (NS_FAILED(rv)) {
325       return nullptr;
326     }
327 
328     // Initialize DNS Service here, since it needs to be done in main thread.
329     nsCOMPtr<nsIDNSService> dns =
330         do_GetService("@mozilla.org/network/dns-service;1", &rv);
331     if (NS_FAILED(rv)) {
332       return nullptr;
333     }
334 
335     RefPtr<HttpConnectionMgrChild> actor = new HttpConnectionMgrChild();
336     return actor.forget();
337   }
338 
339   return nullptr;
340 }
341 
342 mozilla::ipc::IPCResult
RecvOnHttpActivityDistributorActivated(const bool & aIsActivated)343 SocketProcessChild::RecvOnHttpActivityDistributorActivated(
344     const bool& aIsActivated) {
345   if (nsCOMPtr<nsIHttpActivityObserver> distributor =
346           services::GetActivityDistributor()) {
347     distributor->SetIsActive(aIsActivated);
348   }
349   return IPC_OK();
350 }
351 already_AddRefed<PInputChannelThrottleQueueChild>
AllocPInputChannelThrottleQueueChild(const uint32_t & aMeanBytesPerSecond,const uint32_t & aMaxBytesPerSecond)352 SocketProcessChild::AllocPInputChannelThrottleQueueChild(
353     const uint32_t& aMeanBytesPerSecond, const uint32_t& aMaxBytesPerSecond) {
354   RefPtr<InputChannelThrottleQueueChild> p =
355       new InputChannelThrottleQueueChild();
356   p->Init(aMeanBytesPerSecond, aMaxBytesPerSecond);
357   return p.forget();
358 }
359 
360 already_AddRefed<PAltSvcTransactionChild>
AllocPAltSvcTransactionChild(const HttpConnectionInfoCloneArgs & aConnInfo,const uint32_t & aCaps)361 SocketProcessChild::AllocPAltSvcTransactionChild(
362     const HttpConnectionInfoCloneArgs& aConnInfo, const uint32_t& aCaps) {
363   RefPtr<nsHttpConnectionInfo> cinfo =
364       nsHttpConnectionInfo::DeserializeHttpConnectionInfoCloneArgs(aConnInfo);
365   RefPtr<AltSvcTransactionChild> child =
366       new AltSvcTransactionChild(cinfo, aCaps);
367   return child.forget();
368 }
369 
AllocPDNSRequestChild(const nsCString & aHost,const nsCString & aTrrServer,const uint16_t & aType,const OriginAttributes & aOriginAttributes,const uint32_t & aFlags)370 already_AddRefed<PDNSRequestChild> SocketProcessChild::AllocPDNSRequestChild(
371     const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType,
372     const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) {
373   RefPtr<DNSRequestHandler> handler = new DNSRequestHandler();
374   RefPtr<DNSRequestChild> actor = new DNSRequestChild(handler);
375   return actor.forget();
376 }
377 
RecvPDNSRequestConstructor(PDNSRequestChild * aActor,const nsCString & aHost,const nsCString & aTrrServer,const uint16_t & aType,const OriginAttributes & aOriginAttributes,const uint32_t & aFlags)378 mozilla::ipc::IPCResult SocketProcessChild::RecvPDNSRequestConstructor(
379     PDNSRequestChild* aActor, const nsCString& aHost,
380     const nsCString& aTrrServer, const uint16_t& aType,
381     const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) {
382   RefPtr<DNSRequestChild> actor = static_cast<DNSRequestChild*>(aActor);
383   RefPtr<DNSRequestHandler> handler =
384       actor->GetDNSRequest()->AsDNSRequestHandler();
385   handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags);
386   return IPC_OK();
387 }
388 
AddDataBridgeToMap(uint64_t aChannelId,BackgroundDataBridgeParent * aActor)389 void SocketProcessChild::AddDataBridgeToMap(
390     uint64_t aChannelId, BackgroundDataBridgeParent* aActor) {
391   ipc::AssertIsOnBackgroundThread();
392   MutexAutoLock lock(mMutex);
393   mBackgroundDataBridgeMap.Put(aChannelId, aActor);
394 }
395 
RemoveDataBridgeFromMap(uint64_t aChannelId)396 void SocketProcessChild::RemoveDataBridgeFromMap(uint64_t aChannelId) {
397   ipc::AssertIsOnBackgroundThread();
398   MutexAutoLock lock(mMutex);
399   mBackgroundDataBridgeMap.Remove(aChannelId);
400 }
401 
402 Maybe<RefPtr<BackgroundDataBridgeParent>>
GetAndRemoveDataBridge(uint64_t aChannelId)403 SocketProcessChild::GetAndRemoveDataBridge(uint64_t aChannelId) {
404   MutexAutoLock lock(mMutex);
405   return mBackgroundDataBridgeMap.GetAndRemove(aChannelId);
406 }
407 
RecvClearSessionCache()408 mozilla::ipc::IPCResult SocketProcessChild::RecvClearSessionCache() {
409   if (EnsureNSSInitializedChromeOrContent()) {
410     nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
411   }
412   return IPC_OK();
413 }
414 
AllocPTRRServiceChild(const bool & aCaptiveIsPassed,const bool & aParentalControlEnabled,const nsTArray<nsCString> & aDNSSuffixList)415 already_AddRefed<PTRRServiceChild> SocketProcessChild::AllocPTRRServiceChild(
416     const bool& aCaptiveIsPassed, const bool& aParentalControlEnabled,
417     const nsTArray<nsCString>& aDNSSuffixList) {
418   RefPtr<TRRServiceChild> actor = new TRRServiceChild();
419   return actor.forget();
420 }
421 
RecvPTRRServiceConstructor(PTRRServiceChild * aActor,const bool & aCaptiveIsPassed,const bool & aParentalControlEnabled,nsTArray<nsCString> && aDNSSuffixList)422 mozilla::ipc::IPCResult SocketProcessChild::RecvPTRRServiceConstructor(
423     PTRRServiceChild* aActor, const bool& aCaptiveIsPassed,
424     const bool& aParentalControlEnabled, nsTArray<nsCString>&& aDNSSuffixList) {
425   static_cast<TRRServiceChild*>(aActor)->Init(
426       aCaptiveIsPassed, aParentalControlEnabled, std::move(aDNSSuffixList));
427   return IPC_OK();
428 }
429 
430 }  // namespace net
431 }  // namespace mozilla
432