Bug 1361304 - Remove /private/var read access from Mac level 3 content sandbox; r?alex_gaynor
Removes read access to /private/var and its subdirectories from
the content process under the level 3 Mac sandbox. Still permits
reading of file metadata within the majority of /private/var.
Adds tests to validate the level 3 Mac content sandbox prevents
reading from /private.
MozReview-Commit-ID: FO5dz0F7dl4
--- a/security/sandbox/mac/SandboxPolicies.h
+++ b/security/sandbox/mac/SandboxPolicies.h
@@ -64,25 +64,27 @@ static const char contentSandboxRules[]
(define hasFilePrivileges (param "HAS_FILE_PRIVILEGES"))
(define isDebugBuild (param "DEBUG_BUILD"))
; Allow read access to standard system paths.
(allow file-read*
(require-all (file-mode #o0004)
(require-any (subpath "/Library/Filesystems/NetFSPlugins")
(subpath "/System")
- (subpath "/private/var/db/dyld")
(subpath "/usr/lib")
(subpath "/usr/share"))))
(allow file-read-metadata
(literal "/etc")
(literal "/tmp")
(literal "/var")
- (literal "/private/etc/localtime"))
+ (literal "/private/etc/localtime")
+ (literal "/home")
+ (literal "/net")
+ (regex "^/private/tmp/KSInstallAction\."))
; Allow read access to standard special files.
(allow file-read*
(literal "/dev/autofs_nowait")
(literal "/dev/random")
(literal "/dev/urandom"))
(allow file-read*
@@ -105,34 +107,27 @@ static const char contentSandboxRules[]
(debug deny)
(define resolving-literal literal)
(define resolving-subpath subpath)
(define resolving-regex regex)
(define container-path appPath)
(define appdir-path appDir)
- (define var-folders-re "^/private/var/folders/[^/][^/]")
- (define var-folders2-re (string-append var-folders-re "/[^/]+/[^/]"))
(define (home-regex home-relative-regex)
(resolving-regex (string-append "^" (regex-quote home-path) home-relative-regex)))
(define (home-subpath home-relative-subpath)
(resolving-subpath (string-append home-path home-relative-subpath)))
(define (home-literal home-relative-literal)
(resolving-literal (string-append home-path home-relative-literal)))
(define (profile-subpath profile-relative-subpath)
(resolving-subpath (string-append profileDir profile-relative-subpath)))
- (define (var-folders-regex var-folders-relative-regex)
- (resolving-regex (string-append var-folders-re var-folders-relative-regex)))
- (define (var-folders2-regex var-folders2-relative-regex)
- (resolving-regex (string-append var-folders2-re var-folders2-relative-regex)))
-
(define (allow-shared-preferences-read domain)
(begin
(if (defined? `user-preference-read)
(allow user-preference-read (preference-domain domain)))
(allow file-read*
(home-literal (string-append "/Library/Preferences/" domain ".plist"))
(home-regex (string-append "/Library/Preferences/ByHost/" (regex-quote domain) "\..*\.plist$")))
))
@@ -141,23 +136,16 @@ static const char contentSandboxRules[]
(allow file-read*
(home-regex (string-append "/Library/Preferences/" (regex-quote domain)))))
(allow ipc-posix-shm
(ipc-posix-name-regex "^/tmp/com.apple.csseed:")
(ipc-posix-name-regex "^CFPBS:")
(ipc-posix-name-regex "^AudioIO"))
- (allow file-read-metadata
- (literal "/home")
- (literal "/net")
- (regex "^/private/tmp/KSInstallAction\.")
- (var-folders-regex "/")
- (home-subpath "/Library"))
-
(allow signal (target self))
(allow job-creation (literal "/Library/CoreMediaIO/Plug-Ins/DAL"))
(allow iokit-set-properties (iokit-property "IOAudioControlValue"))
(allow mach-lookup
(global-name "com.apple.coreservices.launchservicesd")
(global-name "com.apple.coreservices.appleevents")
(global-name "com.apple.pasteboard.1")
@@ -224,29 +212,35 @@ static const char contentSandboxRules[]
(home-subpath "/Library/Spelling")
(home-subpath "/Library/Application Support/Adobe/CoreSync/plugins/livetype")
(subpath appdir-path)
(literal appPath)
(literal appBinaryPath))
+ (allow file-read-metadata (home-subpath "/Library"))
+
+ (allow file-read-metadata
+ (literal "/private/var")
+ (subpath "/private/var/folders"))
+
+ ; bug 1303987
+ (if (string=? isDebugBuild "TRUE")
+ (allow file-write* (subpath "/private/var")))
+
+ ; bug 1324610
+ (allow network-outbound (literal "/private/var/run/cupsd"))
+
(allow-shared-list "org.mozilla.plugincontainer")
; the following rule should be removed when microphone access
; is brokered through the content process
(allow device-microphone)
- (allow file* (var-folders2-regex "/com\.apple\.IntlDataCache\.le$"))
- (allow file-read*
- (var-folders2-regex "/com\.apple\.IconServices/")
- (var-folders2-regex "/[^/]+\.mozrunner/extensions/[^/]+/chrome/[^/]+/content/[^/]+\.j(s|ar)$"))
-
- (allow file-write* (var-folders2-regex "/org\.chromium\.[a-zA-Z0-9]*$"))
-
; Per-user and system-wide Extensions dir
(allow file-read*
(home-regex "/Library/Application Support/[^/]+/Extensions/[^/]/")
(resolving-regex "/Library/Application Support/[^/]+/Extensions/[^/]/"))
; The following rules impose file access restrictions which get
; more restrictive in higher levels. When file-origin-specific
; content processes are used for file:// origin browsing, the
@@ -276,33 +270,40 @@ static const char contentSandboxRules[]
(allow file-read*
(profile-subpath "/extensions")
(profile-subpath "/chrome")))
; we don't have a profile dir
(allow file-read* (require-not (home-subpath "/Library")))))))
; level 3: global read access permitted, no global write access,
; no read access to the home directory,
+ ; no read access to /private/var (but read-metadata allowed above),
; read access permitted to $PROFILE/{extensions,chrome}
(if (string=? sandbox-level-3 "TRUE")
(if (string=? hasFilePrivileges "TRUE")
; This process has blanket file read privileges
(allow file-read*)
; This process does not have blanket file read privileges
(if (string=? hasProfileDir "TRUE")
; we have a profile dir
(begin
(allow file-read* (require-all
(require-not (subpath home-path))
- (require-not (subpath profileDir))))
+ (require-not (subpath profileDir))
+ (require-not (subpath "/private/var"))))
+ (allow file-read* (literal "/private/var/run/cupsd"))
(allow file-read*
(profile-subpath "/extensions")
(profile-subpath "/chrome")))
; we don't have a profile dir
- (allow file-read* (require-not (subpath home-path))))))
+ (begin
+ (allow file-read* (require-all
+ (require-not (subpath home-path))
+ (require-not (subpath "/private/var"))))
+ (allow file-read* (literal "/private/var/run/cupsd"))))))
; accelerated graphics
(allow-shared-preferences-read "com.apple.opengl")
(allow-shared-preferences-read "com.nvidia.OpenGL")
(allow mach-lookup
(global-name "com.apple.cvmsServ"))
(allow iokit-open
(iokit-connection "IOAccelerator")
@@ -320,21 +321,14 @@ static const char contentSandboxRules[]
(iokit-user-client-class "NVDVDContextTesla")
(iokit-user-client-class "Gen6DVDContext"))
; bug 1237847
(allow file-read*
(subpath appTempDir))
(allow file-write*
(subpath appTempDir))
-
- ; bug 1324610
- (allow network-outbound (literal "/private/var/run/cupsd"))
-
- ; bug 1303987
- (if (string=? isDebugBuild "TRUE")
- (allow file-write* (var-folders-regex "/")))
)
)";
}
#endif // mozilla_SandboxPolicies_h
--- a/security/sandbox/test/browser_content_sandbox_fs.js
+++ b/security/sandbox/test/browser_content_sandbox_fs.js
@@ -313,16 +313,76 @@ function* testFileAccess() {
ok: shouldBeReadable,
browser: webBrowser,
file: homeTempDir,
minLevel: minLevel,
});
}
}
+ // Should we enable this /var test on Linux? Once we are running
+ // with read access restrictions on Linux, this todo will fail and
+ // should then be removed.
+ if (isLinux()) {
+ todo(level >= minHomeReadSandboxLevel(), "enable /var test on Linux?");
+ }
+ if (isMac()) {
+ let varDir = GetDir("/var");
+
+ // Mac sandbox rules use /private/var because /var is a symlink
+ // to /private/var on OS X. Make sure that hasn't changed.
+ varDir.normalize();
+ Assert.ok(varDir.path === '/private/var', '/var resolves to /private/var');
+
+ tests.push({
+ desc: "/var",
+ ok: false,
+ browser: webBrowser,
+ file: varDir,
+ minLevel: minHomeReadSandboxLevel(),
+ });
+ if (fileContentProcessEnabled) {
+ tests.push({
+ desc: "/var",
+ ok: true,
+ browser: fileBrowser,
+ file: varDir,
+ minLevel: 0,
+ });
+ }
+ }
+
+ if (isMac()) {
+ // Test if we can read from $TMPDIR because we expect it
+ // to be within /private/var. Reading from it should be
+ // prevented in a 'web' process.
+ let macTempDir = GetDirFromEnvVariable('TMPDIR');
+
+ macTempDir.normalize();
+ Assert.ok(macTempDir.path.startsWith('/private/var'),
+ '$TMPDIR is in /private/var');
+
+ tests.push({
+ desc: `$TMPDIR (${macTempDir.path})`,
+ ok: false,
+ browser: webBrowser,
+ file: macTempDir,
+ minLevel: minHomeReadSandboxLevel(),
+ });
+ if (fileContentProcessEnabled) {
+ tests.push({
+ desc: `$TMPDIR (${macTempDir.path})`,
+ ok: true,
+ browser: fileBrowser,
+ file: macTempDir,
+ minLevel: 0,
+ });
+ }
+ }
+
let extensionsDir = GetProfileEntry("extensions");
if (extensionsDir.exists() && extensionsDir.isDirectory()) {
tests.push({
desc: "extensions dir",
ok: true,
browser: webBrowser,
file: extensionsDir,
minLevel: 0,
--- a/security/sandbox/test/browser_content_sandbox_utils.js
+++ b/security/sandbox/test/browser_content_sandbox_utils.js
@@ -1,13 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
+const environment = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
/*
* Utility functions for the browser content sandbox tests.
*/
function isMac() { return Services.appinfo.OS == "Darwin" }
function isWin() { return Services.appinfo.OS == "WINNT" }
function isLinux() { return Services.appinfo.OS == "Linux" }
@@ -70,8 +72,19 @@ function GetHomeDir() {
// Returns a file object for the file or directory named |name| in the
// profile directory.
function GetProfileEntry(name) {
let entry = GetProfileDir();
entry.append(name);
return (entry);
}
+
+function GetDir(path) {
+ let dir = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
+ dir.initWithPath(path);
+ Assert.ok(dir.isDirectory(), `${path} is a directory`);
+ return (dir);
+}
+
+function GetDirFromEnvVariable(varName) {
+ return GetDir(environment.get(varName));
+}