Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemPreferences.askForMediaAccess(mediaType) causes app to crash in macOS Mojave #19307

Closed
3 tasks done
fgladisch opened this issue Jul 17, 2019 · 16 comments
Closed
3 tasks done
Assignees

Comments

@fgladisch
Copy link

@fgladisch fgladisch commented Jul 17, 2019

Preflight Checklist

  • I have read the Contributing Guidelines for this project.
  • I agree to follow the Code of Conduct that this project adheres to.
  • I have searched the issue tracker for an issue that matches the one I want to file, without success.

Issue Details

  • Electron Version:
    • 5.0.7
  • Operating System:
    • MacOS 10.14.5 (Mojave)
  • Last Known Working Electron version:
    • N/A (Same issue in version 4.0.0, which introduced askForMediaAccess())

Expected Behavior

User should be prompted to grant microphone access.

Actual Behavior

App crashes with the following error report: https://gist.github.com/fgladisch/04f1c62b46dae37d55f05d001af7d7ee

To Reproduce

The app crashes as soon as this line is called:

const success = await systemPreferences.askForMediaAccess("microphone");

We have included a NSMicrophoneUsageDescription in our Info.plist as described here.

Here is the full function we use to request media access. It is called when the Permission Request Handler is invoked with the media permission. The app does not reach the catch Block, so the error is not logged. We tested this behaviour on 3 different machines.

async function askForMediaAccess(): Promise<boolean> {
  try {
    if (platform !== "darwin") {
      return true;
    }

    const status = await systemPreferences.getMediaAccessStatus("microphone");
    log.info("Current microphone access status:", status);

    if (status === "not-determined") {
      const success = await systemPreferences.askForMediaAccess("microphone");
      log.info("Result of microphone access:", success.valueOf() ? "granted" : "denied");
      return success.valueOf();
    }

    return status === "granted";
  } catch (error) {
    log.error("Could not get microphone permission:", error.message);
  }
  return false;
}
@codebytere codebytere self-assigned this Jul 17, 2019
@codebytere
Copy link
Member

@codebytere codebytere commented Jul 17, 2019

@fgladisch I see you didn't note a last working version: can you please check and add that?

@fgladisch
Copy link
Author

@fgladisch fgladisch commented Jul 17, 2019

We have the same issue in version 4.0.0, which introduced askForMediaAccess(). Maybe an MacOS update broke it?

@codebytere
Copy link
Member

@codebytere codebytere commented Jul 17, 2019

__CRASHING_DUE_TO_PRIVACY_VIOLATION__ seems to be the root cause here, indicating a permissions issue. i'll try to dig into this, and @miniak may also know more here.

@fgladisch
Copy link
Author

@fgladisch fgladisch commented Jul 17, 2019

We are also suspecting that it is related to code signing. We don't seem to be having this issue when the app is started in development mode.

Also pretty weird: The app (signed version) does not crash when started from Terminal. The prompt is coming from the Terminal in this case.

@fgladisch
Copy link
Author

@fgladisch fgladisch commented Jul 18, 2019

Update: The TCC log revealed what the problem is:

2019-07-18 09:34:02.381107+0200 0x667f8    Info        0x4f53d              13071  0    CLINQ: (TCC) [com.apple.TCC:access] Received asynchronous reply <dictionary: 0x600003ce00c0> { count = 2, transaction: 0, voucher = 0x600002a92120, contents =
	"problem_key" => <string: 0x6000007104e0> { length = 37, contents = "com.apple.security.device.audio-input" }
	"abort" => <string: 0x600000710660> { length = 243, contents = "This app has crashed because it has a hardened runtime and attempted to access privacy-sensitive data without an entitlement indicating its intent to access this data.  The app must have the 'com.apple.security.device.audio-input' entitlement." }
}

We created an entitlements file with this content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.device.audio-input</key>
    <true/>
  </dict>
</plist>

Unfortunately this also leads to an immediate crash (this time before asking for microphone access):
https://gist.github.com/fgladisch/534fd60c37b5308a51c14966985f0ffd

The signed app seems to be valid.

Code Signature:

$ codesign -vvv --deep --strict CLINQ.app
--prepared:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/CLINQ Helper.app
--prepared:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/Squirrel.framework/Versions/Current/.
--validated:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/CLINQ Helper.app
--validated:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/Squirrel.framework/Versions/Current/.
--prepared:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/Mantle.framework/Versions/Current/.
--validated:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/Mantle.framework/Versions/Current/.
--prepared:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/ReactiveCocoa.framework/Versions/Current/.
--validated:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/ReactiveCocoa.framework/Versions/Current/.
--prepared:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/Electron Framework.framework/Versions/Current/.
--validated:/Users/sipgate/code/clinq-app-web/dist/CLINQ.app/Contents/Frameworks/Electron Framework.framework/Versions/Current/.
CLINQ.app/: valid on disk
CLINQ.app/: satisfies its Designated Requirement

Certificate Check:

$ spctl -vvv --assess --type exec CLINQ.app
CLINQ.app: accepted
source=Developer ID
origin=Developer ID Application: sipgate GmbH (XXX)

@fgladisch
Copy link
Author

@fgladisch fgladisch commented Jul 18, 2019

Update 2: Disabling "Hardened Runtime" through electron-builder fixes the crash above:

{
  "mac": {
    "hardenedRuntime": false
  }
}

Everything seems to work now, including the microphone access prompt with the string set in NSMicrophoneUsageDescription.

@MarshallOfSound
Copy link
Member

@MarshallOfSound MarshallOfSound commented Jul 18, 2019

@fgladisch Please check the Hardened Runtime documentation for entitlements --> https://developer.apple.com/documentation/bundleresources/entitlements?language=objc

If you want the ability to access the microphone you need to add the com.apple.security.device.audio-input entitlement if you have hardened runtime enabled

@fgladisch
Copy link
Author

@fgladisch fgladisch commented Jul 18, 2019

As I've said above: we already did that. This leads to the process immediately crashing with this crash report:

https://gist.github.com/fgladisch/534fd60c37b5308a51c14966985f0ffd

The TCC log indicates that the entitlement is correctly set. The app crashes regardless. This seems to be a bug affecting Electron under MacOS 10.14.5 or higher.

@MarshallOfSound
Copy link
Member

@MarshallOfSound MarshallOfSound commented Jul 18, 2019

That crash appears to indicate that you did not codesign the binary correctly.

EXC_BAD_ACCESS (Code Signature Invalid)

You can verify your code signature using spctl

This seems to be a bug affecting Electron under MacOS 10.14.5 or higher.

Just as a general rule, if the thing is only crashing when certain code signing entitlements are applied, 99.99% of the time it isn't an electron issue, it's either invalid signing or an incorrect choice of entitlements 👍

@javer
Copy link

@javer javer commented Aug 23, 2019

@fgladisch

The TCC log indicates that the entitlement is correctly set. The app crashes regardless. This seems to be a bug affecting Electron under MacOS 10.14.5 or higher.

After adding the following entitlement my app stopped crashing just after start:

    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>

It seems that some part of Electron application (the framework itself or some part of the bundled Chromium) generates runtime code and puts it in the writeable memory area, that's why application immediately crashes with EXC_BAD_ACCESS (Code Signature Invalid), because code generated in runtime cannot be signed.

@MarshallOfSound @codebytere I believe it should be noted somewhere in the documentation, that any Electron application to be built with hardenedRuntime option (which is turned on by default in the latest electron-builder) requires some specific entitlements additionally to yours (camera, audio-input etc), otherwise the application will crash immediately, even if it does nothing. I have spent several hours of debugging to realize it.

The whole working entitlements.mac.plist for my use case:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.device.audio-input</key>
    <true/>
    <key>com.apple.security.device.camera</key>
    <true/>
  </dict>
</plist>

Also to be able to use camera and microphone in your application package.json for using with electron-builder should contain the following additional information (I leave it here for those who try to find a solution to be able to record video and audio in Electron 4, 5 and 6 under Mac OS 10.14+):

{
  "build": {
    "mac": {
      "entitlements": "build/entitlements.mac.plist",
      "extendInfo": {
        "NSCameraUsageDescription": "This app requires camera access to record video.",
        "NSMicrophoneUsageDescription": "This app requires microphone access to record audio."
      }
    }
  }
}

Without this information your application will be killed by OS after call systemPreferences.askForMediaAccess()

@Nodarii
Copy link

@Nodarii Nodarii commented Oct 9, 2019

It works for the electron-builder builds, but it doesn't for 'local' (electron .).
By the way, now(after fix: add default media usage strings to info.plist) it looks like it works without specifying extendInfo.

I would appreciate any help as I already spent whole day with this, thanks in advance 👍

@Nodarii
Copy link

@Nodarii Nodarii commented Oct 9, 2019

steps to reproduce what i'm talking about in previous comment:

  • npx create-electron-app not-working-media-access
  • in the index.js -> createWindow function insert code fragment 1
  • run application with the npm start

code fragment 1

systemPreferences.askForMediaAccess('microphone').then((isAllowed) => {
      console.log('isAllowed', isAllowed);
  });

question on stackoverflow:
https://stackoverflow.com/questions/58290668/electron-osx-systempreferences-askformediaaccess-crashes-app

@budifajriarzi
Copy link

@budifajriarzi budifajriarzi commented Nov 21, 2019

Update 2: Disabling "Hardened Runtime" through electron-builder fixes the crash above:

{
  "mac": {
    "hardenedRuntime": false
  }
}

Everything seems to work now, including the microphone access prompt with the string set in NSMicrophoneUsageDescription.

@fgladisch thanks !!! it works now !! this is what i looking for. once again, thanks man.
Running on MacOS Catalina 10.15.1

@madchops1
Copy link

@madchops1 madchops1 commented Apr 15, 2020

How can you notarize without hardened runtime?

@danmo
Copy link

@danmo danmo commented Aug 19, 2020

How can you notarize without hardened runtime?

you can't. this is the whole point of notarization: imposing e predictable hardened runtime.

@amitojsingh366
Copy link

@amitojsingh366 amitojsingh366 commented Mar 16, 2021

steps to reproduce what i'm talking about in previous comment:

* `npx create-electron-app not-working-media-access`

* in the `index.js` -> `createWindow` function insert code fragment 1

* run application with the `npm start`

code fragment 1

systemPreferences.askForMediaAccess('microphone').then((isAllowed) => {
      console.log('isAllowed', isAllowed);
  });

question on stackoverflow:
https://stackoverflow.com/questions/58290668/electron-osx-systempreferences-askformediaaccess-crashes-app

@Nodarii were you able to figure this out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
9 participants