diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index fd5f17656b5..ecd2052478f 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -587,34 +587,6 @@ ContentParent::GetNewOrUsed(bool aForBrowserElement) return p.forget(); } -namespace { -struct SpecialPermission { - const char* perm; // an app permission - ChildPrivileges privs; // the OS privilege it requires -}; -} - -static ChildPrivileges -PrivilegesForApp(mozIApplication* aApp) -{ - const SpecialPermission specialPermissions[] = { - // FIXME/bug 785592: implement a CameraBridge so we don't have - // to hack around with OS permissions - { "camera", base::PRIVILEGES_CAMERA } - }; - 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."); - break; - } else if (hasPermission) { - return specialPermissions[i].privs; - } - } - return base::PRIVILEGES_DEFAULT; -} - /*static*/ ProcessPriority ContentParent::GetInitialProcessPriority(Element* aFrameElement) { @@ -733,7 +705,7 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext, } if (!p) { - ChildPrivileges privs = PrivilegesForApp(ownApp); + ChildPrivileges privs = base::PRIVILEGES_DEFAULT; p = MaybeTakePreallocatedAppProcess(manifestURL, privs, initialPriority); if (!p) { diff --git a/ipc/chromium/src/base/process_util.h b/ipc/chromium/src/base/process_util.h index 1b90b9a9a9a..04c5fcaf5f9 100644 --- a/ipc/chromium/src/base/process_util.h +++ b/ipc/chromium/src/base/process_util.h @@ -129,7 +129,6 @@ void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map); enum ChildPrivileges { PRIVILEGES_DEFAULT, PRIVILEGES_UNPRIVILEGED, - PRIVILEGES_CAMERA, PRIVILEGES_INHERIT, PRIVILEGES_LAST }; diff --git a/ipc/chromium/src/base/process_util_linux.cc b/ipc/chromium/src/base/process_util_linux.cc index 9c3eecd9d4d..5b9552530ee 100644 --- a/ipc/chromium/src/base/process_util_linux.cc +++ b/ipc/chromium/src/base/process_util_linux.cc @@ -302,17 +302,6 @@ void SetCurrentProcessPrivileges(ChildPrivileges privs) { gid += getpid(); uid += getpid(); } - if (privs == PRIVILEGES_CAMERA) { -#if ANDROID_VERSION < 17 - gid_t groups[] = { AID_SDCARD_RW }; -#else - gid_t groups[] = { AID_SDCARD_R, AID_SDCARD_RW, AID_MEDIA_RW }; -#endif - if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) { - DLOG(ERROR) << "FAILED TO setgroups() CHILD PROCESS"; - _exit(127); - } - } #endif if (setgid(gid) != 0) { DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS"; diff --git a/widget/gonk/GonkPermission.cpp b/widget/gonk/GonkPermission.cpp index 03513f2130d..1b8d667d181 100644 --- a/widget/gonk/GonkPermission.cpp +++ b/widget/gonk/GonkPermission.cpp @@ -21,6 +21,13 @@ #include #include "GonkPermission.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/TabParent.h" +#include "mozilla/SyncRunnable.h" +#include "nsIAppsService.h" +#include "mozIApplication.h" +#include "nsThreadUtils.h" + #undef LOG #include #define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args) @@ -28,31 +35,104 @@ using namespace android; using namespace mozilla; +// Checking permissions needs to happen on the main thread, but the +// binder callback is called on a special binder thread, so we use +// this runnable for that. +class GonkPermissionChecker : public nsRunnable { + int32_t mPid; + bool mCanUseCamera; + + explicit GonkPermissionChecker(int32_t pid) + : mPid(pid) + , mCanUseCamera(false) + { + } + +public: + static already_AddRefed Inspect(int32_t pid) + { + nsRefPtr that = new GonkPermissionChecker(pid); + nsCOMPtr mainThread = do_GetMainThread(); + MOZ_ASSERT(mainThread); + SyncRunnable::DispatchToThread(mainThread, that); + return that.forget(); + } + + bool CanUseCamera() + { + return mCanUseCamera; + } + + NS_IMETHOD Run(); +}; + +NS_IMETHODIMP +GonkPermissionChecker::Run() +{ + MOZ_ASSERT(NS_IsMainThread()); + + // Find our ContentParent. + dom::ContentParent *contentParent = nullptr; + { + nsTArray parents; + dom::ContentParent::GetAll(parents); + for (uint32_t i = 0; i < parents.Length(); ++i) { + if (parents[i]->Pid() == mPid) { + contentParent = parents[i]; + break; + } + } + } + if (!contentParent) { + ALOGE("pid=%d denied: can't find ContentParent", mPid); + return NS_OK; + } + + // Now iterate its apps... + for (uint32_t i = 0; i < contentParent->ManagedPBrowserParent().Length(); i++) { + dom::TabParent *tabParent = + static_cast(contentParent->ManagedPBrowserParent()[i]); + nsCOMPtr mozApp = tabParent->GetOwnOrContainingApp(); + if (!mozApp) { + continue; + } + + // ...and check if any of them has camera access. + bool appCanUseCamera; + nsresult rv = mozApp->HasPermission("camera", &appCanUseCamera); + if (NS_SUCCEEDED(rv) && appCanUseCamera) { + mCanUseCamera = true; + return NS_OK; + } + } + return NS_OK; +} + bool GonkPermissionService::checkPermission(const String16& permission, int32_t pid, int32_t uid) { - if (0 == uid) + // root can do anything. + if (0 == uid) { return true; + } String8 perm8(permission); - // Some ril implementations need android.permission.MODIFY_AUDIO_SETTINGS if (uid == AID_RADIO && - perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") + perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") { return true; + } - // Camera/audio record permissions are only for apps with the - // "camera" permission. These apps are also the only apps granted - // the AID_SDCARD_RW supplemental group (bug 785592) - + // No other permissions apply to non-app processes. if (uid < AID_APP) { ALOGE("%s for pid=%d,uid=%d denied: not an app", String8(permission).string(), pid, uid); return false; } + // Only these permissions can be granted to apps through this service. if (perm8 != "android.permission.CAMERA" && perm8 != "android.permission.RECORD_AUDIO") { ALOGE("%s for pid=%d,uid=%d denied: unsupported permission", @@ -69,40 +149,16 @@ GonkPermissionService::checkPermission(const String16& permission, int32_t pid, return true; } - char filename[32]; - snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - FILE *f = fopen(filename, "r"); - if (!f) { - ALOGE("%s for pid=%d,uid=%d denied: unable to open %s", - String8(permission).string(), pid, uid, filename); - return false; + // Camera/audio record permissions are allowed for apps with the + // "camera" permission. + nsRefPtr checker = + GonkPermissionChecker::Inspect(pid); + bool canUseCamera = checker->CanUseCamera(); + if (!canUseCamera) { + ALOGE("%s for pid=%d,uid=%d denied: not granted by user or app manifest", + String8(permission).string(), pid, uid); } - - char line[80]; - while (fgets(line, sizeof(line), f)) { - char *save; - char *name = strtok_r(line, "\t", &save); - if (!name) - continue; - - if (strcmp(name, "Groups:")) - continue; - char *group; - while ((group = strtok_r(NULL, " \n", &save))) { - #define _STR(x) #x - #define STR(x) _STR(x) - if (!strcmp(group, STR(AID_SDCARD_RW))) { - fclose(f); - return true; - } - } - break; - } - fclose(f); - - ALOGE("%s for pid=%d,uid=%d denied: missing group", - String8(permission).string(), pid, uid); - return false; + return canUseCamera; } static GonkPermissionService* gGonkPermissionService = NULL;