SandboxBrokerPolicyFactory.cpp (39301B)
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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "SandboxBrokerPolicyFactory.h" 8 #include "SandboxInfo.h" 9 #include "SandboxLogging.h" 10 11 #include "mozilla/Array.h" 12 #include "mozilla/ClearOnShutdown.h" 13 #include "mozilla/Omnijar.h" 14 #include "mozilla/Preferences.h" 15 #include "mozilla/SandboxLaunch.h" 16 #include "mozilla/SandboxSettings.h" 17 #include "mozilla/StaticPrefs_security.h" 18 #include "mozilla/StaticMutex.h" 19 #include "mozilla/UniquePtr.h" 20 #include "mozilla/UniquePtrExtensions.h" 21 #include "mozilla/ipc/SharedMemoryHandle.h" 22 #include "nsComponentManagerUtils.h" 23 #include "nsPrintfCString.h" 24 #include "nsString.h" 25 #include "nsThreadUtils.h" 26 #include "nsXULAppAPI.h" 27 #include "nsDirectoryServiceDefs.h" 28 #include "nsAppDirectoryServiceDefs.h" 29 #include "SpecialSystemDirectory.h" 30 #include "nsReadableUtils.h" 31 #include "nsIFileStreams.h" 32 #include "nsILineInputStream.h" 33 #include "nsIFile.h" 34 35 #include "nsNetCID.h" 36 #include "prenv.h" 37 38 #if defined(MOZ_PROFILE_GENERATE) 39 # include <string> 40 #endif 41 42 #ifdef ANDROID 43 # include "cutils/properties.h" 44 #endif 45 46 #ifdef MOZ_WIDGET_GTK 47 # include "mozilla/WidgetUtilsGtk.h" 48 # include <glib.h> 49 #endif 50 51 #ifdef MOZ_ENABLE_V4L2 52 # include <linux/videodev2.h> 53 # include <sys/ioctl.h> 54 # include <fcntl.h> 55 #endif // MOZ_ENABLE_V4L2 56 57 #include <dirent.h> 58 #include <sys/stat.h> 59 #include <sys/sysmacros.h> 60 #include <sys/types.h> 61 #ifndef ANDROID 62 # include <glob.h> 63 #endif 64 65 namespace mozilla { 66 67 namespace { 68 static const int rdonly = SandboxBroker::MAY_READ; 69 static const int wronly = SandboxBroker::MAY_WRITE; 70 static const int rdwr = rdonly | wronly; 71 static const int rdwrcr = rdwr | SandboxBroker::MAY_CREATE; 72 static const int access = SandboxBroker::MAY_ACCESS; 73 static const int deny = SandboxBroker::FORCE_DENY; 74 } // namespace 75 76 using CacheE = std::pair<nsCString, int>; 77 using FileCacheT = nsTArray<CacheE>; 78 79 static void AddDriPaths(SandboxBroker::Policy* aPolicy) { 80 // Bug 1401666: Mesa driver loader part 2: Mesa <= 12 using libudev 81 // Used by libdrm, which is used by Mesa, and 82 // Intel(R) Media Driver for VAAPI. 83 if (auto dir = opendir("/dev/dri")) { 84 while (auto entry = readdir(dir)) { 85 if (entry->d_name[0] != '.') { 86 nsPrintfCString devPath("/dev/dri/%s", entry->d_name); 87 struct stat sb; 88 if (stat(devPath.get(), &sb) == 0 && S_ISCHR(sb.st_mode)) { 89 // For both the DRI node and its parent (the physical 90 // device), allow reading the "uevent" file. 91 static const Array<nsCString, 2> kSuffixes = {""_ns, "/device"_ns}; 92 nsPrintfCString prefix("/sys/dev/char/%u:%u", major(sb.st_rdev), 93 minor(sb.st_rdev)); 94 for (const auto& suffix : kSuffixes) { 95 nsCString sysPath(prefix + suffix); 96 97 // libudev will expand the symlink but not do full 98 // canonicalization, so it will leave in ".." path 99 // components that will be realpath()ed in the 100 // broker. To match this, allow the canonical paths. 101 UniqueFreePtr<char[]> realSysPath(realpath(sysPath.get(), nullptr)); 102 if (realSysPath) { 103 // https://gitlab.freedesktop.org/mesa/drm/-/commit/3988580e4c0f4b3647a0c6af138a3825453fe6e0 104 // > term = strrchr(real_path, '/'); 105 // > if (term && strncmp(term, "/virtio", 7) == 0) 106 // > *term = 0; 107 char* term = strrchr(realSysPath.get(), '/'); 108 if (term && strncmp(term, "/virtio", 7) == 0) { 109 *term = 0; 110 } 111 112 aPolicy->AddFilePrefix(rdonly, realSysPath.get(), ""); 113 // Allowing stat-ing and readlink-ing the parent dirs 114 nsPrintfCString basePath("%s/", realSysPath.get()); 115 aPolicy->AddAncestors(basePath.get(), rdonly); 116 } 117 } 118 119 // https://gitlab.freedesktop.org/mesa/drm/-/commit/a02900133b32dd4a7d6da4966f455ab337e80dfc 120 // > strncpy(path, device_path, PATH_MAX); 121 // > strncat(path, "/subsystem", PATH_MAX); 122 // > 123 // > if (readlink(path, link, PATH_MAX) < 0) 124 // > return -errno; 125 nsCString subsystemPath(prefix + "/device/subsystem"_ns); 126 aPolicy->AddPath(rdonly, subsystemPath.get()); 127 aPolicy->AddAncestors(subsystemPath.get(), rdonly); 128 } 129 } 130 } 131 closedir(dir); 132 } 133 134 // https://gitlab.freedesktop.org/mesa/mesa/-/commit/04bdbbcab3c4862bf3f54ce60fcc1d2007776f80 135 aPolicy->AddPath(rdonly, "/usr/share/drirc.d"); 136 137 // https://dri.freedesktop.org/wiki/ConfigurationInfrastructure/ 138 aPolicy->AddPath(rdonly, "/etc/drirc"); 139 140 nsCOMPtr<nsIFile> drirc; 141 nsresult rv = 142 GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(drirc)); 143 if (NS_SUCCEEDED(rv)) { 144 rv = drirc->AppendNative(".drirc"_ns); 145 if (NS_SUCCEEDED(rv)) { 146 nsAutoCString tmpPath; 147 rv = drirc->GetNativePath(tmpPath); 148 if (NS_SUCCEEDED(rv)) { 149 aPolicy->AddPath(rdonly, tmpPath.get()); 150 } 151 } 152 } 153 } 154 155 static void JoinPathIfRelative(const nsACString& aCwd, const nsACString& inPath, 156 nsACString& outPath) { 157 if (inPath.Length() < 1) { 158 outPath.Assign(aCwd); 159 SANDBOX_LOG("Unjoinable path: %s", PromiseFlatCString(aCwd).get()); 160 return; 161 } 162 const char* startChar = inPath.BeginReading(); 163 if (*startChar != '/') { 164 // Relative path, copy basepath in front 165 outPath.Assign(aCwd); 166 outPath.Append("/"); 167 outPath.Append(inPath); 168 } else { 169 // Absolute path, it's ok like this 170 outPath.Assign(inPath); 171 } 172 } 173 174 static void CachePathsFromFile(FileCacheT& aCache, const nsACString& aPath); 175 176 static void CachePathsFromFileInternal(FileCacheT& aCache, 177 const nsACString& aCwd, 178 const nsACString& aPath) { 179 nsresult rv; 180 nsCOMPtr<nsIFile> ldconfig; 181 rv = NS_NewNativeLocalFile(aPath, getter_AddRefs(ldconfig)); 182 if (NS_WARN_IF(NS_FAILED(rv))) { 183 return; 184 } 185 nsCOMPtr<nsIFileInputStream> fileStream( 186 do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv)); 187 if (NS_WARN_IF(NS_FAILED(rv))) { 188 return; 189 } 190 rv = fileStream->Init(ldconfig, -1, -1, 0); 191 if (NS_WARN_IF(NS_FAILED(rv))) { 192 return; 193 } 194 nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv)); 195 if (NS_WARN_IF(NS_FAILED(rv))) { 196 return; 197 } 198 199 nsAutoCString line; 200 bool more = true; 201 do { 202 rv = lineStream->ReadLine(line, &more); 203 if (NS_FAILED(rv)) { 204 break; 205 } 206 // Cut off any comments at the end of the line, also catches lines 207 // that are entirely a comment 208 int32_t hash = line.FindChar('#'); 209 if (hash >= 0) { 210 line = Substring(line, 0, hash); 211 } 212 // Simplify our following parsing by trimming whitespace 213 line.CompressWhitespace(true, true); 214 if (line.IsEmpty()) { 215 // Skip comment lines 216 continue; 217 } 218 // Check for any included files and recursively process 219 nsACString::const_iterator start, end, token_end; 220 221 line.BeginReading(start); 222 line.EndReading(end); 223 token_end = end; 224 225 if (FindInReadable("include "_ns, start, token_end)) { 226 nsAutoCString includes(Substring(token_end, end)); 227 for (const nsACString& includeGlob : includes.Split(' ')) { 228 // Glob path might be relative, so add cwd if so. 229 nsAutoCString includeFile; 230 JoinPathIfRelative(aCwd, includeGlob, includeFile); 231 glob_t globbuf; 232 if (!glob(PromiseFlatCString(includeFile).get(), GLOB_NOSORT, nullptr, 233 &globbuf)) { 234 for (size_t fileIdx = 0; fileIdx < globbuf.gl_pathc; fileIdx++) { 235 nsAutoCString filePath(globbuf.gl_pathv[fileIdx]); 236 CachePathsFromFile(aCache, filePath); 237 } 238 globfree(&globbuf); 239 } 240 } 241 } 242 243 // Cut off anything behind an = sign, used by dirname=TYPE directives 244 int32_t equals = line.FindChar('='); 245 if (equals >= 0) { 246 line = Substring(line, 0, equals); 247 } 248 char* resolvedPath = realpath(line.get(), nullptr); 249 if (resolvedPath) { 250 aCache.AppendElement(std::make_pair(nsCString(resolvedPath), rdonly)); 251 free(resolvedPath); 252 } 253 } while (more); 254 } 255 256 static void CachePathsFromFile(FileCacheT& aCache, const nsACString& aPath) { 257 // Find the new base path where that file sits in. 258 nsresult rv; 259 nsCOMPtr<nsIFile> includeFile; 260 rv = NS_NewNativeLocalFile(aPath, getter_AddRefs(includeFile)); 261 if (NS_WARN_IF(NS_FAILED(rv))) { 262 return; 263 } 264 if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) { 265 SANDBOX_LOG("Adding paths from %s to policy.", 266 PromiseFlatCString(aPath).get()); 267 } 268 269 // Find the parent dir where this file sits in. 270 nsCOMPtr<nsIFile> parentDir; 271 rv = includeFile->GetParent(getter_AddRefs(parentDir)); 272 if (NS_WARN_IF(NS_FAILED(rv))) { 273 return; 274 } 275 nsAutoCString parentPath; 276 rv = parentDir->GetNativePath(parentPath); 277 if (NS_WARN_IF(NS_FAILED(rv))) { 278 return; 279 } 280 if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) { 281 SANDBOX_LOG("Parent path is %s", PromiseFlatCString(parentPath).get()); 282 } 283 CachePathsFromFileInternal(aCache, parentPath, aPath); 284 } 285 286 static void AddLdconfigPaths(SandboxBroker::Policy* aPolicy) { 287 static StaticMutex sMutex; 288 StaticMutexAutoLock lock(sMutex); 289 290 static FileCacheT ldConfigCache{}; 291 static bool ldConfigCachePopulated = false; 292 if (!ldConfigCachePopulated) { 293 CachePathsFromFile(ldConfigCache, "/etc/ld.so.conf"_ns); 294 ldConfigCachePopulated = true; 295 RunOnShutdown([&] { 296 ldConfigCache.Clear(); 297 MOZ_ASSERT(ldConfigCache.IsEmpty(), "ldconfig cache should be empty"); 298 }); 299 } 300 for (const CacheE& e : ldConfigCache) { 301 aPolicy->AddTree(e.second, e.first.get()); 302 } 303 } 304 305 static void AddLdLibraryEnvPaths(SandboxBroker::Policy* aPolicy) { 306 nsAutoCString LdLibraryEnv(PR_GetEnv("LD_LIBRARY_PATH")); 307 // The items in LD_LIBRARY_PATH can be separated by either colons or 308 // semicolons, according to the ld.so(8) man page, and empirically it 309 // seems to be allowed to mix them (i.e., a:b;c is a list with 3 elements). 310 // There is no support for escaping the delimiters, fortunately (for us). 311 LdLibraryEnv.ReplaceChar(';', ':'); 312 for (const nsACString& libPath : LdLibraryEnv.Split(':')) { 313 char* resolvedPath = realpath(PromiseFlatCString(libPath).get(), nullptr); 314 if (resolvedPath) { 315 aPolicy->AddTree(rdonly, resolvedPath); 316 free(resolvedPath); 317 } 318 } 319 } 320 321 static void AddSharedMemoryPaths(SandboxBroker::Policy* aPolicy, pid_t aPid) { 322 std::string shmPath("/dev/shm"); 323 if (ipc::shared_memory::AppendPosixShmPrefix(&shmPath, aPid)) { 324 aPolicy->AddPrefix(rdwrcr, shmPath.c_str()); 325 } 326 } 327 328 static void AddMemoryReporting(SandboxBroker::Policy* aPolicy, pid_t aPid) { 329 // Bug 1198552: memory reporting. 330 // Bug 1647957: memory reporting. 331 aPolicy->AddPath(rdonly, nsPrintfCString("/proc/%d/statm", aPid).get()); 332 aPolicy->AddPath(rdonly, nsPrintfCString("/proc/%d/smaps", aPid).get()); 333 } 334 335 static void AddDynamicPathList(SandboxBroker::Policy* policy, 336 const char* aPathListPref, int perms) { 337 nsAutoCString pathList; 338 nsresult rv = Preferences::GetCString(aPathListPref, pathList); 339 if (NS_SUCCEEDED(rv)) { 340 for (const nsACString& path : pathList.Split(',')) { 341 nsCString trimPath(path); 342 trimPath.Trim(" ", true, true); 343 policy->AddDynamic(perms, trimPath.get()); 344 } 345 } 346 } 347 348 static void AddX11Dependencies(SandboxBroker::Policy* policy) { 349 // Allow Primus to contact the Bumblebee daemon to manage GPU 350 // switching on NVIDIA Optimus systems. 351 const char* bumblebeeSocket = PR_GetEnv("BUMBLEBEE_SOCKET"); 352 if (bumblebeeSocket == nullptr) { 353 bumblebeeSocket = "/var/run/bumblebee.socket"; 354 } 355 policy->AddPath(SandboxBroker::MAY_CONNECT, bumblebeeSocket); 356 357 #if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11) 358 // Allow local X11 connections, for several purposes: 359 // 360 // * for content processes to use WebGL when the browser is in headless 361 // mode, by opening the X display if/when needed 362 // 363 // * if Primus or VirtualGL is used, to contact the secondary X server 364 static const bool kIsX11 = 365 !mozilla::widget::GdkIsWaylandDisplay() && PR_GetEnv("DISPLAY"); 366 if (kIsX11) { 367 policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X"); 368 if (auto* const xauth = PR_GetEnv("XAUTHORITY")) { 369 policy->AddPath(rdonly, xauth); 370 } else if (auto* const home = PR_GetEnv("HOME")) { 371 // This follows the logic in libXau: append "/.Xauthority", 372 // even if $HOME ends in a slash, except in the special case 373 // where HOME=/ because POSIX allows implementations to treat 374 // an initial double slash specially. 375 nsAutoCString xauth(home); 376 if (xauth != "/"_ns) { 377 xauth.Append('/'); 378 } 379 xauth.AppendLiteral(".Xauthority"); 380 policy->AddPath(rdonly, xauth.get()); 381 } 382 } 383 #endif 384 } 385 386 static void AddGLDependencies(SandboxBroker::Policy* policy) { 387 // Devices 388 policy->AddTree(rdwr, "/dev/dri"); 389 policy->AddFilePrefix(rdwr, "/dev", "nvidia"); 390 391 // Hardware info 392 AddDriPaths(policy); 393 394 // /etc and /usr/share (glvnd, libdrm, drirc, ...?) 395 policy->AddTree(rdonly, "/etc"); 396 policy->AddTree(rdonly, "/usr/share"); 397 policy->AddTree(rdonly, "/usr/local/share"); 398 399 // Snap puts the usual /usr/share things in a different place, and 400 // we'll fail to load the library if we don't have (at least) the 401 // glvnd config: 402 if (const char* snapDesktopDir = PR_GetEnv("SNAP_DESKTOP_RUNTIME")) { 403 nsAutoCString snapDesktopShare(snapDesktopDir); 404 snapDesktopShare.AppendLiteral("/usr/share"); 405 policy->AddTree(rdonly, snapDesktopShare.get()); 406 } 407 408 // Introduced by Snap's core24 changes there is a gpu-2404 dependency and 409 // it is recommended to allow access to all of it? 410 if (const char* snapRoot = PR_GetEnv("SNAP")) { 411 nsAutoCString snapRootString(snapRoot); 412 snapRootString.AppendLiteral("/gpu-2404"); 413 policy->AddTree(rdonly, snapRootString.get()); 414 } 415 416 // Note: This function doesn't do anything about Mesa's shader 417 // cache, because the details can vary by process type, including 418 // whether caching is enabled. 419 420 // This also doesn't include permissions for connecting to a display 421 // server, because headless GL (e.g., Mesa GBM) may not need it. 422 } 423 424 // Assums this is an absolute path, SandboxBroker does not like relative paths: 425 // RealPath() will try to get the absolute path of the llvm profile path to open 426 // for writing but this will return errno=2 because the file does not exists, so 427 // sandbox will not allow for its creation. 428 // 429 // Forcing expecting an absolute path will be enough to make sure it can be 430 // allowed. 431 // 432 // It should only be allowed on instrumented builds, never on production 433 // builds. 434 #if defined(MOZ_PROFILE_GENERATE) 435 static void AddLLVMProfilePathDirectory(SandboxBroker::Policy* aPolicy) { 436 std::string parentPath; 437 if (GetLlvmProfileDir(parentPath)) { 438 aPolicy->AddFutureDir(rdwrcr, parentPath.c_str()); 439 } 440 } 441 #endif // defined(MOZ_PROFILE_GENERATE) 442 443 // Make sure the path read from environment is correct (absolute). 444 const char* PathFromEnvIfAbsolute(const char* aPath) { 445 const char* envValue = PR_GetEnv(aPath); 446 if (envValue && envValue[0] == '/') { 447 return envValue; 448 } 449 return nullptr; 450 } 451 452 void SandboxBrokerPolicyFactory::InitContentPolicy() { 453 const int level = GetEffectiveContentSandboxLevel(); 454 const bool headless = level >= 5; 455 456 // Policy entries that are the same in every process go here, and 457 // are cached over the lifetime of the factory. 458 SandboxBroker::Policy* policy = new SandboxBroker::Policy; 459 // Write permssions 460 461 // Bug 1575985: WASM library sandbox needs RW access to /dev/null 462 policy->AddPath(rdwr, "/dev/null"); 463 464 if (!headless) { 465 AddGLDependencies(policy); 466 AddX11Dependencies(policy); 467 } 468 469 // Read permissions 470 policy->AddPath(rdonly, "/dev/urandom"); 471 policy->AddPath(rdonly, "/dev/random"); 472 policy->AddPath(rdonly, "/proc/sys/crypto/fips_enabled"); 473 policy->AddPath(rdonly, "/proc/cpuinfo"); 474 policy->AddPath(rdonly, "/proc/meminfo"); 475 policy->AddTree(rdonly, "/sys/devices/cpu"); 476 policy->AddTree(rdonly, "/sys/devices/system/cpu"); 477 policy->AddTree(rdonly, "/lib"); 478 policy->AddTree(rdonly, "/lib64"); 479 policy->AddTree(rdonly, "/usr/lib"); 480 policy->AddTree(rdonly, "/usr/lib32"); 481 policy->AddTree(rdonly, "/usr/lib64"); 482 policy->AddTree(rdonly, "/etc"); 483 policy->AddTree(rdonly, "/usr/share"); 484 policy->AddTree(rdonly, "/usr/local/share"); 485 // Various places where fonts reside 486 policy->AddTree(rdonly, "/usr/X11R6/lib/X11/fonts"); 487 policy->AddTree(rdonly, "/nix/store"); 488 // https://gitlab.com/freedesktop-sdk/freedesktop-sdk/-/blob/e434e680d22260f277f4a30ec4660ed32b591d16/files/fontconfig-flatpak.conf 489 policy->AddTree(rdonly, "/run/host/fonts"); 490 policy->AddTree(rdonly, "/run/host/user-fonts"); 491 policy->AddTree(rdonly, "/run/host/local-fonts"); 492 policy->AddTree(rdonly, "/var/cache/fontconfig"); 493 494 // Bug 1848615 495 policy->AddPath(rdonly, "/usr"); 496 policy->AddPath(rdonly, "/nix"); 497 498 AddLdconfigPaths(policy); 499 AddLdLibraryEnvPaths(policy); 500 501 if (!headless) { 502 // Bug 1385715: NVIDIA PRIME support 503 policy->AddPath(rdonly, "/proc/modules"); 504 } 505 506 // XDG directories might be non existent according to specs: 507 // https://specifications.freedesktop.org/basedir-spec/0.8/ar01s04.html 508 // 509 // > If, when attempting to write a file, the destination directory is 510 // > non-existent an attempt should be made to create it with permission 0700. 511 // 512 // For that we use AddPath(, SandboxBroker::Policy::AddCondition::AddAlways). 513 // 514 // Allow access to XDG_CONFIG_HOME and XDG_CONFIG_DIRS 515 nsAutoCString xdgConfigHome(PathFromEnvIfAbsolute("XDG_CONFIG_HOME")); 516 if (!xdgConfigHome.IsEmpty()) { // AddPath will fail on empty strings 517 policy->AddFutureDir(rdonly, xdgConfigHome.get()); 518 } 519 520 nsAutoCString xdgConfigDirs(PR_GetEnv("XDG_CONFIG_DIRS")); 521 for (const auto& path : xdgConfigDirs.Split(':')) { 522 if (path[0] != '/') { 523 continue; 524 } 525 526 if (!path.IsEmpty()) { // AddPath will fail on empty strings 527 policy->AddFutureDir(rdonly, PromiseFlatCString(path).get()); 528 } 529 } 530 531 // Allow fonts subdir in XDG_DATA_HOME 532 nsAutoCString xdgDataHome(PathFromEnvIfAbsolute("XDG_DATA_HOME")); 533 if (!xdgDataHome.IsEmpty()) { 534 nsAutoCString fontPath(xdgDataHome); 535 fontPath.Append("/fonts"); 536 policy->AddFutureDir(rdonly, PromiseFlatCString(fontPath).get()); 537 } 538 539 // Any font subdirs in XDG_DATA_DIRS 540 nsAutoCString xdgDataDirs(PR_GetEnv("XDG_DATA_DIRS")); 541 for (const auto& path : xdgDataDirs.Split(':')) { 542 if (path[0] != '/') { 543 continue; 544 } 545 546 nsAutoCString fontPath(path); 547 fontPath.Append("/fonts"); 548 policy->AddFutureDir(rdonly, PromiseFlatCString(fontPath).get()); 549 } 550 551 // Extra configuration/cache dirs in the homedir that we want to allow read 552 // access to. 553 std::vector<const char*> extraConfDirsAllow = { 554 ".themes", 555 ".fonts", 556 ".cache/fontconfig", 557 }; 558 559 // Fallback if XDG_CONFIG_HOME isn't set 560 if (xdgConfigHome.IsEmpty()) { 561 extraConfDirsAllow.emplace_back(".config"); 562 } 563 564 nsCOMPtr<nsIFile> homeDir; 565 nsresult rv = 566 GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(homeDir)); 567 if (NS_SUCCEEDED(rv)) { 568 nsCOMPtr<nsIFile> confDir; 569 570 for (const auto& dir : extraConfDirsAllow) { 571 rv = homeDir->Clone(getter_AddRefs(confDir)); 572 if (NS_SUCCEEDED(rv)) { 573 rv = confDir->AppendRelativeNativePath(nsDependentCString(dir)); 574 if (NS_SUCCEEDED(rv)) { 575 nsAutoCString tmpPath; 576 rv = confDir->GetNativePath(tmpPath); 577 if (NS_SUCCEEDED(rv)) { 578 policy->AddTree(rdonly, tmpPath.get()); 579 } 580 } 581 } 582 } 583 584 // ~/.config/mozilla/ needs to be manually blocked, because the previous 585 // loop will allow for ~/.config/ access. 586 { 587 // If $XDG_CONFIG_HOME is set, we need to account for it. 588 // FIXME: Bug 1722272: Maybe this should just be handled with 589 // GetSpecialSystemDirectory(Unix_XDG_ConfigHome) ? 590 nsCOMPtr<nsIFile> confDirOrXDGConfigHomeDir; 591 if (!xdgConfigHome.IsEmpty()) { 592 rv = NS_NewNativeLocalFile(xdgConfigHome, 593 getter_AddRefs(confDirOrXDGConfigHomeDir)); 594 // confDirOrXDGConfigHomeDir = nsIFile($XDG_CONFIG_HOME) 595 } else { 596 rv = homeDir->Clone(getter_AddRefs(confDirOrXDGConfigHomeDir)); 597 if (NS_SUCCEEDED(rv)) { 598 // since we will use that later, we dont need to care about trailing 599 // slash 600 rv = confDirOrXDGConfigHomeDir->AppendNative(".config"_ns); 601 // confDirOrXDGConfigHomeDir = nsIFile($HOME/.config/) 602 } 603 } 604 605 if (NS_SUCCEEDED(rv)) { 606 rv = confDirOrXDGConfigHomeDir->AppendNative("mozilla"_ns); 607 if (NS_SUCCEEDED(rv)) { 608 nsAutoCString tmpPath; 609 rv = confDirOrXDGConfigHomeDir->GetNativePath(tmpPath); 610 if (NS_SUCCEEDED(rv)) { 611 policy->AddFutureDir(deny, tmpPath.get()); 612 } 613 } 614 } 615 } 616 617 // ~/.local/share (for themes) 618 rv = homeDir->Clone(getter_AddRefs(confDir)); 619 if (NS_SUCCEEDED(rv)) { 620 rv = confDir->AppendNative(".local"_ns); 621 if (NS_SUCCEEDED(rv)) { 622 rv = confDir->AppendNative("share"_ns); 623 } 624 if (NS_SUCCEEDED(rv)) { 625 nsAutoCString tmpPath; 626 rv = confDir->GetNativePath(tmpPath); 627 if (NS_SUCCEEDED(rv)) { 628 policy->AddTree(rdonly, tmpPath.get()); 629 } 630 } 631 } 632 633 // ~/.fonts.conf (Fontconfig) 634 rv = homeDir->Clone(getter_AddRefs(confDir)); 635 if (NS_SUCCEEDED(rv)) { 636 rv = confDir->AppendNative(".fonts.conf"_ns); 637 if (NS_SUCCEEDED(rv)) { 638 nsAutoCString tmpPath; 639 rv = confDir->GetNativePath(tmpPath); 640 if (NS_SUCCEEDED(rv)) { 641 policy->AddPath(rdonly, tmpPath.get()); 642 } 643 } 644 } 645 646 // .pangorc 647 rv = homeDir->Clone(getter_AddRefs(confDir)); 648 if (NS_SUCCEEDED(rv)) { 649 rv = confDir->AppendNative(".pangorc"_ns); 650 if (NS_SUCCEEDED(rv)) { 651 nsAutoCString tmpPath; 652 rv = confDir->GetNativePath(tmpPath); 653 if (NS_SUCCEEDED(rv)) { 654 policy->AddPath(rdonly, tmpPath.get()); 655 } 656 } 657 } 658 } 659 660 // Firefox binary dir. 661 // Note that unlike the previous cases, we use NS_GetSpecialDirectory 662 // instead of GetSpecialSystemDirectory. The former requires a working XPCOM 663 // system, which may not be the case for some tests. For querying for the 664 // location of XPCOM things, we can use it anyway. 665 nsCOMPtr<nsIFile> ffDir; 666 rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(ffDir)); 667 if (NS_SUCCEEDED(rv)) { 668 nsAutoCString tmpPath; 669 rv = ffDir->GetNativePath(tmpPath); 670 if (NS_SUCCEEDED(rv)) { 671 policy->AddTree(rdonly, tmpPath.get()); 672 } 673 } 674 675 if (!mozilla::IsPackagedBuild()) { 676 // If this is not a packaged build the resources are likely symlinks to 677 // outside the binary dir. Therefore in non-release builds we allow reads 678 // from the whole repository. MOZ_DEVELOPER_REPO_DIR is set by mach run. 679 const char* developer_repo_dir = PR_GetEnv("MOZ_DEVELOPER_REPO_DIR"); 680 if (developer_repo_dir) { 681 policy->AddTree(rdonly, developer_repo_dir); 682 } 683 } 684 685 #ifdef DEBUG 686 char* bloatLog = PR_GetEnv("XPCOM_MEM_BLOAT_LOG"); 687 // XPCOM_MEM_BLOAT_LOG has the format 688 // /tmp/tmpd0YzFZ.mozrunner/runtests_leaks.log 689 // but stores into /tmp/tmpd0YzFZ.mozrunner/runtests_leaks_tab_pid3411.log 690 // So cut the .log part and whitelist the prefix. 691 if (bloatLog != nullptr) { 692 size_t bloatLen = strlen(bloatLog); 693 if (bloatLen >= 4) { 694 nsAutoCString bloatStr(bloatLog); 695 bloatStr.Truncate(bloatLen - 4); 696 policy->AddPrefix(rdwrcr, bloatStr.get()); 697 } 698 } 699 #endif 700 701 if (!headless) { 702 AddX11Dependencies(policy); 703 } 704 705 // Bug 1732580: when packaged as a strictly confined snap, may need 706 // read-access to configuration files under $SNAP/. 707 const char* snap = PR_GetEnv("SNAP"); 708 if (snap) { 709 // When running as a snap, the directory pointed to by $SNAP is guaranteed 710 // to exist before the app is launched, but unit tests need to create it 711 // dynamically, hence the use of AddFutureDir(). 712 policy->AddTree(rdonly, snap); 713 } 714 715 // Read any extra paths that will get write permissions, 716 // configured by the user or distro 717 AddDynamicPathList(policy, "security.sandbox.content.write_path_whitelist", 718 rdwr); 719 720 // Whitelisted for reading by the user/distro 721 AddDynamicPathList(policy, "security.sandbox.content.read_path_whitelist", 722 rdonly); 723 724 // userContent.css and the extensions dir sit in the profile, which is 725 // normally blocked. 726 nsCOMPtr<nsIFile> profileDir; 727 rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, 728 getter_AddRefs(profileDir)); 729 if (NS_SUCCEEDED(rv)) { 730 nsCOMPtr<nsIFile> workDir; 731 rv = profileDir->Clone(getter_AddRefs(workDir)); 732 if (NS_SUCCEEDED(rv)) { 733 rv = workDir->AppendNative("chrome"_ns); 734 if (NS_SUCCEEDED(rv)) { 735 nsAutoCString tmpPath; 736 rv = workDir->GetNativePath(tmpPath); 737 if (NS_SUCCEEDED(rv)) { 738 policy->AddTree(rdonly, tmpPath.get()); 739 } 740 } 741 } 742 rv = profileDir->Clone(getter_AddRefs(workDir)); 743 if (NS_SUCCEEDED(rv)) { 744 rv = workDir->AppendNative("extensions"_ns); 745 if (NS_SUCCEEDED(rv)) { 746 nsAutoCString tmpPath; 747 rv = workDir->GetNativePath(tmpPath); 748 if (NS_SUCCEEDED(rv)) { 749 bool exists; 750 rv = workDir->Exists(&exists); 751 if (NS_SUCCEEDED(rv)) { 752 if (!exists) { 753 policy->AddPrefix(rdonly, tmpPath.get()); 754 policy->AddPath(rdonly, tmpPath.get()); 755 } else { 756 policy->AddTree(rdonly, tmpPath.get()); 757 } 758 } 759 } 760 } 761 } 762 } 763 764 bool allowPulse = false; 765 bool allowAlsa = false; 766 if (level < 4) { 767 #ifdef MOZ_PULSEAUDIO 768 allowPulse = true; 769 #endif 770 #ifdef MOZ_ALSA 771 allowAlsa = true; 772 #endif 773 } 774 775 if (allowAlsa) { 776 // Bug 1309098: ALSA support 777 policy->AddTree(rdwr, "/dev/snd"); 778 } 779 780 if (allowPulse) { 781 policy->AddTree(rdwrcr, "/dev/shm"); 782 } 783 784 #ifdef MOZ_WIDGET_GTK 785 if (const auto userDir = g_get_user_runtime_dir()) { 786 // Bug 1321134: DConf's single bit of shared memory 787 // The leaf filename is "user" by default, but is configurable. 788 nsPrintfCString shmPath("%s/dconf/", userDir); 789 policy->AddPrefix(rdwrcr, shmPath.get()); 790 policy->AddAncestors(shmPath.get()); 791 if (allowPulse) { 792 // PulseAudio, if it can't get server info from X11, will break 793 // unless it can open this directory (or create it, but in our use 794 // case we know it already exists). See bug 1335329. 795 nsPrintfCString pulsePath("%s/pulse", userDir); 796 policy->AddPath(rdonly, pulsePath.get()); 797 } 798 } 799 #endif // MOZ_WIDGET_GTK 800 801 if (allowPulse) { 802 // PulseAudio also needs access to read the $XAUTHORITY file (see 803 // bug 1384986 comment #1), but that's already allowed for hybrid 804 // GPU drivers (see above). 805 policy->AddPath(rdonly, "/var/lib/dbus/machine-id"); 806 } 807 808 // Bug 1434711 - AMDGPU-PRO crashes if it can't read it's marketing ids 809 // and various other things 810 if (!headless && HasAtiDrivers()) { 811 policy->AddTree(rdonly, "/opt/amdgpu/share"); 812 policy->AddPath(rdonly, "/sys/module/amdgpu"); 813 } 814 815 #if defined(MOZ_PROFILE_GENERATE) 816 AddLLVMProfilePathDirectory(policy); 817 #endif 818 819 mCommonContentPolicy.reset(policy); 820 } 821 822 UniquePtr<SandboxBroker::Policy> SandboxBrokerPolicyFactory::GetContentPolicy( 823 int aPid, bool aFileProcess) { 824 // Policy entries that vary per-process (because they depend on the 825 // pid or content subtype) are added here. 826 827 MOZ_ASSERT(NS_IsMainThread()); 828 829 const int level = GetEffectiveContentSandboxLevel(); 830 // The file broker is used at level 2 and up. 831 if (level <= 1) { 832 // Level 1 has been removed. 833 MOZ_ASSERT(level == 0); 834 return nullptr; 835 } 836 837 std::call_once(mContentInited, [this] { InitContentPolicy(); }); 838 MOZ_ASSERT(mCommonContentPolicy); 839 UniquePtr<SandboxBroker::Policy> policy( 840 new SandboxBroker::Policy(*mCommonContentPolicy)); 841 842 // No read blocking at level 2 and below. 843 // file:// processes also get global read permissions 844 if (level <= 2 || aFileProcess) { 845 policy->AddTree(rdonly, "/"); 846 // Any other read-only rules will be removed as redundant by 847 // Policy::FixRecursivePermissions, so there's no need to 848 // early-return here. 849 } 850 851 // Access to /dev/shm is restricted to a per-process prefix to 852 // prevent interfering with other processes or with services outside 853 // the browser (e.g., PulseAudio). 854 AddSharedMemoryPaths(policy.get(), aPid); 855 856 // Bug 1198550: the profiler's replacement for dl_iterate_phdr 857 policy->AddPath(rdonly, nsPrintfCString("/proc/%d/maps", aPid).get()); 858 859 // Bug 1736040: CPU use telemetry 860 policy->AddPath(rdonly, nsPrintfCString("/proc/%d/stat", aPid).get()); 861 862 // Bug 1198552: memory reporting. 863 AddMemoryReporting(policy.get(), aPid); 864 865 // Bug 1384804, notably comment 15 866 // Used by libnuma, included by x265/ffmpeg, who falls back 867 // to get_mempolicy if this fails 868 policy->AddPath(rdonly, nsPrintfCString("/proc/%d/status", aPid).get()); 869 870 // Finalize the policy. 871 policy->FixRecursivePermissions(); 872 return policy; 873 } 874 875 #ifdef MOZ_ENABLE_V4L2 876 static void AddV4l2Dependencies(SandboxBroker::Policy* policy) { 877 // For V4L2 hardware-accelerated video decode, RDD needs access to certain 878 // /dev/video* devices but don't want to allow it access to webcams etc. 879 // So we only allow it access to M2M video devices (encoders and decoders). 880 DIR* dir = opendir("/dev"); 881 if (!dir) { 882 SANDBOX_LOG("Couldn't list /dev"); 883 return; 884 } 885 886 struct dirent* dir_entry; 887 while ((dir_entry = readdir(dir))) { 888 if (strncmp(dir_entry->d_name, "video", 5)) { 889 // Not a /dev/video* device, so ignore it 890 continue; 891 } 892 893 nsCString path = "/dev/"_ns; 894 path += nsDependentCString(dir_entry->d_name); 895 896 int fd = open(path.get(), O_RDWR | O_NONBLOCK, 0); 897 if (fd < 0) { 898 // Couldn't open this device, so ignore it. 899 SANDBOX_LOG("Couldn't open video device %s", path.get()); 900 continue; 901 } 902 903 // Query device capabilities 904 struct v4l2_capability cap; 905 int result = ioctl(fd, VIDIOC_QUERYCAP, &cap); 906 if (result < 0) { 907 // Couldn't query capabilities of this device, so ignore it 908 SANDBOX_LOG("Couldn't query capabilities of video device %s", path.get()); 909 close(fd); 910 continue; 911 } 912 913 if ((cap.device_caps & V4L2_CAP_VIDEO_M2M) || 914 (cap.device_caps & V4L2_CAP_VIDEO_M2M_MPLANE)) { 915 // This is an M2M device (i.e. not a webcam), so allow access 916 policy->AddPath(rdwr, path.get()); 917 } 918 919 close(fd); 920 } 921 closedir(dir); 922 923 // FFmpeg V4L2 needs to list /dev to find V4L2 devices. 924 policy->AddPath(rdonly, "/dev"); 925 } 926 #endif // MOZ_ENABLE_V4L2 927 928 /* static */ UniquePtr<SandboxBroker::Policy> 929 SandboxBrokerPolicyFactory::GetRDDPolicy(int aPid) { 930 auto policy = MakeUnique<SandboxBroker::Policy>(); 931 932 AddSharedMemoryPaths(policy.get(), aPid); 933 934 policy->AddPath(rdonly, "/dev/urandom"); 935 // FIXME (bug 1662321): we should fix nsSystemInfo so that every 936 // child process doesn't need to re-read these files to get the info 937 // the parent process already has. 938 policy->AddPath(rdonly, "/proc/cpuinfo"); 939 policy->AddPath(rdonly, 940 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"); 941 policy->AddPath(rdonly, "/sys/devices/system/cpu/cpu0/cache/index2/size"); 942 policy->AddPath(rdonly, "/sys/devices/system/cpu/cpu0/cache/index3/size"); 943 policy->AddTree(rdonly, "/sys/devices/cpu"); 944 policy->AddTree(rdonly, "/sys/devices/system/cpu"); 945 policy->AddTree(rdonly, "/sys/devices/system/node"); 946 policy->AddTree(rdonly, "/lib"); 947 policy->AddTree(rdonly, "/lib64"); 948 policy->AddTree(rdonly, "/usr/lib"); 949 policy->AddTree(rdonly, "/usr/lib32"); 950 policy->AddTree(rdonly, "/usr/lib64"); 951 policy->AddTree(rdonly, "/run/opengl-driver/lib"); 952 policy->AddTree(rdonly, "/nix/store"); 953 954 // Bug 1647957: memory reporting. 955 AddMemoryReporting(policy.get(), aPid); 956 957 // Firefox binary dir. 958 // Note that unlike the previous cases, we use NS_GetSpecialDirectory 959 // instead of GetSpecialSystemDirectory. The former requires a working XPCOM 960 // system, which may not be the case for some tests. For querying for the 961 // location of XPCOM things, we can use it anyway. 962 nsCOMPtr<nsIFile> ffDir; 963 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(ffDir)); 964 if (NS_SUCCEEDED(rv)) { 965 nsAutoCString tmpPath; 966 rv = ffDir->GetNativePath(tmpPath); 967 if (NS_SUCCEEDED(rv)) { 968 policy->AddTree(rdonly, tmpPath.get()); 969 } 970 } 971 972 if (!mozilla::IsPackagedBuild()) { 973 // If this is not a packaged build the resources are likely symlinks to 974 // outside the binary dir. Therefore in non-release builds we allow reads 975 // from the whole repository. MOZ_DEVELOPER_REPO_DIR is set by mach run. 976 const char* developer_repo_dir = PR_GetEnv("MOZ_DEVELOPER_REPO_DIR"); 977 if (developer_repo_dir) { 978 policy->AddTree(rdonly, developer_repo_dir); 979 } 980 } 981 982 // VA-API needs GPU access and GL context creation (but not display 983 // server access, as of bug 1769499). 984 AddGLDependencies(policy.get()); 985 986 // FFmpeg and GPU drivers may need general-case library loading 987 AddLdconfigPaths(policy.get()); 988 AddLdLibraryEnvPaths(policy.get()); 989 990 #ifdef MOZ_ENABLE_V4L2 991 AddV4l2Dependencies(policy.get()); 992 #endif // MOZ_ENABLE_V4L2 993 994 // Bug 1903688: NVIDIA Tegra hardware decoding from Linux4Tegra 995 // Only built on ARM64 since Tegra is ARM64 SoC with different drivers, so the 996 // path are not needed on e.g. x86-64 997 #if defined(__aarch64__) 998 policy->AddTree(rdonly, "/sys/devices/system/present"); 999 policy->AddTree(rdonly, "/sys/module/tegra_fuse"); 1000 policy->AddPath(rdwr, "/dev/nvmap"); 1001 policy->AddPath(rdwr, "/dev/nvhost-ctrl"); 1002 policy->AddPath(rdwr, "/dev/nvhost-ctrl-gpu"); 1003 policy->AddPath(rdwr, "/dev/nvhost-nvdec"); 1004 policy->AddPath(rdwr, "/dev/nvhost-nvdec1"); 1005 policy->AddPath(rdwr, "/dev/nvhost-vic"); 1006 #endif // defined(__aarch64__) 1007 1008 #if defined(MOZ_PROFILE_GENERATE) 1009 AddLLVMProfilePathDirectory(policy.get()); 1010 #endif 1011 1012 if (policy->IsEmpty()) { 1013 policy = nullptr; 1014 } 1015 return policy; 1016 } 1017 1018 /* static */ UniquePtr<SandboxBroker::Policy> 1019 SandboxBrokerPolicyFactory::GetSocketProcessPolicy(int aPid) { 1020 auto policy = MakeUnique<SandboxBroker::Policy>(); 1021 1022 policy->AddPath(rdonly, "/dev/urandom"); 1023 policy->AddPath(rdonly, "/dev/random"); 1024 policy->AddPath(rdonly, "/proc/sys/crypto/fips_enabled"); 1025 policy->AddPath(rdonly, "/proc/cpuinfo"); 1026 policy->AddPath(rdonly, "/proc/meminfo"); 1027 policy->AddTree(rdonly, "/sys/devices/cpu"); 1028 policy->AddTree(rdonly, "/sys/devices/system/cpu"); 1029 policy->AddTree(rdonly, "/lib"); 1030 policy->AddTree(rdonly, "/lib64"); 1031 policy->AddTree(rdonly, "/usr/lib"); 1032 policy->AddTree(rdonly, "/usr/lib32"); 1033 policy->AddTree(rdonly, "/usr/lib64"); 1034 policy->AddTree(rdonly, "/usr/share"); 1035 policy->AddTree(rdonly, "/usr/local/share"); 1036 policy->AddTree(rdonly, "/etc"); 1037 1038 // glibc will try to stat64("/") while populating nsswitch database 1039 // https://sourceware.org/git/?p=glibc.git;a=blob;f=nss/nss_database.c;h=cf0306adc47f12d9bc761ab1b013629f4482b7e6;hb=9826b03b747b841f5fc6de2054bf1ef3f5c4bdf3#l396 1040 // denying will make getaddrinfo() return ENONAME 1041 policy->AddPath(access, "/"); 1042 1043 AddLdconfigPaths(policy.get()); 1044 1045 // Socket process sandbox needs to allow shmem in order to support 1046 // profiling. See Bug 1626385. 1047 AddSharedMemoryPaths(policy.get(), aPid); 1048 1049 // Bug 1647957: memory reporting. 1050 AddMemoryReporting(policy.get(), aPid); 1051 1052 // Firefox binary dir. 1053 // Note that unlike the previous cases, we use NS_GetSpecialDirectory 1054 // instead of GetSpecialSystemDirectory. The former requires a working XPCOM 1055 // system, which may not be the case for some tests. For querying for the 1056 // location of XPCOM things, we can use it anyway. 1057 nsCOMPtr<nsIFile> ffDir; 1058 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(ffDir)); 1059 if (NS_SUCCEEDED(rv)) { 1060 nsAutoCString tmpPath; 1061 rv = ffDir->GetNativePath(tmpPath); 1062 if (NS_SUCCEEDED(rv)) { 1063 policy->AddTree(rdonly, tmpPath.get()); 1064 } 1065 } 1066 1067 #if defined(MOZ_PROFILE_GENERATE) 1068 AddLLVMProfilePathDirectory(policy.get()); 1069 #endif 1070 1071 if (policy->IsEmpty()) { 1072 policy = nullptr; 1073 } 1074 return policy; 1075 } 1076 1077 /* static */ UniquePtr<SandboxBroker::Policy> 1078 SandboxBrokerPolicyFactory::GetUtilityProcessPolicy(int aPid) { 1079 auto policy = MakeUnique<SandboxBroker::Policy>(); 1080 1081 policy->AddPath(rdonly, "/dev/urandom"); 1082 policy->AddPath(rdonly, "/proc/cpuinfo"); 1083 policy->AddPath(rdonly, "/proc/meminfo"); 1084 policy->AddPath(rdonly, nsPrintfCString("/proc/%d/exe", aPid).get()); 1085 policy->AddTree(rdonly, "/sys/devices/cpu"); 1086 policy->AddTree(rdonly, "/sys/devices/system/cpu"); 1087 policy->AddTree(rdonly, "/lib"); 1088 policy->AddTree(rdonly, "/lib64"); 1089 policy->AddTree(rdonly, "/usr/lib"); 1090 policy->AddTree(rdonly, "/usr/lib32"); 1091 policy->AddTree(rdonly, "/usr/lib64"); 1092 policy->AddTree(rdonly, "/usr/share"); 1093 policy->AddTree(rdonly, "/usr/local/share"); 1094 policy->AddTree(rdonly, "/etc"); 1095 // Required to make sure ffmpeg loads properly, this is already existing on 1096 // Content and RDD 1097 policy->AddTree(rdonly, "/nix/store"); 1098 1099 // glibc will try to stat64("/") while populating nsswitch database 1100 // https://sourceware.org/git/?p=glibc.git;a=blob;f=nss/nss_database.c;h=cf0306adc47f12d9bc761ab1b013629f4482b7e6;hb=9826b03b747b841f5fc6de2054bf1ef3f5c4bdf3#l396 1101 // denying will make getaddrinfo() return ENONAME 1102 policy->AddPath(access, "/"); 1103 1104 AddLdconfigPaths(policy.get()); 1105 AddLdLibraryEnvPaths(policy.get()); 1106 1107 // Utility process sandbox needs to allow shmem in order to support 1108 // profiling. See Bug 1626385. 1109 AddSharedMemoryPaths(policy.get(), aPid); 1110 1111 // Bug 1647957: memory reporting. 1112 AddMemoryReporting(policy.get(), aPid); 1113 1114 // Firefox binary dir. 1115 // Note that unlike the previous cases, we use NS_GetSpecialDirectory 1116 // instead of GetSpecialSystemDirectory. The former requires a working XPCOM 1117 // system, which may not be the case for some tests. For querying for the 1118 // location of XPCOM things, we can use it anyway. 1119 nsCOMPtr<nsIFile> ffDir; 1120 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(ffDir)); 1121 if (NS_SUCCEEDED(rv)) { 1122 nsAutoCString tmpPath; 1123 rv = ffDir->GetNativePath(tmpPath); 1124 if (NS_SUCCEEDED(rv)) { 1125 policy->AddTree(rdonly, tmpPath.get()); 1126 } 1127 } 1128 1129 #if defined(MOZ_PROFILE_GENERATE) 1130 AddLLVMProfilePathDirectory(policy.get()); 1131 #endif 1132 1133 if (policy->IsEmpty()) { 1134 policy = nullptr; 1135 } 1136 return policy; 1137 } 1138 1139 } // namespace mozilla