-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Crash on macOS related to code signing and third-party JIT compilation #63952
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
Tagging subscribers to this area: @vitek-karas, @agocke, @VSadov Issue DetailsDescriptionOur .NET library hosts the V8 JavaScript engine – a native component that performs JIT compilation. On macOS, .NET code that consumes our library works correctly when run as an application, ( The crash occurs when V8 jumps into its JIT-compiled code. According to the Console application, the exception type is "EXC_CRASH (SIGKILL (Code Signature Invalid))". The native library that hosts V8 is signed with an official Microsoft signature. This affects arm64 (M1) hardware, and possibly x64 in some scenarios. It does not affect Linux or Windows. This issue was reported for our project here and here. Reproduction StepsAndrey Taritsyn has provided a minimal sample. Here are his instructions:
Expected behaviorThe tool should print out "Number of iterations: 999999" in green characters. Actual behaviorThe tool crashes abruptly. Regression?We've only reproduced this issue on arm64 (M1) hardware, so it appears to be new in .NET 6. Our tests on x64 and Rosetta did not crash with .NET 6 or .NET 5, but some users are reporting that the issue affects .NET 6 on x64. Known WorkaroundsIn a different scenario (see this issue), we were able to eliminate the crash by overwriting the official Microsoft code signature with the ad hoc linker signature as follows:
ConfigurationWe've confirmed the crash with .NET 6 in macOS 12.1 on the arm64 (M1) architecture. Other informationOur coded tests are not affected by this issue, apparently because they test only locally built, unsigned (or linker-signed) libraries.
|
@ClearScriptLib This sounds like the ARM64 signing restrictions to me. M1 Macs have new restrictions that force the binaries to be codesigned or MacOS will reject them. Could you run |
Hi @agocke,
That's what's so strange about this. Our library crashes only when it has an official Microsoft signature. And again,
We've confirmed the crash using Andrey's reproduction steps above in conjunction with our official binaries. There are no bad signatures, unless the official Microsoft signature is bad somehow. Anyway, here's the
Please let us know if we can provide any additional information. |
I wonder if this has something to do with a missing JIT entitlement. What does the following print for you?
|
Here's the output for
And here's the output for our officially signed native library:
Hmm, should our library also have the entitlements? |
I think your library needs the allow-jit entitlement. |
Hi @janvorli,
Interesting. We tried re-signing the library – first with only We did use a local signing identity for this experiment, as opposed to an official Microsoft signature or a developer account. Could that still be a problem? If so, we could try an official Microsoft signature with entitlements, once we figure out how to do that 😂. Thanks! |
Ok, thank you for trying. Can you try to sign the actual binary of the tool that gets built using e.g. the same entitlements as the |
@MarcoRossignoli should know for sure about the |
Hmm. This might not be the right place to look, but there's a JSON file in |
No, I don’t think you can add entitlements for the libraries. The strange thing is: this repro passes in my M1 machine. There seems to be an apphost if I install globally, but not locally. Both configurations actually run fine for me. |
Btw the apphost when I installed globally was in ~/.dotnet/tools |
At the moment on Arm64 M1 that run a arm64 muxer version(dotnet) we start the host using muxer self(current running process), something like To confirm that can you append
This will produce logs where we can verify how the host is started(also we did some changes between 6.0.1 and next 6.0.2/7 SDK). |
Hi @agocke,
Wow, really? It's a 100% crash repro here. You're seeing the line "Number of iterations: 999999" in green? Perhaps V8 doesn't detect a hot path on your machine and doesn't bother with JIT compilation. Very odd. |
Hi @MarcoRossignoli,
Will do. BTW, does that not work with |
I did a test on my M1 and confirm:
Repro
Logs
|
@ClearScriptLib I don't think so |
Hi @MarcoRossignoli, We have a trivial test project that confirms the crash via Thanks! |
My results: $ dotnet clearscript-v8-tester
Start script execution...
Number of iterations: 999999
$ dotnet tool run clearscript-v8-tester
Start script execution...
Number of iterations: 999999 Hmm, still trying to figure out what could be different. |
Ha! I updated to 6.0.1 and now it doesn't work. So something must have regressed |
Welp, still haven't figured it out though. Mac reports everything seems to have the right entitlements and is signed appropriately... I can confirm that dev-signing the |
Interestingly, linker-signing our native library ( We've reached out and requested instructions for including entitlements with the official signature. Presumably that's possible, since |
Nope. Just tried it. The crash still occurs. |
Ah, it looks like Support could be implemented for dotnet tools by having the tool install always use an apphost for executing the tool. The apphost is adhoc signed, so it will allow everything to execute. I've confirmed that if you run the apphost created during |
It basically prevents macOS from checking that only memory explicitly allocated as executable can be ever executable. If that helps, that seems to indicate that the V8 engine doesn't use the MAP_JIT flag in its mmap calls for executable memory. But then I am confused by the fact that dotnet run works. |
I haven't actually tested this in |
@janvorli I believe |
Ok, that seems to explain the problem then. |
Fascinating! If we understand correctly, we should be able to fix this by adding that entitlement to our dylib. We'll give it a try! |
I don't think that will work, Apple seems to state that entitlements must be in the executable: https://developer.apple.com/documentation/security/hardened_runtime
|
I filed dotnet/sdk#23640 for the SDK to explore more options for dotnet tools |
But then why does the crash go away if we adhoc-sign our dylib? |
Ad hoc signing seems to bypass quite a lot of restrictions, so I'm not sure. 😅 |
Yeah, adding that entitlement to our dylib doesn't work. Also, V8 does appear to be using MAP_JIT, but we haven't verified that in the debugger. |
I don't think there's anything more for us to do in the runtime, so I'm going to close this as a dup of dotnet/sdk#23640 |
Description
Our .NET library hosts the V8 JavaScript engine – a native component that performs JIT compilation.
On macOS, .NET code that consumes our library works correctly when run as an application, (
dotnet run
), but crashes when run from the test host (dotnet test
) or as a tool (dotnet tool run
).The crash occurs when V8 jumps into its JIT-compiled code. According to the Console application, the exception type is "EXC_CRASH (SIGKILL (Code Signature Invalid))". The native library that hosts V8 is signed with an official Microsoft signature.
This affects arm64 (M1) hardware, and possibly x64 in some scenarios. It does not affect Linux or Windows.
This issue was reported for our project here and here.
Reproduction Steps
Andrey Taritsyn has provided a minimal sample. Here are his instructions:
mkdir TemporaryProjects && cd TemporaryProjects
git clone https://github.com/Taritsyn/ClearScriptV8Tester.DotNetTool
cd ClearScriptV8Tester.DotNetTool
dotnet pack
cd ..
mkdir TestDotNetTool && cd TestDotNetTool
dotnet new tool-manifest
dotnet tool install ClearScriptV8Tester.DotNetTool --add-source ../ClearScriptV8Tester.DotNetTool/nupkg
dotnet tool run clearscript-v8-tester
Expected behavior
The tool should print out "Number of iterations: 999999" in green characters.
Actual behavior
The tool crashes abruptly.
Regression?
We've only reproduced this issue on arm64 (M1) hardware, so it appears to be new in .NET 6. Our tests on x64 and Rosetta did not crash with .NET 6 or .NET 5, but some users are reporting that the issue affects .NET 6 on x64.
Known Workarounds
In a different scenario (see this issue), we were able to eliminate the crash by overwriting the official Microsoft code signature with the ad hoc linker signature as follows:
codesign --sign - --options linker-signed --force ClearScriptV8.osx-arm64.dylib
Configuration
We've confirmed the crash with .NET 6 in macOS 12.1 on the arm64 (M1) architecture.
Other information
Our coded tests are not affected by this issue, apparently because they test only locally built, unsigned (or linker-signed) libraries.
The text was updated successfully, but these errors were encountered: