tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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