Closed Bug 1218337 Opened 9 years ago Closed 9 years ago

Restrict speech recognition interface access using a permission check instead of the current app-type check

Categories

(Core :: Web Speech, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
2.6 S1 - 11/20
Tracking Status
firefox44 --- fixed
firefox45 --- fixed
b2g-v2.5 --- fixed

People

(Reporter: kdavis, Assigned: kdavis)

References

Details

(Whiteboard: [webspeechapi][systemsfe])

Attachments

(1 file, 3 obsolete files)

Currently the speech recognition interface access is granted through a app-type check. In other words, all relevant webidl interfaces are fo the form

[Constructor,
 Func="SpeechRecognition::IsAuthorized",
 ...]
interface ... {
  ...
};

where the static method SpeechRecognition::IsAuthorized is given by

bool
SpeechRecognition::IsAuthorized(JSContext* aCx, JSObject* aGlobal)
{
  bool inPrivilegedApp = IsInPrivilegedApp(aCx, aGlobal);
  bool enableTests = Preferences::GetBool(TEST_PREFERENCE_ENABLE);
  bool enableRecognitionEnable = Preferences::GetBool(TEST_PREFERENCE_RECOGNITION_ENABLE);
  bool enableRecognitionForceEnable = Preferences::GetBool(TEST_PREFERENCE_RECOGNITION_FORCE_ENABLE);
  return (inPrivilegedApp || enableRecognitionForceEnable || enableTests) && enableRecognitionEnable;
}

This goal of this bug is to move this to a permission check by introducing a permission "speech-recognition" to PermissionsTable.jsm and replacing the webidl Func="SpeechRecognition::IsAuthorized" with something like CheckAnyPermissions="speech-recognition" while also retaining the control of the various preferences TEST_PREFERENCE_ENABLE, TEST_PREFERENCE_RECOGNITION_ENABLE, and TEST_PREFERENCE_RECOGNITION_FORCE_ENABLE.
Assignee: nobody → kdavis
Whiteboard: [webspeechapi][systemsfe]
I realize now that all of those checks (app type, pref, permission) are supported in WebIDL:

App Type: https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings#AvailableIn
Preference: https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings#Pref
Permissions: https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings#CheckAllPermissions

Does this answer your question?
I think the trick is combining them as in the existing method SpeechRecognition::IsAuthorized

(inPrivilegedApp || enableRecognitionForceEnable || enableTests) && enableRecognitionEnable

As far as I know using CheckAllPermissions and Pref together in a webidl file would combine the preference and permission using && while the above code requires a more nuanced combination.
Blocks: 1214092
Thats fine with me Kelly, so long as you replace the "inPrivilegedApp" part with a permission check instead. The reason why this is important is that in the new security model for b2g, there are no app types, only permissions. 

I would note that generally for tests, we use special powers to add the permission, rather than overriding the permission check. (also you can properly test the case when the page _doesn't_ have permission). But I'll leave that up to you.

I was also going to ask that you perform a check on the parent side of the code to, but as far as I can tell this code isn't remoted at all  (ie I guess this runs entirely in the child process). Is my understand correct there? If so, then just the change in the interface check should be sufficient.
(In reply to Paul Theriault [:pauljt] from comment #3)
> Thats fine with me Kelly, so long as you replace the "inPrivilegedApp" part
> with a permission check instead. The reason why this is important is that in
> the new security model for b2g, there are no app types, only permissions.

So that I am sure we are on the same page you mean replace:

bool inPrivilegedApp = IsInPrivilegedApp(aCx, aGlobal);

in the bug description above with something like:

bool inPrivilegedApp = false;

nsresult rv;
nsCOMPtr<nsIPermissionManager> mgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
  return false;
}

uint32_t speechRecognition = nsIPermissionManager::UNKNOWN_ACTION;

nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetOwner());
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();

rv = mgr->TestExactPermissionFromPrincipal(principal, "speech-recognition", &speechRecognition);
if (NS_WARN_IF(NS_FAILED(rv))) {
  return false;
}

inPrivilegedApp = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);


> I would note that generally for tests, we use special powers to add the
> permission, rather than overriding the permission check. (also you can
> properly test the case when the page _doesn't_ have permission). But I'll
> leave that up to you.

This is the way Olli wanted me to do the permission check.

> I was also going to ask that you perform a check on the parent side of the
> code to, but as far as I can tell this code isn't remoted at all  (ie I
> guess this runs entirely in the child process). Is my understand correct
> there? If so, then just the change in the interface check should be
> sufficient.

Yeah this is all happening the the child process.
I'll assume silence = acceptance and start with the implementation
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Part 1 of 1 commit for this bug.

Introduced the permission 'speech-recognition' which guards the speech recognition API.

Due to the odd combination of conditions required to provide access to the speech recognition API, the standard CheckAllPermissions means of checking permission through webidl files was not used.

Instead webidl's Func is used with the static function SpeechRecognition::IsAuthorized which checks the permission 'speech-recognition' along with several other boolean values.

The try for this patch if running here http://mzl.la/1POLsyK
Attachment #8679499 - Flags: review?(fbraun)
Andre/Reza: FYI when this lands you'll have to add the 'speech-recognition' permission to vaani
(In reply to kdavis from comment #7)
> Andre/Reza: FYI when this lands you'll have to add the 'speech-recognition'
> permission to vaani

Yes, thanks Kelly.
Ping
Ping (This needs to land in 2.5)
Comment on attachment 8679499 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Review of attachment 8679499 [details] [diff] [review]:
-----------------------------------------------------------------

Please excuse the delay. I was out sick so I did not look at the review queue.
It looks good in theory, but I think I already mentioned in email that I am not a good reviewer for this code.
You'll also need a module peer for the PermissionsTable.jsm change (one of fabrice, gwagner, smaug, sicking according to VCS log).
Attachment #8679499 - Flags: review?(fbraun) → feedback+
Attachment #8679499 - Flags: review?(bugs)
Comment on attachment 8679499 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

> SpeechRecognition::IsAuthorized(JSContext* aCx, JSObject* aGlobal)
> {
>-  bool inPrivilegedApp = IsInPrivilegedApp(aCx, aGlobal);
>+  nsresult rv;
>+  nsCOMPtr<nsIPermissionManager> mgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
>+  if (NS_WARN_IF(NS_FAILED(rv))) {
>+    return false;
>+  }
>+
>+  uint32_t speechRecognition = nsIPermissionManager::UNKNOWN_ACTION;
>+
>+  JSCompartment *compartment = js::GetObjectCompartment(aGlobal);
>+  JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
>+  nsCOMPtr<nsIPrincipal> principal = nsJSPrincipals::get(principals);
Hmm, this looks unusual.

Something like 
nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);

nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
NS_ENSURE_TRUE(permMgr, false);
uint32_t permission = nsIPermissionManager::DENY_ACTION;
permMgr->TestExactPermissionFromPrincipal(principal, "speech-recognition", &permission);
bool inPrivileged = nsIPermissionManager::ALLOW_ACTION == permission;
...
Attachment #8679499 - Flags: review?(bugs) → review-
I'll add the call:

nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);

But, actually internally nsContentUtils::ObjectPrincipal(aGlobal) does exactly what I've done in my code.

Also, the coding guide lines:

https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style#Error_handling

indicate NS_ENSURE_TRUE should not be used in new code. So, I think the code

nsresult rv;
nsCOMPtr<nsIPermissionManager> mgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
  return false;
}

is actually more in line with the guidelines than what you suggested. Should I still change it to your suggested snippet?
oh, I don't care too much whether NS_WARN_IF or NS_ENSURE_* is used.

(personally I do prefer NS_ENSURE_* in the code I write)
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Part 1 of 1 commit for this bug.

This patch incorporates the use of nsContentUtils::ObjectPrincipal suggested in comment 12.

The interdiff of this patch and the previous is as follows:

diff -u b/dom/media/webspeech/recognition/SpeechRecognition.cpp b/dom/media/webspeech/recognition/SpeechRecognition.cpp
--- b/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -20,14 +20,12 @@
 #include "AudioSegment.h"
 #include "endpointer.h"
 
-#include "js/TypeDecls.h"
-#include "jsfriendapi.h"
 #include "mozilla/dom/SpeechRecognitionEvent.h"
+#include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "nsIObserverService.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
-#include "nsJSPrincipals.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsQueryObject.h"
@@ -172,15 +170,12 @@
   }
 
   uint32_t speechRecognition = nsIPermissionManager::UNKNOWN_ACTION;
-
-  JSCompartment *compartment = js::GetObjectCompartment(aGlobal);
-  JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
-  nsCOMPtr<nsIPrincipal> principal = nsJSPrincipals::get(principals);
-
+  nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
   rv = mgr->TestExactPermissionFromPrincipal(principal, "speech-recognition", &speechRecognition);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
+
   bool inPrivileged = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);
 
   bool enableTests = Preferences::GetBool(TEST_PREFERENCE_ENABLE);


The try for this patch is here https://treeherder.mozilla.org/#/jobs?repo=try&revision=6154d67781ad
Attachment #8679499 - Attachment is obsolete: true
Attachment #8681517 - Flags: review?(bugs)
Comment on attachment 8681517 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Approval Request Comment
[Feature/regressing bug #]: NA
[User impact if declined]: Users will not be able to use speech recognition
[Describe test coverage new/current, TreeHerder]: Manual, tested apps with/with out 'speech-recognition' permission, the only thing covered in this bug.
[Risks and why]: low - If this code has a bug and speech recognition is not accessible, then things will be as before. If this code has a bug and speech recognition is accessible without the permission, then it will only access code that has had a through security review Bug 1162507
[String/UUID change made/needed]: None
Attachment #8681517 - Flags: approval-mozilla-aurora?
Ping
Comment on attachment 8681517 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

So should there be PROMPT_ACTION not ALLOW_ACTION for privileged apps, similar to camera?
Looks like audio-capture has that too.
Comment on attachment 8681517 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Looks like we have some bizarre special case code in
http://mxr.mozilla.org/mozilla-central/source/b2g/components/ContentPermissionPrompt.js#16

SpeechRecognition::IsAuthorized looks fine, but I think this needs some
feedback from people more familiar with b2g setup, so, like fabrice.


bool inPrivileged = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);
'inPrivileged' is a tad wrong name for the boolean there. Perhaps 'hasPermission'
Attachment #8681517 - Flags: review?(bugs) → review?(fabrice)
Comment on attachment 8681517 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Review of attachment 8681517 [details] [diff] [review]:
-----------------------------------------------------------------

r=me with nit addressed.

::: dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ +175,5 @@
> +  if (NS_WARN_IF(NS_FAILED(rv))) {
> +    return false;
> +  }
> +
> +  bool inPrivileged = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);

I agree with smaug, rename inPrivileged to hasPermission. The whole point of PermissionsTable.jsm is to not have to deal with privileged/certified status elsewhere.
Attachment #8681517 - Flags: review?(fabrice) → review+
fabrice, so what do you think about the value in PermissionsTable.js, should it be
PROMPT_ACTION or ALLOW_ACTION?
Flags: needinfo?(fabrice)
(In reply to Olli Pettay [:smaug] from comment #22)
> fabrice, so what do you think about the value in PermissionsTable.js, should
> it be
> PROMPT_ACTION or ALLOW_ACTION?

We already prompt for audio-capture, which seems like the step that really has privacy issues so I feel that ALLOW_ACTION is fine. 

Let's see what Paul thinks.
Flags: needinfo?(fabrice) → needinfo?(ptheriault)
But do we end up using the audio-capture check with speech API?
No, but the speech api only deals with the recognition part, not capture right? So if we prompt the user once for capture and then another time for recognition is that a good experience?

I see two use cases for recognition:
1) coupled with live capture
2) using a pre-recorded source.

For 1) We could actually just prompt on recognition and grant audio-capture at the same time with an "additional" permission like https://mxr.mozilla.org/mozilla-central/source/dom/apps/PermissionsTable.jsm#448 but that's not that clear for the user.

For 2) I'm not sure why we should prompt at all. If the app already has access to the source, it could send it somewhere over the network and do any processing remotely.
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Part 1 of 1 commit for this bug.

This patch differs from the one it replaces only in the renaming of a single variable inPrivileged=>hasPermission In particular the interdiff between the two patches is as follows:

diff -u b/dom/media/webspeech/recognition/SpeechRecognition.cpp b/dom/media/webspeech/recognition/SpeechRecognition.cpp
--- b/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -176,12 +176,12 @@
     return false;
   }
 
-  bool inPrivileged = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);
+  bool hasPermission = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);
 
   bool enableTests = Preferences::GetBool(TEST_PREFERENCE_ENABLE);
   bool enableRecognitionEnable = Preferences::GetBool(TEST_PREFERENCE_RECOGNITION_ENABLE);
   bool enableRecognitionForceEnable = Preferences::GetBool(TEST_PREFERENCE_RECOGNITION_FORCE_ENABLE);
-  return (inPrivileged || enableRecognitionForceEnable || enableTests) && enableRecognitionEnable;
+  return (hasPermission || enableRecognitionForceEnable || enableTests) && enableRecognitionEnable;
 }
 
 already_AddRefed<SpeechRecognition>
Attachment #8681517 - Attachment is obsolete: true
Attachment #8681517 - Flags: approval-mozilla-aurora?
Comment on attachment 8682940 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Approval Request Comment
[Feature/regressing bug #]: NA
[User impact if declined]: Users will not be able to use speech recognition
[Describe test coverage new/current, TreeHerder]: Manual, tested apps with/with out 'speech-recognition' permission, the only thing covered in this bug.
[Risks and why]: low - If this code has a bug and speech recognition is not accessible, then things will be as before. If this code has a bug and speech recognition is accessible without the permission, then it will only access code that has had a through security review Bug 1162507
[String/UUID change made/needed]: None
Attachment #8682940 - Flags: approval-mozilla-aurora?
I'm going to wait on Paul's "needinfo" before marking this as "checkin-needed".
(In reply to [:fabrice] Fabrice Desré from comment #25)
> No, but the speech api only deals with the recognition part, not capture
> right? 

You can use the speech API without first using some capturing API.
In fact, stream parameter for the start() is a Gecko only addition to the API.
Paul: Ping
I've been advised to add the "checkin-needed" keyword
Keywords: checkin-needed
(In reply to [:fabrice] Fabrice Desré from comment #23)
> (In reply to Olli Pettay [:smaug] from comment #22)
> > fabrice, so what do you think about the value in PermissionsTable.js, should
> > it be
> > PROMPT_ACTION or ALLOW_ACTION?
> 
> We already prompt for audio-capture, which seems like the step that really
> has privacy issues so I feel that ALLOW_ACTION is fine. 
> 
> Let's see what Paul thinks.

Yeh I was expecting allow action - the logic in comment 25 seems sound to me. I was mainly pushing for this bug since Im trying to not introduce any more "app type" checks. (I don't know what, if any, plan we have to expose this API to the web though, that might change UX, but for privileged apps, allow still seems appropriate).
Flags: needinfo?(ptheriault)
Comment on attachment 8682940 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

NOTE: Please see https://wiki.mozilla.org/Release_Management/B2G_Landing to better understand the B2G approval process and landings.

[Approval Request Comment]
Bug caused by (feature/regressing bug #): NA
User impact if declined: Users will not be able to use speech recognition
Testing completed: Manual, tested apps with/with out 'speech-recognition' permission, the only thing covered in this bug.
Risk to taking this patch (and alternatives if risky): low - If this code has a bug and speech recognition is not accessible, then things will be as before. If this code has a bug and speech recognition is accessible without the permission, then it will only access code that has had a through security review Bug 1162507
String or UUID changes made by this patch: None
Attachment #8682940 - Flags: approval-mozilla-aurora? → approval‑mozilla‑b2g44?
I had to back this out for introducing a hazard: https://treeherder.mozilla.org/logviewer.html#?job_id=16921494&repo=mozilla-inbound

https://hg.mozilla.org/integration/mozilla-inbound/rev/b02ebe7b7721

 Function '_ZN7mozilla3dom17SpeechRecognition12IsAuthorizedEP9JSContextP8JSObject|uint8 mozilla::dom::SpeechRecognition::IsAuthorized(JSContext*, JSObject*)' has unrooted 'aGlobal' of type 'JSObject*' live across GC call '_ZN8nsCOMPtrI20nsIPermissionManagerEC1ERK33nsGetServiceByContractIDWithError|nsCOMPtr<T>::nsCOMPtr(const nsGetServiceByContractIDWithError&) [with T = nsIPermissionManager]' at dom/media/webspeech/recognition/SpeechRecognition.cpp:167
     dom/media/webspeech/recognition/SpeechRecognition.cpp:167: Call(1,2, __temp_2 := do_GetService("@mozilla.org/permissionmanager;1",rv))
     dom/media/webspeech/recognition/SpeechRecognition.cpp:167: Call(2,3, __temp_1*.nsCOMPtr(0,__temp_2)) [[GC call]]
     dom/media/webspeech/recognition/SpeechRecognition.cpp:167: Assign(3,4, mgr := __temp_1*)
     dom/media/webspeech/recognition/SpeechRecognition.cpp:167: Call(4,5, __temp_1.~nsCOMPtr())
     dom/media/webspeech/recognition/SpeechRecognition.cpp:168: Call(5,6, __temp_5 := NS_FAILED_impl(rv*))
     dom/media/webspeech/recognition/SpeechRecognition.cpp:168: Call(6,7, __temp_4 := __builtin_expect((__temp_5* != 0),0))
     dom/media/webspeech/recognition/SpeechRecognition.cpp:168: Call(7,8, __temp_3 := NS_warn_if_impl((__temp_4* != 0),"NS_FAILED(rv)","/builds/slave/l64-br-haz_m-in_dep-0000000000/build/source/dom/media/webspeech/recognition/SpeechRecognition.cpp",168))
     dom/media/webspeech/recognition/SpeechRecognition.cpp:168: Assume(8,11, __temp_3*, false)
     dom/media/webspeech/recognition/SpeechRecognition.cpp:172: Assign(11,12, speechRecognition := 0)
     dom/media/webspeech/recognition/SpeechRecognition.cpp:173: Call(12,13, principal := ObjectPrincipal(aGlobal*))
Flags: needinfo?(kdavis)
Ok I'm on it....
Flags: needinfo?(kdavis)
Introduced permission 'speech-recognition' and used it in place of the privileged app-check.

Part 1 of 1 commit for this bug.

This patch differs from the one it replaces only in that it moves the use of aGlobal in SpeechRecognition::IsAuthorized before any other calls.

The problem was that the global JSObject* aGlobal could have been garbage 
collected as a result of the call to do_GetService(...) and if that
were to happen, then as a result of the manner in which Spidermonkey GC's
the pointer aGlobal would then become invalid.

The solution to this problem is to use aGlobal immediately before any call(s)
to do_GetService(...) thus not allowing GC to invalidate aGlobal.

The interdiff between this path and the last is

diff -u b/dom/media/webspeech/recognition/SpeechRecognition.cpp b/dom/media/webspeech/recognition/SpeechRecognition.cpp
--- b/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -163,6 +163,8 @@
 bool
 SpeechRecognition::IsAuthorized(JSContext* aCx, JSObject* aGlobal)
 {
+  nsCOMPtr<nsIPrincipal> principal = nsContentUtils::ObjectPrincipal(aGlobal);
+  
   nsresult rv;
   nsCOMPtr<nsIPermissionManager> mgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -170,7 +172,6 @@
   }
 
   uint32_t speechRecognition = nsIPermissionManager::UNKNOWN_ACTION;
-  nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
   rv = mgr->TestExactPermissionFromPrincipal(principal, "speech-recognition", &speechRecognition);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;

The try for this patch is running here https://treeherder.mozilla.org/#/jobs?repo=try&revision=65d1cf8406b5
Attachment #8682940 - Attachment is obsolete: true
Attachment #8682940 - Flags: approval‑mozilla‑b2g44?
Comment on attachment 8684311 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

NOTE: Please see https://wiki.mozilla.org/Release_Management/B2G_Landing to better understand the B2G approval process and landings.

[Approval Request Comment]
Bug caused by (feature/regressing bug #): NA
User impact if declined: Users will not be able to use speech recognition
Testing completed: Manual, tested apps with/with out 'speech-recognition' permission, the only thing covered in this bug.
Risk to taking this patch (and alternatives if risky): low - If this code has a bug and speech recognition is not accessible, then things will be as before. If this code has a bug and speech recognition is accessible without the permission, then it will only access code that has had a through security review Bug 1162507
String or UUID changes made by this patch: None
Attachment #8684311 - Flags: approval‑mozilla‑b2g44?
Keywords: checkin-needed
Target Milestone: --- → 2.6 S1 - 11/20
https://hg.mozilla.org/mozilla-central/rev/8d8eb725a4d9
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Comment on attachment 8684311 [details] [diff] [review]
Introduced permission 'speech-recognition' and used it in place of the privileged app-check

Approved for 2.5

Thanks
Attachment #8684311 - Flags: approval‑mozilla‑b2g44? → approval‑mozilla‑b2g44+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: