Closed Bug 1503694 Opened 7 years ago Closed 5 years ago

FeaturePolicy: Hangouts cannot access microphone from Gmail

Categories

(Web Compatibility :: Site Reports, defect, P1)

defect

Tracking

(firefox-esr60 unaffected, firefox63 unaffected, firefox64+ disabled, firefox65+ disabled, firefox66- disabled, firefox67- disabled, firefox74+ wontfix, firefox75+ wontfix, firefox76+ fixed, firefox77+ fixed)

VERIFIED FIXED
Tracking Status
firefox-esr60 --- unaffected
firefox63 --- unaffected
firefox64 + disabled
firefox65 + disabled
firefox66 - disabled
firefox67 - disabled
firefox74 + wontfix
firefox75 + wontfix
firefox76 + fixed
firefox77 + fixed

People

(Reporter: Mardak, Unassigned)

References

(Blocks 2 open bugs, Regression)

Details

(5 keywords, Whiteboard: [domsecurity-active])

Attachments

(2 files)

Attached image no microphone
[Tracking Requested - why for this release]: Hangouts calling is broken 11:34.93 INFO: Last good revision: 3eb04f5363eb661fa2ae544a934a7ace85b65282 11:34.93 INFO: First bad revision: 8f74f5dbf5c0d12bebf84841b8553b179b7d04a0 11:34.93 INFO: Pushlog: https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?fromchange=3eb04f5363eb661fa2ae544a934a7ace85b65282&tochange=8f74f5dbf5c0d12bebf84841b8553b179b7d04a0 I previously Allow Microphone permission for https://hangouts.google.com but trying to make a call results in no microphones selected (see attachment). If I make a call directly from https://hangouts.google.com, a microphone does get selected. If I remove the existing Allow permission, I can temporarily allow from https://hangouts.google.com. However, if I try to make a call from Gmail without the Allow permission, I don't even get prompted to temporarily allow.
Is the allow permission something like: microphone 'src' ? And is that in an sandboxed iframe? If yes, our implementation follows the spec and FeaturePolicy blocks the feature because of this: https://github.com/WICG/feature-policy/issues/230
Flags: needinfo?(amarchesini) → needinfo?(edilee)
(In reply to Andrea Marchesini [:baku] from comment #1) > our implementation follows the spec and FeaturePolicy blocks the feature > because of this: https://github.com/WICG/feature-policy/issues/230 drno, if the breakage in 63 is intended, does Google already know? baku, i'm assuming the "something like: microphone 'src'" is referring to a content security policy? There's no meta tag, but inspecting the subdocument request shows: script-src 'nonce-0R99clUSk0ZqcdITq526W…' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /webchat/u/0/_/cspreport How do I check if it's a sandboxed iframe?
Flags: needinfo?(edilee)
Flags: needinfo?(drno)
Flags: needinfo?(amarchesini)
The breakage is in 63? I didn't realize that! FeaturePolicy is not enabled in 63, so it should be something else. I'll investigate it tomorrow.
Flags: needinfo?(amarchesini)
Sorry! I misspoke. This is affecting 64. The regressing bug landed towards the end of 64.
Ed, can you check if dom.security.featurePolicy.enabled is set to false? Are you using beta? 64 now is beta and FeaturePolicy is disabled. Everything should work fine.
Flags: needinfo?(edilee)
For me dom.security.featurePolicy.enabled is only true in Nightly 65, but false for Beta and Release. Doesn't sound like breakage is intended. And no Google is probably not aware.
Flags: needinfo?(drno)
Ah indeed. I ran mozregression using nightly builds, so it found Nightly 64. Toggling dom.security.featurePolicy.enabled to false in my running Nightly 65 immediately fixes the problem for me. Good to hear this doesn't actually affect beta/release 64. (Not entirely sure what the status flag should be for preffed off affectedness, but assuming featurePolicy.enabled stays enabled only in nightly as done in bug 1497486, we probably don't need to fix this for 64) I can't find a meta bug for FeaturePolicy but this bug might want to block turning the feature on for wider audiences.
Flags: needinfo?(edilee)
See Also: → 1497486
Summary: Hangouts cannot access microphone from Gmail → FeaturePolicy: Hangouts cannot access microphone from Gmail
Assignee: nobody → amarchesini
Status: NEW → ASSIGNED
Priority: -- → P2
Whiteboard: [domsecurity-active]
The featurePolicy.enabled pref is still only enabled on Nightly, so IIUC, Fx65 shouldn't be affected at this point.

Andrea, are there plans to activate FeaturePolicy for 67 and not just in Nightly? If not, I'll mark this bug as disabled for 67 as well. Thanks

Flags: needinfo?(amarchesini)

No plans for 67. Let's mark it as disabled. Thanks.

Flags: needinfo?(amarchesini)

This bug now affects version 74. Setting dom.security.featurePolicy.enabled to false still provides a workaround.

[Tracking Requested - why for this release]: Hangouts issues via Gmail

I never use this functionality so I don't know how it's supposed to work but I can see the microphone picker is empty for me.

I'm not sure why this bug wasn't addressed before shipping.

Flags: needinfo?(jhofmann)
Flags: needinfo?(ckerschb)
Priority: P2 → --
Regressed by: 1617219

This issue sounds serious. Baku, are you still working on this bug?
Should we set the priority as P1?

Flags: needinfo?(amarchesini)

No, I'm not. But the issue was related to the default value for microphone and camera.
Probably 'self' is too restrictive.

Ethan, do you know who can take this bug? If nobody, I can.

Flags: needinfo?(amarchesini) → needinfo?(ettseng)

It would be great if you can take this bug (actually, you're already the assignee, which is why I needinfo'd you). Thanks! :)

Flags: needinfo?(ettseng)
Priority: -- → P1

That would be great, thanks Baku! Let me know I can help.

FWIW I wasn't aware that this bug existed, it wasn't blocking the right bugs :(

Flags: needinfo?(jhofmann)
Flags: needinfo?(ckerschb)
Keywords: site-compat

Baku, do you have any updates on this bug? We're wondering if we can get the fix uplift to Beta 75?

Flags: needinfo?(amarchesini)

:pascalc - did you mark this '+' for 74 to drive or ride-along for a dot release?

(In reply to Tim Spurway [:tspurway] from comment #19)

:pascalc - did you mark this '+' for 74 to drive or ride-along for a dot release?

potential ride-along

The spec-mandated default here is "self", which I believe is correct.

I see no evidence the hangouts iframe here in https://mail.google.com/mail/u/0/ is sandboxed. But I also don't even see any allow= at all:

<iframe src="https://hangouts.google.com/webchat/u/0/frame?v=...&prop=gmail#epreld"
 scrolling="no" class="a7A" width="262" height="198" frameborder="0"></iframe>

The (top) page domain here is mail.google.com and the iframe is hangouts.google.com which are different sub-domains of google.com which means they're different domains, so for microphone to work I believe the top domain MUST delegate microphone policy to the iframe's domain using e.g. allow="microphone 'src'" or allow="microphone https://hangouts.google.com" (ditto camera).

Why this works in Chrome then (and Safari too) is a mystery, since they both appear to block between different sub-domains on e.g. github.io correctly. i.e. top domain must delegate using allow= for cam/mic before it works.

Any chance other browsers have some builtin exception for *.google.com?

In any case, I suggest reaching out to the gmail team on this.

github.io is on the public suffix list though so that's kind of different?

(In reply to Julien Cristau [:jcristau] from comment #22)

github.io is on the public suffix list though so that's kind of different?

Good question. I don't know how this affects feature policy. Anne, do I need my own domain to test this?

Flags: needinfo?(annevk)

STRs (since it wasn't obvious):

  1. Open https://mail.google.com/mail/u/0/ and log in
  2. In the bottom left, click the 💬 hangouts symbol to reveal hangouts pane
  3. There, click the ➕ plus sign to search for someone to chat (e.g. your second email account)
  4. There, start chat to open chat iframe in the lower right corner
  5. There, click the 📞 handset symbol to call them by phone, to open adjacent call iframe
  6. There, click the ⚙️ gears symbol to see the image in comment 0.

Someone pointed out I may be looking at the wrong iframe, as there's signs of allow="microphone *" in the code. Will investigate more tomorrow.

  c = b.b.b('IFRAME', {
    id: b.id || '',
    src: c,
    'class': 'talk_iframe',
    style: 'border-style:none; width:100%; height:' + (a.h ? '100%' : '400px'),
    frameborder: '0',
    allow: 'microphone *; autoplay *; microphone'
  });

No, feature policy doesn't do any site-related checks.

Flags: needinfo?(annevk)

Looks like gmail is running different (non-working) code in Firefox compared to (working) Safari & Chrome. Paste this into web console:

[...document.getElementsByTagName("IFRAME")].filter(({src}) => src.includes("hangouts")).map(({allow, src}) => ({allow, src}))

Safari:

{"allow":"microphone *; autoplay *; microphone","src":"https://hangouts.google.com/webchat/u/0/load?client=sm&prop..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame2?v=1584912068&pvt=AMP3uWb_QRm0aqwps8YB2IQM8g-VMQY..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame2?v=1584912068&pvt=AMP3uWb_QRm0aqwps8YB2IQM8g-VMQY..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame?v=1584912068&hl=en&pvt=AMP3uWb_QRm0aqwps8YB2IQM8g..."},
{"allow":"microphone *; autoplay *; microphone","src":"https://hangouts.google.com/hangouts/_/hscv?pvt=AMP3uWb_QRm..."}

Chrome:

{"allow":"microphone *; autoplay *; microphone","src":"https://hangouts.google.com/webchat/u/0/load?client=sm&prop..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame2?v=1584912068&pvt=AMP3uWaAmNEb7PpzFmgs9p1ZRhNJ9pC..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame?v=1584912068&hl=en&pvt=AMP3uWaAmNEb7PpzFmgs9p1ZRh..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame?v=1584912068&hl=en&pvt=AMP3uWaAmNEb7PpzFmgs9p1ZRh..."},
{"allow":"microphone *; autoplay *; microphone","src":"https://hangouts.google.com/hangouts/_/hscv?pvt=AMP3uWaAmNE..."}

Firefox:

{"allow":"microphone *; autoplay *; microphone","src":"https://hangouts.google.com/webchat/u/0/load?client=sm&prop..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame2?v=1584912068&pvt=AMP3uWZpwRzcrWVTPvXzx1NGZxdbGm9..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame2?v=1584912068&pvt=AMP3uWZpwRzcrWVTPvXzx1NGZxdbGm9..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/frame?v=1584912068&hl=en&pvt=AMP3uWZpwRzcrWVTPvXzx1NGZx..."},
{"allow":"","src":"https://hangouts.google.com/webchat/u/0/blank"}

The first and last iframe appear to have allow lists for microphone in Safari and Chrome, but not Firefox.

Besides having no allow list, the last iframe in Fireox, https://hangouts.google.com/webchat/u/0/blank is also different.

A chrome-js breakpoint (in createOffer & enumerateDevices) reveals it in turn contains its own embedded iframe:

> this._win.windowGlobalChild.browsingContext.embedderElement
<iframe id="xpcpeernwwJ" name="xpcpeernwwJ" allow="microphone *; autoplay *; microphone" style="visibility: hidden; top:…on: fixed; z-index: -1;" src="https://hangouts.google.…e.com%2Frobots.txt%22%7D">

> this._win.windowGlobalChild.browsingContext.embedderElement.ownerDocument
HTMLDocument https://hangouts.google.com/webchat/u/0/blank

As we can see, the innermost iframe does contain allow="microphone *; autoplay *; microphone" but is itself inside another iframe that doesn't.

Since feature policy requires allow lists all the way up to the top document, before features are delegated down, Firefox works to spec and like every other browser here.

The reason it works in Chrome and Safari is because gmail uses different code there.

The fix is to reach out to the gmail team to fix this, presumably by either adding allow="microphone *; autoplay *; microphone" to the blank iframe, or better, use the same code as in Safari and Chrome if possible.

Adam, can you help with this?

Flags: needinfo?(astevenson)

I've also investigated the issue. I have a quick update to share.
My focus is the "microphone" feature-policy. The chain of iframe is this:

A:  mail.google.com/... FeaturePolicy=0x5647940605c0
  -> B: hangouts.google.com/webchat/... FeaturePolicy=0x5647996b3620
    -> C: hangouts.google.com/webchat/... FeaturePolicy=0x56479b4500d0
      -> D: hangouts.google.com/hangouts/... FeaturePolicy=0x564794a44a70
        -> E: hangouts.google.com/hangouts/... FeaturePolicy=0x56479a916ef0

top-level A
Directives: none. (we don't support feature-policy http header)
Result: microphone allowed only for mail.google.com

Iframe B
Directives: none.
Inheritage: It inherits feature denied for microphone. It doesn't have any custom feature-policy directives.
Result: microphone denied.

Iframe C
Directives: none.
Inheritage: It inherits feature denied for microphone. It doesn't have any custom feature-policy directives.
Result: microphone denied.

Iframe D
Directives: "microphone *" -> Feature allowed for all.
Inheritage: It inherits feature denied for microphone. It doesn't have any custom feature-policy directives.
Result: microphone denied.

Iframe E
Directives: none
Inheritage: It inherits feature "microphone" denied.
Result: microphone denied.

Result: the feature "microphone" is denied.

Flags: needinfo?(amarchesini)
Attached file test-case

In this file, I tried to reproduce the iframe hierarchy of gmail.com. Open it in a webserver, on localhost.
I use navigator.mediaDevices.enumerateDevices() because this is what gmail uses to check if the microphone is allowed.

Gmail team filed this as internal issue http://b/152904726

Flags: needinfo?(astevenson)
Whiteboard: [domsecurity-active] → [domsecurity-active][wfh]

If I understand correctly this is not in the hands of the security engineering team then. Let’s move to Web Compat. Mike, assuming that this may not be highest-priority for Gmail folks can we ship an intervention for this in the meantime?

Assignee: amarchesini → nobody
Status: ASSIGNED → NEW
Component: DOM: Security → Desktop
Flags: needinfo?(miket)
Product: Core → Web Compatibility

Tom, how hard do you think it would be to cook up an intervention for this?

Flags: needinfo?(miket) → needinfo?(twisniewski)
Component: Desktop → Interventions

This quick hack is working for me on baku's test-case (when run before the rest of the script):

const orig = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "allow");
Object.defineProperty(HTMLIFrameElement.prototype, "allow", {
  get: orig.get,
  set: function(val) {
    orig.set.call(this, "microphone *");
  },
  configurable: true,
});

But I'm not sure if the problematic Hangouts page is dynamically adding the iframes with JS just like in that test-case. baku?

Flags: needinfo?(twisniewski) → needinfo?(amarchesini)

If I understand correctly this code is replacing the allow attribute of all iframes with "microphone *"? That seems too insecure to ship. This would give even ad iframes the ability to listen in on your calls.

I think preferably we could poll for the iframe chain mentioned in comment 27 and add a microphone allow attribute to it only.

Thoughts? :)

Flags: needinfo?(twisniewski)

I agree with Johann. Your code would work on Hangouts, allowing the use of the microphone to any iframes. Better to follow the iframe chain.

Flags: needinfo?(amarchesini)

I of course agree, I just didn't know which specific domains to allow through, so I went with a general proof-of-concept :)

Since I'm not hearing "no" from baku, it seems the answer to Mike is: yes, we can use code like I suggested, we'd just want to limit it to run only on the specific iframes we want to let through. For instance we could presumably just add an if-statement to it like this (and ensure it only runs in the first place on frames from GMail/Hangouts as usual in the webcompat addon):

const orig = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "allow");
Object.defineProperty(HTMLIFrameElement.prototype, "allow", {
  get: orig.get,
  set: function(val) {
    if (document.domain == "hangouts.google.com") {
       val = "microphone *";
    }
    orig.set.call(this, val);
  },
  configurable: true,
});
Flags: needinfo?(twisniewski)

Thanks Tom. Let me file a separate bug for the actual intervention.

Component: Interventions → Desktop
See Also: → 1629926

Hi Mike, is this bug then obsolete? Should we track the other one for releases as mitigation for this regression?

Flags: needinfo?(miket)

Since the intervention wouldn’t solve the issue just mitigate it and this bug has a lot of context I would vote for keeping it open :)

Agree with Johann, we can keep this one open (but probably not worth tracking once we ship the intervention).

Flags: needinfo?(miket)

The intervention should be available in 76.0b7 shipping soon.

Note that we're also in contact with Gmail folks and according to them a fix will be available soon. Let's monitor the situation and evaluate whether we need to ship the intervention. It's definitely good to have it for now.

Oana, can you verify that the next Beta fixes this issue (with the intervention applied)? You should see "GMail Hangouts microphone fix" in about:compat to know you have the right Beta. :)

Flags: needinfo?(oana.arbuzov)

Mike, with the "GMail Hangouts microphone fix" intervention enabled (and if I am fast enough to access the ⚙️ "Settings" - I don't have credit) the issue is not reproducible according to comment 24 scenario - Microphone permission is temporary allowed and Microphone field is populated.
https://prnt.sc/s4j513
https://prnt.sc/s4j25t
Disabling the intervention Microphone permission is not asked and Microphone field remains empty.

Tested with:
Browser / Version: Firefox Beta 76.0b7
Operating System: Windows 10 Pro

Flags: needinfo?(oana.arbuzov)

Calling this fixed for Fx76 via webcompat intervention.

This was fixed by Gmail today (not sure if that means FIXED or WORKSFORME). It would be great if everyone could confirm that this is fixed without the intervention applied (you can disable it in about:compat).

Thanks!

Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → WORKSFORME

Yep, verified.

(Typically we close things as fixed if the site does something to fix it)

Status: RESOLVED → VERIFIED
Resolution: WORKSFORME → FIXED
Has Regression Range: --- → yes
Keywords: enterprise
Whiteboard: [domsecurity-active][wfh] → [domsecurity-active]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: