summaryrefslogtreecommitdiffstats
path: root/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
blob: 8e698606ed0c5d0e4d1966cf9f0897d05f9ebc6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "SandboxBrokerPolicyFactory.h"
#include "SandboxInfo.h"

#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "SpecialSystemDirectory.h"

#ifdef ANDROID
#include "cutils/properties.h"
#endif

namespace mozilla {

/* static */ bool
SandboxBrokerPolicyFactory::IsSystemSupported() {
#ifdef ANDROID
  char hardware[PROPERTY_VALUE_MAX];
  int length = property_get("ro.hardware", hardware, nullptr);
  // "goldfish" -> emulator.  Other devices can be added when we're
  // reasonably sure they work.  Eventually this won't be needed....
  if (length > 0 && strcmp(hardware, "goldfish") == 0) {
    return true;
  }

  // When broker is running in permissive mode, we enable it
  // automatically regardless of the device.
  if (SandboxInfo::Get().Test(SandboxInfo::kPermissive)) {
    return true;
  }
#endif
  return false;
}

#if defined(MOZ_CONTENT_SANDBOX)
namespace {
static const int rdonly = SandboxBroker::MAY_READ;
static const int wronly = SandboxBroker::MAY_WRITE;
static const int rdwr = rdonly | wronly;
static const int rdwrcr = rdwr | SandboxBroker::MAY_CREATE;
#if defined(MOZ_WIDGET_GONK)
static const int wrlog = wronly | SandboxBroker::MAY_CREATE;
#endif
}
#endif

SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
{
  // Policy entries that are the same in every process go here, and
  // are cached over the lifetime of the factory.
#if defined(MOZ_CONTENT_SANDBOX) && defined(MOZ_WIDGET_GONK)
  SandboxBroker::Policy* policy = new SandboxBroker::Policy;

  // Devices that need write access:
  policy->AddPath(rdwr, "/dev/genlock");  // bug 980924
  policy->AddPath(rdwr, "/dev/ashmem");   // bug 980947
  policy->AddTree(wronly, "/dev/log"); // bug 1199857
  // Graphics devices are a significant source of attack surface, but
  // there's not much we can do about it without proxying (which is
  // very difficult and a perforamnce hit).
  policy->AddPrefix(rdwr, "/dev", "kgsl");  // bug 995072
  policy->AddPath(rdwr, "/dev/qemu_pipe"); // but 1198410: goldfish gralloc.

  // Bug 1198475: mochitest logs.  (This is actually passed in via URL
  // query param to the mochitest page, and is configurable, so this
  // isn't enough in general, but hopefully it's good enough for B2G.)
  // Conditional on tests being run, using the same check seen in
  // DirectoryProvider.js to set ProfD.
  if (access("/data/local/tests/profile", R_OK) == 0) {
    policy->AddPath(wrlog, "/data/local/tests/log/mochitest.log");
  }

  // Read-only items below this line.

  policy->AddPath(rdonly, "/dev/urandom");  // bug 964500, bug 995069
  policy->AddPath(rdonly, "/dev/ion");      // bug 980937
  policy->AddPath(rdonly, "/proc/cpuinfo"); // bug 995067
  policy->AddPath(rdonly, "/proc/meminfo"); // bug 1025333
  policy->AddPath(rdonly, "/sys/devices/system/cpu/present"); // bug 1025329
  policy->AddPath(rdonly, "/sys/devices/system/soc/soc0/id"); // bug 1025339
  policy->AddPath(rdonly, "/etc/media_profiles.xml"); // bug 1198419
  policy->AddPath(rdonly, "/etc/media_codecs.xml"); // bug 1198460
  policy->AddTree(rdonly, "/system/fonts"); // bug 1026063

  // Bug 1199051 (crossplatformly, this is NS_GRE_DIR).
  policy->AddTree(rdonly, "/system/b2g");

  // Bug 1026356: dynamic library loading from assorted frameworks we
  // don't control (media codecs, maybe others).
  //
  // Bug 1198515: Also, the profiler calls breakpad code to get info
  // on all loaded ELF objects, which opens those files.
  policy->AddTree(rdonly, "/system/lib");
  policy->AddTree(rdonly, "/vendor/lib");
  policy->AddPath(rdonly, "/system/bin/linker"); // (profiler only)

  // Bug 1199866: EGL/WebGL.
  policy->AddPath(rdonly, "/system/lib/egl");
  policy->AddPath(rdonly, "/vendor/lib/egl");

  // Bug 1198401: timezones.  Yes, we need both of these; see bug.
  policy->AddTree(rdonly, "/system/usr/share/zoneinfo");
  policy->AddTree(rdonly, "/system//usr/share/zoneinfo");

  policy->AddPath(rdonly, "/data/local/tmp/profiler.options",
                  SandboxBroker::Policy::AddAlways); // bug 1029337

  mCommonContentPolicy.reset(policy);
#elif defined(MOZ_CONTENT_SANDBOX)
  SandboxBroker::Policy* policy = new SandboxBroker::Policy;
  policy->AddDir(rdonly, "/");
  policy->AddDir(rdwrcr, "/dev/shm");
  // Add write permissions on the temporary directory. This can come
  // from various environment variables (TMPDIR,TMP,TEMP,...) so
  // make sure to use the full logic.
  nsCOMPtr<nsIFile> tmpDir;
  nsresult rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
                                          getter_AddRefs(tmpDir));
  if (NS_SUCCEEDED(rv)) {
    nsAutoCString tmpPath;
    rv = tmpDir->GetNativePath(tmpPath);
    if (NS_SUCCEEDED(rv)) {
      policy->AddDir(rdwrcr, tmpPath.get());
    }
  }
  // If the above fails at any point, fall back to a very good guess.
  if (NS_FAILED(rv)) {
    policy->AddDir(rdwrcr, "/tmp");
  }

  // Bug 1308851: NVIDIA proprietary driver when using WebGL
  policy->AddPrefix(rdwr, "/dev", "nvidia");

  // Bug 1312678: radeonsi/Intel with DRI when using WebGL
  policy->AddDir(rdwr, "/dev/dri");

  mCommonContentPolicy.reset(policy);
#endif
}

#ifdef MOZ_CONTENT_SANDBOX
UniquePtr<SandboxBroker::Policy>
SandboxBrokerPolicyFactory::GetContentPolicy(int aPid)
{
  // Policy entries that vary per-process (currently the only reason
  // that can happen is because they contain the pid) are added here.

  MOZ_ASSERT(NS_IsMainThread());
  // File broker usage is controlled through a pref.
  if (Preferences::GetInt("security.sandbox.content.level") <= 1) {
    return nullptr;
  }

  MOZ_ASSERT(mCommonContentPolicy);
#if defined(MOZ_WIDGET_GONK)
  // Allow overriding "unsupported"ness with a pref, for testing.
  if (!IsSystemSupported()) {
    return nullptr;
  }
  UniquePtr<SandboxBroker::Policy>
    policy(new SandboxBroker::Policy(*mCommonContentPolicy));

  // Bug 1029337: where the profiler writes the data.
  nsPrintfCString profilerLogPath("/data/local/tmp/profile_%d_%d.txt",
                                  GeckoProcessType_Content, aPid);
  policy->AddPath(wrlog, profilerLogPath.get());

  // Bug 1198550: the profiler's replacement for dl_iterate_phdr
  policy->AddPath(rdonly, nsPrintfCString("/proc/%d/maps", aPid).get());

  // Bug 1198552: memory reporting.
  policy->AddPath(rdonly, nsPrintfCString("/proc/%d/statm", aPid).get());
  policy->AddPath(rdonly, nsPrintfCString("/proc/%d/smaps", aPid).get());

  return policy;
#else
  UniquePtr<SandboxBroker::Policy>
    policy(new SandboxBroker::Policy(*mCommonContentPolicy));
  // Return the common policy.
  return policy;
#endif
}

#endif // MOZ_CONTENT_SANDBOX
} // namespace mozilla