Please Note: The project is not a Xamarin.Mac project but a .NET 4.5 project, I've seen a lot of similar questions asked here where answers come from people who seem to know a lot of about mono in general. If this is the wrong place to ask this. I will take down this post.
I've been struggling with this for a month now, unable to bundle a .NET exe with mono such that it runs correctly on a target macOS 10.14 after having been codesignged with strict and hardened runtime options. Either working bundle cannot be signed, or I have a non-working bundle that can be signed.
I have a test project on github, but my account is too new here to share it. The app is a simple "hello world" .NET console app with no external dependencies.
I'll repeat here:
I found a related bug on xamarin bugzilla but cannot share it here. I cannot find any other references to this issue on mono github / stack overflow / xamarin community forums
Requirements:
- Mac OS 10.14.6
- Visual Studio for Mac 8.3.9
- XCode 11
- Mono 6.4.0
- A Signing Certificate (self signed used below)
Steps to reproduce issue(s)
Case 1:
1. compile a .NET 4.5 console app in VS with release config, produces testConsoleApp.exe
2. in the project folder execute the below command of mkbundle with --simple flag
- produces testConsoleApp binary which works when run on the command line "./bin/Release/testConsoleApp"
mkbundle -v -o testConsoleApp --deps --simple testConsoleApp.exe --sdk $MONOROOT/Versions/Current
codesign -f --strict --verbose --entitlements $ENTSFILE -o runtime -s "$CERT" testConsoleApp --timestamp
Expected: signing to be successful
Actual: signing is unsuccessful, console error: "testConsoleApp: main executable failed strict validation"
Case 2:
1. compile a .NET 4.5 console app in VS with release config, produces testConsoleApp.exe
2. in the project folder execute the below command of mkbundle with -L flag and passes mono directory for the path
- produces testConsoleApp binary which seg faults, error code 11, when run on the command line "./bin/Release/testConsoleApp"
- stack trace below, can't link too it...
mkbundle -v -o testConsoleApp --deps testConsoleApp.exe -L $MONOROOT/Versions/Current/lib/mono/4.5/
codesign -f --strict --verbose --entitlements $ENTSFILE -o runtime -s "$CERT" testConsoleApp --timestamp
Expected: signing to be successful
Actual: signing is successful, but the program still seg faults when executed "./bin/Debug/testConsoleApp"
[X ] macOS
[ ] Linux
[ ] Windows
Process: testConsoleApp [71605]
Path: /Users/*/testConsoleApp
Identifier: testConsoleApp
Version: 0
Code Type: X86-64 (Native)
Parent Process: bash [53460]
Responsible: testConsoleApp [71605]
User ID: 490749117
Date/Time: 2019-11-22 11:51:05.126 -0500
OS Version: Mac OS X 10.14.5 (18F132)
Report Version: 12
Anonymous UUID: DF34AE02-2897-021E-660E-FE6E4146A6B8
Sleep/Wake UUID: B3602C3E-8214-4A17-91B8-05C3B13F041F
Time Awake Since Boot: 270000 seconds
Time Since Wake: 8300 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [71605]
VM Regions Near 0:
-->
__TEXT 000000010f3cb000-000000010f3cc000 [ 4K] r-x/r-x SM=COW /Users/*
Application Specific Information:
dyld2 mode
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 ??? 000000000000000000 0 + 0
1 testConsoleApp 0x000000010f3cbb16 mono_mkbundle_init + 22 (temp.c:158)
2 testConsoleApp 0x000000010f3cbcc8 main + 376 (temp.c:235)
3 libdyld.dylib 0x00007fff7e6883d5 start + 1
Thread 0 crashed with X86 Thread State (64-bit):
rax: 0x00007fcf78005070 rbx: 0x0000000000000000 rcx: 0x0000000000000002 rdx: 0x0000000000000001
rdi: 0x000000010f3cc0d0 rsi: 0x0000000000000002 rbp: 0x00007ffee0834420 rsp: 0x00007ffee0834418
r8: 0x00000000f7800508 r9: 0x00000000fffffeff r10: 0x00007fcf78000000 r11: 0x000000000000000e
r12: 0x0000000000000000 r13: 0x0000000000000000 r14: 0x0000000000000000 r15: 0x0000000000000000
rip: 0x0000000000000000 rfl: 0x0000000000010246 cr2: 0x0000000000000000
Logical CPU: 6
Error Code: 0x00000014
Trap Number: 14
Binary Images:
0x10f3cb000 - 0x10f3cbffb +testConsoleApp (0) <5F5740B6-64AC-319F-B350-DD9F457A1E67> /Users/*/testConsoleApp
0x10f865000 - 0x10fc5dff7 +libmonosgen-2.0.1.dylib (0) /Library/Frameworks/Mono.framework/Versions/6.4.0/lib/libmonosgen-2.0.1.dylib
0x11f40e000 - 0x11f4786ef dyld (655.1.1) /usr/lib/dyld
So when I checked the closest thing we have to a sample on this, I found out it was broken.
After fixing that up - https://github.com/xamarin/mac-samples/pull/122
I have a few steps you can consider doing:
<key>NSPrincipalClass</key> <string>NSApplication</string> <key>NSMainStoryboardFile</key> <string>Main</string> <key>XSAppIconAssets</key> <string>Assets.xcassets/AppIcon.appiconset</string>
<key>LSUIElement</key> <true/>
Then you can startup your application in Main with:
static void Main () { NSApplication.Init (); // Your stuff here
Once you have that running, you can look into signing / hardening using the XM tools built in.
Answers
This seems like more of an issue for mono.
I haven't used mkbundle in years, but you should unpack the output and confirm:
Another thing is that you are enabling the hardened runtime with:
-o runtime
If you really want that, you need to validate that the correct entitlements are included, including JIT, or you will crash exceptionally early in application launch.
tl;dr; - I'm not sure how well mkbundle supports signing, and very uncertain if it supports hardened runtime - but this is a mono issue with mkbundle.
Thanks Chris,
I created an issue on the mono github last week. I thought that I might get more eyes here.
I did forget to include the entitlements used, but the bundle is crashing before being signed, before adding hardened runtime. I'll update the OP with the entitlements used. EDIT: Hmm I guess you can't update an OP. I'll add the entitlements to the bottom of this post.
mkbundle does not create a .app or an "unpackable" output the way Xamarin.mac does. It creates a packed binary of the executable and it's dependencies along with the mono run time. There is no associated Info.plist , maybe this is the issue? Does codesign expect other artifacts to be present along with the object being signed? Can only .app's or .pkg's be signed, not arbitrary binaries?
When I inspect the output of a built Xamarin.mac .app, I do see a generic binary in Contents/MacOS . But I'm having trouble getting VS configured to do the codesigning, so that I can inspect what actually gets signed when I let VS handle it. Can you help out in providing what artifacts of a Xamarin.mac .app get signed? Maybe the Xamarin.mac project I am using isn't the greatest example as it's wrapping another .NET project, such that within Contents/MonoBundle I have .exe and DLL . I am very curious if VS would sign all of these or not.
EDIT:
Note: the entitlements being used in entitlements.plist, which most likely are not necessary. The disabling of library validation was necessary due to the dynamic library importing being blocked due to the signing not being trusted.
Thanks Chris,
I created an issue on the mono github last week. I thought that I might get more eyes here.
I did forget to include the entitlements used, but the bundle is crashing before being signed, before adding hardened runtime. I'll add the entitlements used to the bottom of this post.
mkbundle does not create a .app or an "unpackable" output the way Xamarin.mac does. It creates a packed binary of the executable and it's dependencies along with the mono run time. There is no associated Info.plist , maybe this is the issue? Does codesign expect other artifacts to be present along with the object being signed? Can only .app's or .pkg's be signed, not arbitrary binaries?
When I inspect the output of a built Xamarin.mac .app, I do see a generic binary in Contents/MacOS . But I'm having trouble getting VS configured to do the codesigning, so that I can inspect what actually gets signed when I let VS handle it. Can you help out in providing what artifacts of a Xamarin.mac .app get signed? Maybe the Xamarin.mac project I am using isn't the greatest example as it's wrapping another .NET project, such that within Contents/MonoBundle I have .exe and DLL . I am very curious if VS would sign all of these or not.
entitlements used:
Yeah, I honestly have no idea how mkbundle works under the hood.
I suspect that it may be rather difficult to get a mkbundl'ed app to have the correct structure for hardened runtime, but on the other hand it might be considered a "single file" application and be under different rules.
My understanding is not full, but I believe there are three buckets of signed things:
You can look at the msbuild output (Errors Tab -> Build Output) to see what we're doing as part of the build. Roughly however we:
Invoke mmp to bundle things:
Invoke codesign (Apple tool) to sign that bundle
The mono folks might be able to give you more info, but if you really want a macOS application, and it isn't a command line tool, it might make sense to use Xamarin.Mac as your packager / launcher.
If you set full or system as your target framework you should be able to get most things working under Xamarin.Mac.
Yes I imagine I could wrap the existing console app that I have in a xamarin.mac app, but I think that that will require a lot more work, that I'm not willing to take on just yet.
I've found docs.microsoft.com/en-us/xamarin/mac/app-fundamentals/console#creating-the-console-app which suggests I can add some of the xamarin dlls to an existing console app and then "run it", but the example shows that the output is a .exe and doesn't indicate how to run it. So I'm not sure that the article is of any use.
The beauty of mkbundle is that it will pack the mono runtime into the binary itself so that you don't have to have the mono runtime installed on the target machine.
EDIT: oh, the article continues on to use mkbundle... I'll investigate if I've missed anything.
Xamarin.Mac apps also bundle mono into the app bundle. I understand not wanting to bite off all of that working for signing.
The hard part of headless is handling the libxammac.dylib. In a single file configuring, there isn't a great place to put it.
The resulting bundle from that example crashes and cannot be signed. Could I bother you try run through the steps in that article?
@ChrisHamons
I also found and old thread you commented on https://forums.xamarin.com/discussion/66916/how-to-construct-c-console-application-which-will-be-able-to-consume-mac-specific-api-keychain
Do you have any updated articles for how one best would port or wrap an existing .net console app in a xamarin mac app?
I want to at least understand how much work might be required. I don't need to pass command line args to my "daemon", it will be launched via a plist in /Library/LaunchDameons/
Should I start a new thread asking that specific question? Do you know of an open one that I could add to?
So when I checked the closest thing we have to a sample on this, I found out it was broken.
After fixing that up - https://github.com/xamarin/mac-samples/pull/122
I have a few steps you can consider doing:
Then you can startup your application in Main with:
Once you have that running, you can look into signing / hardening using the XM tools built in.
The resulting bundle from that example crashes and cannot be signed. Could I bother you try run through the steps in that article?
Sorry your message got caught in the spam filter.
It looks like you are hitting this line:
https://github.com/xamarin/xamarin-macios/blob/master/src/ObjCRuntime/Runtime.cs#L256
which was added as part of our 2018-08 mono integration branch. That is 5.18.x.
Can you commit your sample to a repo somewhere I can try it, and confirm what version of mono you are building against?
Hello @ChrisHamons,
I wanted to come back around and thank you for your help back in November. We are able to get our product working! codesigned correctly with hardened runtime such that notarization passes!
Your post above worked like a charm, creating a new Xamarin App that called the entry point to our console app, just as you suggested.
All we needed in the new main.cs
Where our console app assembly is added as a reference to the project. Also had to make the Access Modifiers of the class and Main() function public so they could be referenced in the new project.
Building this new project with msbuild, or within Visual Studio, produced an .app bundle that could be signed with hardened runtime.
Thanks again, I'm glad we are were able to get off of mkbundle, and have some peace-of-mind knowing there is an active Xamarin dev community.
Awesome, glad a Xamarin.Mac application could do the heavy codesign lifting for you and you were able to get off mkbundle!