Bug 822510: Add specific privilege levels for camera and video, and enable that for video. r=jlebar,kang
authorChris Jones <jones.chris.g@gmail.com>
Wed, 19 Dec 2012 23:41:08 -0800
changeset 125716 bb90ec82052beeae0941949e907ae92bfea926fb
parent 125715 ebad7aef8c52ef6ea023a6dbab9dfb3a62ef77ab
child 125717 54618ad94522b6609d234e05b6edaaeb7f4b46a5
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar, kang
bugs822510
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 822510: Add specific privilege levels for camera and video, and enable that for video. r=jlebar,kang
dom/ipc/ContentParent.cpp
ipc/chromium/src/base/process_util.h
ipc/chromium/src/base/process_util_linux.cc
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -106,16 +106,17 @@
 #ifdef MOZ_B2G_BT
 #include "BluetoothParent.h"
 #include "BluetoothService.h"
 #endif
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
 
+using base::ChildPrivileges;
 using base::KillProcess;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
@@ -284,38 +285,45 @@ ContentParent::GetNewOrUsed(bool aForBro
     nsRefPtr<ContentParent> p =
         new ContentParent(/* appManifestURL = */ EmptyString(),
                           aForBrowserElement);
     p->Init();
     gNonAppContentParents->AppendElement(p);
     return p;
 }
 
-static bool
-AppNeedsInheritedOSPrivileges(mozIApplication* aApp)
+namespace {
+struct SpecialPermission {
+    const char* perm;           // an app permission
+    ChildPrivileges privs;      // the OS privilege it requires
+};
+}
+
+static ChildPrivileges
+PrivilegesForApp(mozIApplication* aApp)
 {
-    const char* const needInheritPermissions[] = {
+    const SpecialPermission specialPermissions[] = {
         // FIXME/bug 785592: implement a CameraBridge so we don't have
         // to hack around with OS permissions
-        "camera",
+        { "camera", base::PRIVILEGES_INHERIT },
         // FIXME/bug 793034: change our video architecture so that we
         // can stream video from remote processes
-        "deprecated-hwvideo",
+        { "deprecated-hwvideo", base::PRIVILEGES_VIDEO }
     };
-    for (size_t i = 0; i < ArrayLength(needInheritPermissions); ++i) {
-        const char* const permission = needInheritPermissions[i];
-        bool needsInherit = false;
-        if (NS_FAILED(aApp->HasPermission(permission, &needsInherit))) {
+    for (size_t i = 0; i < ArrayLength(specialPermissions); ++i) {
+        const char* const permission = specialPermissions[i].perm;
+        bool hasPermission = false;
+        if (NS_FAILED(aApp->HasPermission(permission, &hasPermission))) {
             NS_WARNING("Unable to check permissions.  Breakage may follow.");
-            return false;
-        } else if (needsInherit) {
-            return true;
+            break;
+        } else if (hasPermission) {
+            return specialPermissions[i].privs;
         }
     }
-    return false;
+    return base::PRIVILEGES_DEFAULT;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowserOrApp(const TabContext& aContext)
 {
     if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
         if (ContentParent* cp = GetNewOrUsed(aContext.IsBrowserElement())) {
             nsRefPtr<TabParent> tp(new TabParent(aContext));
@@ -343,19 +351,20 @@ ContentParent::CreateBrowserOrApp(const 
     nsAutoString manifestURL;
     if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) {
         NS_ERROR("Failed to get manifest URL");
         return nullptr;
     }
 
     nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
     if (!p) {
-        if (AppNeedsInheritedOSPrivileges(ownApp)) {
+        ChildPrivileges privs = PrivilegesForApp(ownApp);
+        if (privs != base::PRIVILEGES_DEFAULT) {
             p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
-                                  base::PRIVILEGES_INHERIT);
+                                  privs);
             p->Init();
         } else {
             p = MaybeTakePreallocatedAppProcess();
             if (p) {
                 p->SetManifestFromPreallocated(manifestURL);
             } else {
                 NS_WARNING("Unable to use pre-allocated app process");
                 p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
--- a/ipc/chromium/src/base/process_util.h
+++ b/ipc/chromium/src/base/process_util.h
@@ -124,16 +124,18 @@ void SetAllFDsToCloseOnExec();
 // given multimap. Only call this function in a child process where you know
 // that there aren't any other threads.
 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map);
 #endif
 
 enum ChildPrivileges {
   PRIVILEGES_DEFAULT,
   PRIVILEGES_UNPRIVILEGED,
+  PRIVILEGES_CAMERA,
+  PRIVILEGES_VIDEO,
   PRIVILEGES_INHERIT
 };
 
 #if defined(OS_WIN)
 // Runs the given application name with the given command line. Normally, the
 // first command line argument should be the path to the process, and don't
 // forget to quote it.
 //
--- a/ipc/chromium/src/base/process_util_linux.cc
+++ b/ipc/chromium/src/base/process_util_linux.cc
@@ -24,16 +24,20 @@
 /*
  * AID_APP is the first application UID used by Android. We're using
  * it as our unprivilegied UID.  This ensure the UID used is not
  * shared with any other processes than our own childs.
  */
 # include <private/android_filesystem_config.h>
 # define CHILD_UNPRIVILEGED_UID AID_APP
 # define CHILD_UNPRIVILEGED_GID AID_APP
+# define CHILD_CAMERA_UID AID_SYSTEM
+# define CHILD_CAMERA_GID AID_SDCARD_RW
+# define CHILD_VIDEO_UID AID_MEDIA
+# define CHILD_VIDEO_GID AID_AUDIO
 #else
 /*
  * On platforms that are not gonk based, we fall back to an arbitrary
  * UID. This is generally the UID for user `nobody', albeit it is not
  * always the case.
  */
 # define CHILD_UNPRIVILEGED_UID 65534
 # define CHILD_UNPRIVILEGED_GID 65534
@@ -226,46 +230,54 @@ bool LaunchApp(const std::vector<std::st
       _exit(127);
 
     CloseSuperfluousFds(fd_shuffle2);
 
     for (size_t i = 0; i < argv.size(); i++)
       argv_cstr[i] = const_cast<char*>(argv[i].c_str());
     argv_cstr[argv.size()] = NULL;
 
-    if (privs == PRIVILEGES_UNPRIVILEGED) {
+    if (privs != PRIVILEGES_INHERIT) {
       gid_t gid = CHILD_UNPRIVILEGED_GID;
       uid_t uid = CHILD_UNPRIVILEGED_UID;
 #ifdef MOZ_WIDGET_GONK
-      static bool checked_pix_max, pix_max_ok;
-      if (!checked_pix_max) {
-        checked_pix_max = true;
-        int fd = open("/proc/sys/kernel/pid_max", O_CLOEXEC | O_RDONLY);
-        if (fd < 0) {
-          DLOG(ERROR) << "Failed to open pid_max";
+      if (privs == PRIVILEGES_UNPRIVILEGED) {
+        static bool checked_pix_max, pix_max_ok;
+        if (!checked_pix_max) {
+          checked_pix_max = true;
+          int fd = open("/proc/sys/kernel/pid_max", O_CLOEXEC | O_RDONLY);
+          if (fd < 0) {
+            DLOG(ERROR) << "Failed to open pid_max";
+            _exit(127);
+          }
+          char buf[PATH_MAX];
+          ssize_t len = read(fd, buf, sizeof(buf) - 1);
+          close(fd);
+          if (len < 0) {
+            DLOG(ERROR) << "Failed to read pid_max";
+            _exit(127);
+          }
+          buf[len] = '\0';
+          int pid_max = atoi(buf);
+          pix_max_ok =
+            (pid_max + CHILD_UNPRIVILEGED_UID > CHILD_UNPRIVILEGED_UID);
+        }
+        if (!pix_max_ok) {
+          DLOG(ERROR) << "Can't safely get unique uid/gid";
           _exit(127);
         }
-        char buf[PATH_MAX];
-        ssize_t len = read(fd, buf, sizeof(buf) - 1);
-        close(fd);
-        if (len < 0) {
-          DLOG(ERROR) << "Failed to read pid_max";
-          _exit(127);
-        }
-        buf[len] = '\0';
-        int pid_max = atoi(buf);
-        pix_max_ok =
-          (pid_max + CHILD_UNPRIVILEGED_UID > CHILD_UNPRIVILEGED_UID);
+        gid += getpid();
+        uid += getpid();
+      } else if (privs == PRIVILEGES_CAMERA) {
+        uid = CHILD_CAMERA_UID;
+        gid = CHILD_CAMERA_GID;
+      } else if (privs == PRIVILEGES_VIDEO) {
+        uid = CHILD_VIDEO_UID;
+        gid = CHILD_VIDEO_GID;
       }
-      if (!pix_max_ok) {
-        DLOG(ERROR) << "Can't safely get unique uid/gid";
-        _exit(127);
-      }
-      gid += getpid();
-      uid += getpid();
 #endif
       if (setgid(gid) != 0) {
         DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS, path: " << argv_cstr[0];
         _exit(127);
       }
       if (setuid(uid) != 0) {
         DLOG(ERROR) << "FAILED TO setuid() CHILD PROCESS, path: " << argv_cstr[0];
         _exit(127);