Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/ipc/ContentProcess.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/ipc/IOThreadChild.h"
8
9
#include "ContentProcess.h"
10
#include "base/shared_memory.h"
11
#include "mozilla/Preferences.h"
12
#include "mozilla/Scheduler.h"
13
#include "mozilla/recordreplay/ParentIPC.h"
14
15
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
16
#include <stdlib.h>
17
#endif
18
19
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
20
#include "mozilla/SandboxSettings.h"
21
#include "nsAppDirectoryServiceDefs.h"
22
#include "nsDirectoryService.h"
23
#include "nsDirectoryServiceDefs.h"
24
#endif
25
26
using mozilla::ipc::IOThreadChild;
27
28
namespace mozilla {
29
namespace dom {
30
31
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
32
static void
33
SetTmpEnvironmentVariable(nsIFile* aValue)
34
{
35
  // Save the TMP environment variable so that is is picked up by GetTempPath().
36
  // Note that we specifically write to the TMP variable, as that is the first
37
  // variable that is checked by GetTempPath() to determine its output.
38
  nsAutoString fullTmpPath;
39
  nsresult rv = aValue->GetPath(fullTmpPath);
40
  if (NS_WARN_IF(NS_FAILED(rv))) {
41
    return;
42
  }
43
  Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get()));
44
  // We also set TEMP in case there is naughty third-party code that is
45
  // referencing the environment variable directly.
46
  Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get()));
47
}
48
#endif
49
50
51
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
52
static void
53
SetUpSandboxEnvironment()
54
{
55
  MOZ_ASSERT(nsDirectoryService::gService,
56
    "SetUpSandboxEnvironment relies on nsDirectoryService being initialized");
57
58
  // On Windows, a sandbox-writable temp directory is used whenever the sandbox
59
  // is enabled.
60
  if (!IsContentSandboxEnabled()) {
61
    return;
62
  }
63
64
  nsCOMPtr<nsIFile> sandboxedContentTemp;
65
  nsresult rv =
66
    nsDirectoryService::gService->Get(NS_APP_CONTENT_PROCESS_TEMP_DIR,
67
                                      NS_GET_IID(nsIFile),
68
                                      getter_AddRefs(sandboxedContentTemp));
69
  if (NS_WARN_IF(NS_FAILED(rv))) {
70
    return;
71
  }
72
73
  // Change the gecko defined temp directory to our sandbox-writable one.
74
  // Undefine returns a failure if the property is not already set.
75
  Unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR);
76
  rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, sandboxedContentTemp);
77
  if (NS_WARN_IF(NS_FAILED(rv))) {
78
    return;
79
  }
80
81
  SetTmpEnvironmentVariable(sandboxedContentTemp);
82
}
83
#endif
84
85
#ifdef ANDROID
86
static int gPrefsFd = -1;
87
static int gPrefMapFd = -1;
88
89
void
90
SetPrefsFd(int aFd)
91
{
92
  gPrefsFd = aFd;
93
}
94
95
void
96
SetPrefMapFd(int aFd)
97
{
98
  gPrefMapFd = aFd;
99
}
100
#endif
101
102
bool
103
ContentProcess::Init(int aArgc, char* aArgv[])
104
0
{
105
0
  Maybe<uint64_t> childID;
106
0
  Maybe<bool> isForBrowser;
107
0
  Maybe<base::SharedMemoryHandle> prefsHandle;
108
0
  Maybe<FileDescriptor> prefMapHandle;
109
0
  Maybe<size_t> prefsLen;
110
0
  Maybe<size_t> prefMapSize;
111
0
  Maybe<const char*> schedulerPrefs;
112
0
  Maybe<const char*> parentBuildID;
113
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
114
  nsCOMPtr<nsIFile> profileDir;
115
#endif
116
117
0
  // Parses an arg containing a pointer-sized-integer.
118
0
  auto parseUIntPtrArg = [] (char*& aArg) {
119
0
    // ContentParent uses %zu to print a word-sized unsigned integer. So
120
0
    // even though strtoull() returns a long long int, it will fit in a
121
0
    // uintptr_t.
122
0
    return uintptr_t(strtoull(aArg, &aArg, 10));
123
0
  };
124
0
125
#ifdef XP_WIN
126
  auto parseHandleArg = [&] (char*& aArg) {
127
    return HANDLE(parseUIntPtrArg(aArg));
128
  };
129
#endif
130
131
0
  for (int i = 1; i < aArgc; i++) {
132
0
    if (!aArgv[i]) {
133
0
      continue;
134
0
    }
135
0
136
0
    if (strcmp(aArgv[i], "-appdir") == 0) {
137
0
      if (++i == aArgc) {
138
0
        return false;
139
0
      }
140
0
      nsDependentCString appDir(aArgv[i]);
141
0
      mXREEmbed.SetAppDir(appDir);
142
0
143
0
    } else if (strcmp(aArgv[i], "-childID") == 0) {
144
0
      if (++i == aArgc) {
145
0
        return false;
146
0
      }
147
0
      char* str = aArgv[i];
148
0
      childID = Some(strtoull(str, &str, 10));
149
0
      if (str[0] != '\0') {
150
0
        return false;
151
0
      }
152
0
153
0
    } else if (strcmp(aArgv[i], "-isForBrowser") == 0) {
154
0
      isForBrowser = Some(true);
155
0
156
0
    } else if (strcmp(aArgv[i], "-notForBrowser") == 0) {
157
0
      isForBrowser = Some(false);
158
0
159
#ifdef XP_WIN
160
    } else if (strcmp(aArgv[i], "-prefsHandle") == 0) {
161
      if (++i == aArgc) {
162
        return false;
163
      }
164
      char* str = aArgv[i];
165
      prefsHandle = Some(parseHandleArg(str));
166
      if (str[0] != '\0') {
167
        return false;
168
      }
169
170
    } else if (strcmp(aArgv[i], "-prefMapHandle") == 0) {
171
      if (++i == aArgc) {
172
        return false;
173
      }
174
      char* str = aArgv[i];
175
      // The FileDescriptor constructor will clone this handle when constructed,
176
      // so store it in a UniquePlatformHandle to make sure the original gets
177
      // closed.
178
      FileDescriptor::UniquePlatformHandle handle(parseHandleArg(str));
179
      prefMapHandle.emplace(handle.get());
180
      if (str[0] != '\0') {
181
        return false;
182
      }
183
#endif
184
185
0
    } else if (strcmp(aArgv[i], "-prefsLen") == 0) {
186
0
      if (++i == aArgc) {
187
0
        return false;
188
0
      }
189
0
      char* str = aArgv[i];
190
0
      prefsLen = Some(parseUIntPtrArg(str));
191
0
      if (str[0] != '\0') {
192
0
        return false;
193
0
      }
194
0
195
0
    } else if (strcmp(aArgv[i], "-prefMapSize") == 0) {
196
0
      if (++i == aArgc) {
197
0
        return false;
198
0
      }
199
0
      char* str = aArgv[i];
200
0
      prefMapSize = Some(parseUIntPtrArg(str));
201
0
      if (str[0] != '\0') {
202
0
        return false;
203
0
      }
204
0
205
0
    } else if (strcmp(aArgv[i], "-schedulerPrefs") == 0) {
206
0
      if (++i == aArgc) {
207
0
        return false;
208
0
      }
209
0
      schedulerPrefs = Some(aArgv[i]);
210
0
211
0
    } else if (strcmp(aArgv[i], "-safeMode") == 0) {
212
0
      gSafeMode = true;
213
0
214
0
    } else if (strcmp(aArgv[i], "-parentBuildID") == 0) {
215
0
      if (++i == aArgc) {
216
0
        return false;
217
0
      }
218
0
      parentBuildID = Some(aArgv[i]);
219
0
220
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
221
    } else if (strcmp(aArgv[i], "-profile") == 0) {
222
      if (++i == aArgc) {
223
        return false;
224
      }
225
      bool flag;
226
      nsresult rv = XRE_GetFileFromPath(aArgv[i], getter_AddRefs(profileDir));
227
      if (NS_FAILED(rv) || NS_FAILED(profileDir->Exists(&flag)) || !flag) {
228
        NS_WARNING("Invalid profile directory passed to content process.");
229
        profileDir = nullptr;
230
      }
231
#endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
232
    }
233
0
  }
234
0
235
#ifdef ANDROID
236
  // Android is different; get the FD via gPrefsFd instead of a fixed fd.
237
  MOZ_RELEASE_ASSERT(gPrefsFd != -1);
238
  prefsHandle = Some(base::FileDescriptor(gPrefsFd, /* auto_close */ true));
239
240
  FileDescriptor::UniquePlatformHandle handle(gPrefMapFd);
241
  prefMapHandle.emplace(handle.get());
242
#elif XP_UNIX
243
0
  prefsHandle = Some(base::FileDescriptor(kPrefsFileDescriptor,
244
0
                                          /* auto_close */ true));
245
0
246
0
  // The FileDescriptor constructor will clone this handle when constructed,
247
0
  // so store it in a UniquePlatformHandle to make sure the original gets
248
0
  // closed.
249
0
  FileDescriptor::UniquePlatformHandle handle(kPrefMapFileDescriptor);
250
0
  prefMapHandle.emplace(handle.get());
251
0
#endif
252
0
253
0
  // Did we find all the mandatory flags?
254
0
  if (childID.isNothing() ||
255
0
      isForBrowser.isNothing() ||
256
0
      prefsHandle.isNothing() ||
257
0
      prefsLen.isNothing() ||
258
0
      prefMapHandle.isNothing() ||
259
0
      prefMapSize.isNothing() ||
260
0
      schedulerPrefs.isNothing() ||
261
0
      parentBuildID.isNothing()) {
262
0
    return false;
263
0
  }
264
0
265
0
  // Init the shared-memory base preference mapping first, so that only changed
266
0
  // preferences wind up in heap memory.
267
0
  Preferences::InitSnapshot(prefMapHandle.ref(), *prefMapSize);
268
0
269
0
  // Set up early prefs from the shared memory.
270
0
  base::SharedMemory shm;
271
0
  if (!shm.SetHandle(*prefsHandle, /* read_only */ true)) {
272
0
    NS_ERROR("failed to open shared memory in the child");
273
0
    return false;
274
0
  }
275
0
  if (!shm.Map(*prefsLen)) {
276
0
    NS_ERROR("failed to map shared memory in the child");
277
0
    return false;
278
0
  }
279
0
  Preferences::DeserializePreferences(static_cast<char*>(shm.memory()),
280
0
                                      *prefsLen);
281
0
282
0
  Scheduler::SetPrefs(*schedulerPrefs);
283
0
284
0
  if (recordreplay::IsMiddleman()) {
285
0
    recordreplay::parent::InitializeMiddleman(aArgc, aArgv, ParentPid(),
286
0
                                              *prefsHandle, *prefMapHandle);
287
0
  }
288
0
289
0
  mContent.Init(IOThreadChild::message_loop(),
290
0
                ParentPid(),
291
0
                *parentBuildID,
292
0
                IOThreadChild::channel(),
293
0
                *childID,
294
0
                *isForBrowser);
295
0
296
0
  mXREEmbed.Start();
297
#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
298
  mContent.SetProfileDir(profileDir);
299
#endif
300
301
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
302
  SetUpSandboxEnvironment();
303
#endif
304
305
0
  return true;
306
0
}
307
308
// Note: CleanUp() never gets called in non-debug builds because we exit early
309
// in ContentChild::ActorDestroy().
310
void
311
ContentProcess::CleanUp()
312
0
{
313
0
  mXREEmbed.Stop();
314
0
}
315
316
} // namespace dom
317
} // namespace mozilla