Bug 976398 - Check camera permissions directly instead of using Unix groups. r=mwu r=bent

Loosely based on the code used to check PRemoteOpenFile.
This commit is contained in:
Jed Davis 2014-03-12 15:48:15 -07:00
parent 5c75b92a92
commit b756489606
4 changed files with 97 additions and 81 deletions

View File

@ -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) {

View File

@ -129,7 +129,6 @@ void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map);
enum ChildPrivileges {
PRIVILEGES_DEFAULT,
PRIVILEGES_UNPRIVILEGED,
PRIVILEGES_CAMERA,
PRIVILEGES_INHERIT,
PRIVILEGES_LAST
};

View File

@ -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";

View File

@ -21,6 +21,13 @@
#include <private/android_filesystem_config.h>
#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 <android/log.h>
#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<GonkPermissionChecker> Inspect(int32_t pid)
{
nsRefPtr<GonkPermissionChecker> that = new GonkPermissionChecker(pid);
nsCOMPtr<nsIThread> 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<dom::ContentParent*> 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<dom::TabParent*>(contentParent->ManagedPBrowserParent()[i]);
nsCOMPtr<mozIApplication> 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<GonkPermissionChecker> 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;