HinTak/mono-modification

Investigating codesign fix script usage

Closed this issue · 27 comments

Spit out from mono/mono#17881 (comment) proprietory app ThumbGenerator

@nor0x - I have looked at the binary you sent, and the problem seems to be simple: the mono folks have started signing the main mono executables, so it indeed already has a signature. This affects people running mkbundle natively on Mac OS X to try to bundle for Mac OS X. (I wasn't - I was building on linux to bundle for mac os x).
The mkbundle process puts bundled dll's after it, and so the script refuses to run. So here are three possible answers:

  • I have updated the script to detect this case, and it would go ahead and modifying the binary to prepare it for re-sign.
    The resulting binary is still going to be slightly strange; so you may have to specify -f (for forcing re-sign) when you sign. If it refuses to sign even if forced, I'd like to know; if you managed to re-sign, with or without specifying force re-sign, I'd like to see the resulting binary. Either way, I'll need to update the script with some relevant messages at least.

The script is updated to print this the first time you run it:
"mkbundle with Native Mac OS X/default runtime detected. This may not work."
on repeated run it, should just stop at:
"End of Signature not at end of file: 4699296"

  • you could try copying and stripping the main mono executable's signature first. There are various tutorial online on doing that. (if you ask nicely and if the first answer above does not work, I might even write a script to do that...)

  • you could try to do what I did, which was ... --cross mono-5.20.1-osx-10.9-x64 ..., plus using binaries with backported changes (here in this repo, under ./mono-5.20.1.34/mono/mini, ./mono-6.6.0.166/mono/mini, ./mono-6.8.0.105/mono/mini ). My mkbundle --local-targets show this:

$ mkbundle --local-targets
Available targets locally:
	default	- Current System Mono
	mono-4.8.0-osx-10.7-x64.zip
	mono-4.8.0-ubuntu-14.04-x64.zip
	mono-4.8.0-ubuntu-16.04-x64.zip
	mono-5.14.0-osx-10.7-x64
	mono-5.14.0-ubuntu-16.04-x64
	mono-5.20.1-osx-10.9-x64
	mono-5.20.1-raspbian-9-arm
	mono-5.20.1-ubuntu-14.04-x64
	mono-5.20.1-ubuntu-16.04-x64
	mono-5.20.1-ubuntu-18.04-x64

This happened after I have done mkbundle --fetch-target ... the relevant items from the output of mkbundle --list-targets. As I wrote earlier part of the fix is in 6.13 onwards (and backported to late 6.12.x), you need to overwrite the fetched target under ~/.mono. Here is how mine looks like - I moved the fetched one aside as "*.stock":

$ ls -l ~/.mono/targets/mono-5.20.1-osx-10.9-x64/bin/
total 10264
-rwxrwxr-x. 1 Hin-Tak Hin-Tak 6003468 Oct  1  2020 mono
-rw-rw-r--. 1 Hin-Tak Hin-Tak 4505156 Apr 12  2019 mono.stock

It seems that the mono folks are not making any new list-targets beyond 6.8, somehow. But I have 6.6/6.8 backported here. Mine you, you need to watch mkbundle -v ... carefully to see that it is not mixing and matching bits from the host mono vs the fetched mono.

Yes, there are a lot of hoops to jump through, but it can be done... the mac os x releases under http://github.com/HinTak/Font-Validator was made that way and mac os x users seem to be okay with it.

cc @roslynn , Just in case this is the same problem you have... It has some similiarities.

nor0x commented

Hi @HinTak, thank you for investigating this issue. The first option i tried was running the modified script and then codesigning the binary with the --force flag. This unfortunately doesn't work and leads to the following output of the codesign command.

MyApp.app/Contents/Resources/ThumbGenerator: replacing existing signature

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate: object: /johnny/dev/MyApp.MacOS/bin/Release/MyApp.app/Contents/Resources/ThumbGenerator malformed object (code signature data at offset 4606688 with a size of 92608, overlaps string table at offset 4320172 with a size of 135273973)

MyApp.app/Contents/Resources/ThumbGenerator: the codesign_allocate helper tool cannot be found or used

i will now continue with your next suggestion

copying and stripping the main mono executable's signature first.

i will start investigating this, but to be honest a helping hand would be really nice in this case since i have not much experience in this field - i will start doing some research to find out how i can finally have successful codesigning.

@nor0x okay the "overlaps string table" matter I kind-of expect, so I think option 2 it is. I 'll update the script to abort with a warning message about trying to strip the old signature first. Since the old signature is between the string table and the mkbundle appended data, option 1 is no-go then.

nor0x commented

thanks for the info @HinTak. Just for clarification by option 2 you meant to remove the signature of monos main executable? Could this be done with the codesign tool and the --remove-signature flag?

Do you have something like a GitHub sponsor? You already helped me to understand the errors and I would really like to support you if you can assist me further in this case

@nor0x Argh, quite likely codesign tool's --remove-signature would do that. If you run mkbundle -v it would tell you where it is reading bin/mono from (it varies depends on whether you are doing --cross etc). Make make a back-up copy, before modifying, so that you can rewind without reinstalling mono.

As a matter of fact, I was going to drop some hints later, https://hintak.github.io has some paypal links at the bottom. Thanks.

nor0x commented

based on your comments and suggestions @HinTak i can report success in codesigning and notarization. For the record - i'm using
codesign --remove-signature /Library/Frameworks/Mono.framework/Versions/Current/bin/mono-sgen64

to remove the existing signature of mono (which is actually a symlink to mono-sgen64) before running the mkbundle command. After mkbundle i run mono-codesign-fix.py and after that i do a codesign --force on the binary. I have just tested this locally and on the hosted build agent and it works fine.

thank you for the assistance i have sent you a virtual-beer 🍻 via PayPal

@nor0x good to know! Actually I have just finshed writing a script for striping the code signature too (https://github.com/HinTak/mono-modification/blob/macosx-10.13/remove-code-signature.py). Can I have the outcome from strip with codesign to compare? Just the modified mono-sgen64 is fine. I can recover the unmodified mono-sgen64 from the beginning portion of your app, assume you have not upgraded mono meanwhile! It would be nice to know and confirm what codesign --remove-signature does.

And thanks for the virtual beer!

@nor0x No need to send the codesign --remove-signature mono-sgen64. I have committed them here, and if you could confirm the md5sum's of them, that would be nice:

c9846d7d797117c21bc4b5ffda4052d9  mono-6.12.0.140/mono-sgen64.no-signature
65aef3983c88a9231c556d8542cff237  mono-6.12.0.140/mono-sgen64.stock

On Linux, the command to calculate md5sum is just md5sum. I have an impression that on Mac OS X and Solaris and other BSD variant, it might be md5 instead. (and the output is laid out somewhat differently from above too). If you could confirm the md5sum's, I'd close this.

nor0x commented

i have a different value for mono-sgen64.no-signature

MD5 (/Library/Frameworks/Mono.framework/Versions/6.12.0/bin/mono-sgen64.no-signature) = 2d1568c239b17f0e1d55d820b03e5e16
MD5 (/Library/Frameworks/Mono.framework/Versions/6.12.0/bin/mono-sgen64) = 65aef3983c88a9231c556d8542cff237

@nor0x Argh, in that case I'd like to have that file and see what codesign --remove-signature does! If you can attach it here please?

nor0x commented

not much output from the codesign command

> sudo /usr/bin/codesign -v --remove-signature /Library/Frameworks/Mono.framework/Versions/Current/bin/mono-sgen64
/Library/Frameworks/Mono.framework/Versions/Current/bin/mono-sgen64: signed  []

here is the file:
mono-sgen64.zip

@nor0x Thanks for the file. The outcome from codesign --remove-signature differs from my remove-code-signature.py by 3 bytes, the reserved VM size of the binary. It seems to be a safety measure to reserve a bit more memory by about 100k to cater for compressed and self-extracting binaries (which mono's main loader is not). As this is a field later modified by mono-codesign-fix.py, the difference is unimportant. What I mean is that, "codesign --remove-signature + mkbundle + mono-codesign-fix.py" gives byte-wise identical result as "remove-code-signature.py + mkbundle + mono-codesign-fix.py". Having a script (instead of using codesign) to remove the signature is good, at least in a bigger development environment. This is because the administrative person who has the key to eventually sign the release, and need to have the signing tool installed, may not be the development person who is buillding the binary.

I added a comment in the script to mention this difference as unimportant, and I am happy that this issue is resolved.

nor0x commented

i'm back at this @HinTak - during runtime when i want to run the ThumbGenerator executable it crashes with the following info:

CODE SIGNING: 17413[ThumbGenerator] vm_map_enter: curprot cannot be write+execute. failing

i have tried it with both codesign --remove-signature and remove-code-signature.py

@nor0x quick Google search gives me this: xamarin/xamarin-macios#4288 (comment) . In a nutshell, there is something about the -o runtime codesign option, and something about creating a custom entitlement file?

@nor0x I re-read that thread properly, it appears that if you have -o runtime in the codesign option, you need to specify extra entitlement for mono to work. Did you have -o runtime, and can you live without it? Or allowing extra entitlement if you want the hardened runtime option?

nor0x commented

indeed i'm running codesign with -o runtime i need it for correct notarization

Hi, @schriftgestalt , did you encounter any problems during notorization of FontVal? I see you have "disable library validation" in there. Nothing else about jit?

@schriftgestalt I see just one line in https://github.com/HinTak/FontVal-MacGUI/blob/master/FontValidator/FontValidator/FontValidator.entitlements , and the "codesign command.txt" in that directory includes "-o runtime".

@nor0x My collaborator did the signing. Let's see what he says.

nor0x commented

got it, it seems that com.apple.security.cs.disable-library-validationdid the trick for me

@nor0x Good we get to the end of this. Could really do with another round of virtual beer to celebrate :-).

Since we have to remove the original signature before re-signing, I wonder if the mono people gave their signed mono main loader binary any extra entitlement. For the record, the command to display current entitlement of signed app seems to be codesign -d --entitlements ..., but it is easier than that - the entitlement seems to be just appended as plain text as part of the signature, so strings ... does it too.

The stock mono binary as distributed by the mono people was signed with 4 entra entitlements:

mono-6.12.0.140/mono-sgen64.stock is shipped with these (from "strings ..."):
     com.apple.security.cs.allow-jit
     com.apple.security.cs.allow-unsigned-executable-memory
     com.apple.security.cs.allow-dyld-environment-variables
     com.apple.security.cs.disable-library-validation

So it is little surprise that mkbundled binary (which consists of appending stuff to the main mono loader binary) needs one of these. More sophisticated usage of mkbundle / mono may needs the other 3, and/or something extra specific to mkbundle.

Added some of these notes as comments to the scripts.

I don’t think the other entitlements are needed.

@schriftgestalt thanks for your insights. In the case of FontVal, since we are extracting and loading a shared library (freetype), plus other .net bits, it makes sense to have "disable-library-validation". "allow-dyld-environment-variables" looks like would have allowed libfreetype on disk, as in the earlier version of FontVal, to work. The other two I am not sure - the "allow-jit" could be useful for some other usage (building for android?) of mono. The 4 is likely the maximum for all possible usage of mono; so yes, for our purpose, only one is needed. I am not holding my breath on Apple not tightening security further though :( .

nor0x commented

Hello again @HinTak and @schriftgestalt - unfortunately i'm back with more info regarding this issue. I'm codesigning with hardened runtime and entitlements as discussed above. However on running the application it crashes with the following output. Notarization works fine now but it just won't launch and ouputs this to the console

Process:               ThumbGenerator [71830]
Path:                  /Users/USER/Documents/*/MyApp.app/Contents/Resources/ThumbGenerator
Identifier:            ThumbGenerator
Version:               ???
Code Type:             X86-64 (Native)
Parent Process:        MyApp [71723]
Responsible:           MyApp [71723]
User ID:               501

Date/Time:             2021-07-03 22:59:56.594 +0200
OS Version:            macOS 11.4 (20F71)
Report Version:        12
Bridge OS Version:     5.4 (18P4663)
Anonymous UUID:        4AD0721A-F4A0-CC61-0183-32CEEEFD1A0F

Sleep/Wake UUID:       18DA2AA2-50F9-41A4-86C7-17A83FF78510

Time Awake Since Boot: 250000 seconds
Time Since Wake:       5600 seconds

System Integrity Protection: enabled

Crashed Thread:        Unknown

Exception Type:        EXC_CRASH (Code Signature Invalid)
Exception Codes:       0x0000000000000000, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Reason:    Namespace CODESIGNING, Code 0x1

kernel messages:

VM Regions Near 0 (cr2):
--> 
    mapped file                 10ba18000-10bdf7000    [ 3964K] r-x/rwx SM=COW  Object_id=6e461e7f

Backtrace not available

Unknown thread crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000000  rbx: 0x0000000000000000  rcx: 0x0000000000000000  rdx: 0x0000000000000000
  rdi: 0x0000000000000000  rsi: 0x0000000000000000  rbp: 0x0000000000000000  rsp: 0x00007ffee41e7870
   r8: 0x0000000000000000   r9: 0x0000000000000000  r10: 0x0000000000000000  r11: 0x0000000000000000
  r12: 0x0000000000000000  r13: 0x0000000000000000  r14: 0x0000000000000000  r15: 0x0000000000000000
  rip: 0x0000000119775000  rfl: 0x0000000000000200  cr2: 0x0000000000000000
  
Logical CPU:     0
Error Code:      0x00000000
Trap Number:     0

Unknown thread instruction stream not available.

Unknown thread last branch register state not available.


Binary images description not available


External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 63
    thread_create: 0
    thread_set_state: 0

VM Region Summary:
Writable regions: Total=8508K written=0K(0%) resident=0K(0%) swapped_out=0K(0%) unallocated=8508K(100%)
 
                                VIRTUAL   REGION 
REGION TYPE                        SIZE    COUNT (non-coalesced) 
===========                     =======  ======= 
STACK GUARD                       56.0M        1 
Stack                             8192K        1 
VM_ALLOCATE                          8K        2 
VM_ALLOCATE (reserved)             332K        3         reserved VM address space (unallocated)
mapped file                      135.6M        7 
===========                     =======  ======= 
TOTAL                            200.0M       14 
TOTAL, minus reserved VM space   199.6M       14 


can you read something out of this?

EXC_CRASH (Code Signature Invalid) - why would it be invalid after you sign it?

@nor0x actually if you search for that particular string on Google it gives you some suggestions, mainly in two areas: you are supposed to set up some provisioning profile ; the OS can tell where an Mac App came from (via extended attributes stored on disk) - so if you sign with a mac store distribution id, you are supposed to download it and install it from mac store, even if you have a local copy of the app...