Bug 1000253 - Background tabs with persistent device permissions can access devices without the user noticing, r=jesup,MattN.

This commit is contained in:
Florian Quèze 2014-06-13 14:51:12 +02:00
parent 4868201b22
commit 13b7c7896a
3 changed files with 40 additions and 33 deletions

View File

@ -593,6 +593,9 @@ let gTests = [
yield promiseMessage(expectedMessage, gum);
if (expectedMessage == "ok") {
expectObserverCalled("getUserMedia:request");
yield promiseNoPopupNotification("webRTC-shareDevices");
expectObserverCalled("getUserMedia:response:allow");
expectObserverCalled("recording-device-events");
// Check what's actually shared.
@ -687,6 +690,8 @@ let gTests = [
yield promiseMessage("ok", () => {
content.wrappedJSObject.requestDevice(aRequestAudio, aRequestVideo);
});
expectObserverCalled("getUserMedia:request");
expectObserverCalled("getUserMedia:response:allow");
expectObserverCalled("recording-device-events");
yield checkSharingUI();

View File

@ -212,6 +212,38 @@ function prompt(aContentWindow, aCallID, aAudioRequested, aVideoRequested, aDevi
if (aTopic != "showing")
return false;
// DENY_ACTION is handled immediately by MediaManager, but handling
// of ALLOW_ACTION is delayed until the popupshowing event
// to avoid granting permissions automatically to background tabs.
if (aSecure) {
let perms = Services.perms;
let micPerm = perms.testExactPermission(uri, "microphone");
if (micPerm == perms.PROMPT_ACTION)
micPerm = perms.UNKNOWN_ACTION;
let camPerm = perms.testExactPermission(uri, "camera");
if (camPerm == perms.PROMPT_ACTION)
camPerm = perms.UNKNOWN_ACTION;
// We don't check that permissions are set to ALLOW_ACTION in this
// test; only that they are set. This is because if audio is allowed
// and video is denied persistently, we don't want to show the prompt,
// and will grant audio access immediately.
if ((!audioDevices.length || micPerm) && (!videoDevices.length || camPerm)) {
// All permissions we were about to request are already persistently set.
let allowedDevices = Cc["@mozilla.org/supports-array;1"]
.createInstance(Ci.nsISupportsArray);
if (videoDevices.length && camPerm == perms.ALLOW_ACTION)
allowedDevices.AppendElement(videoDevices[0]);
if (audioDevices.length && micPerm == perms.ALLOW_ACTION)
allowedDevices.AppendElement(audioDevices[0]);
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID);
this.remove();
return true;
}
}
function listDevices(menupopup, devices) {
while (menupopup.lastChild)
menupopup.removeChild(menupopup.lastChild);

View File

@ -1498,14 +1498,6 @@ MediaManager::GetUserMedia(bool aPrivileged,
rv = permManager->TestExactPermissionFromPrincipal(
aWindow->GetExtantDoc()->NodePrincipal(), "microphone", &audioPerm);
NS_ENSURE_SUCCESS(rv, rv);
if (audioPerm == nsIPermissionManager::PROMPT_ACTION) {
audioPerm = nsIPermissionManager::UNKNOWN_ACTION;
}
if (audioPerm == nsIPermissionManager::ALLOW_ACTION) {
if (!isHTTPS) {
audioPerm = nsIPermissionManager::UNKNOWN_ACTION;
}
}
}
uint32_t videoPerm = nsIPermissionManager::UNKNOWN_ACTION;
@ -1513,33 +1505,11 @@ MediaManager::GetUserMedia(bool aPrivileged,
rv = permManager->TestExactPermissionFromPrincipal(
aWindow->GetExtantDoc()->NodePrincipal(), "camera", &videoPerm);
NS_ENSURE_SUCCESS(rv, rv);
if (videoPerm == nsIPermissionManager::PROMPT_ACTION) {
videoPerm = nsIPermissionManager::UNKNOWN_ACTION;
}
if (videoPerm == nsIPermissionManager::ALLOW_ACTION) {
if (!isHTTPS) {
videoPerm = nsIPermissionManager::UNKNOWN_ACTION;
}
}
}
if ((!IsOn(c.mAudio) || audioPerm != nsIPermissionManager::UNKNOWN_ACTION) &&
(!IsOn(c.mVideo) || videoPerm != nsIPermissionManager::UNKNOWN_ACTION)) {
// All permissions we were about to request already have a saved value.
if (IsOn(c.mAudio) && audioPerm == nsIPermissionManager::DENY_ACTION) {
c.mAudio.SetAsBoolean() = false;
runnable->SetContraints(c);
}
if (IsOn(c.mVideo) && videoPerm == nsIPermissionManager::DENY_ACTION) {
c.mVideo.SetAsBoolean() = false;
runnable->SetContraints(c);
}
if (!IsOn(c.mAudio) && !IsOn(c.mVideo)) {
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
}
return mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) &&
(!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) {
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
}
// Ask for user permission, and dispatch runnable (or not) when a response