indygreg / apple-platform-rs

Rust crates supporting Apple platform development
595 stars 49 forks source link

When attempting to sign an app bundle with debug symbols shipped in it, rcodesign fails to properly detect app bundle. #128

Closed ProjectSynchro closed 10 months ago

ProjectSynchro commented 10 months ago

Hey there,

I'm trying to integrate rcodesign into our workflow to release universal binaries for macOS while cross-compiling.

Currently if you attempt to sign an app bundle with debug symbols included (.dSYM subdirectory in Contents/MacOS/) rcodesign tries and fails to sign the debug symbols as if they are a binary.

Here's an example when I try signing a bundle with those symbols:

[synchro@MacroSynchro dist.x86]$ rcodesign sign Naev.app/
signing Naev.app/ in place
signing bundle at Naev.app/
signing 1 nested bundles in the following order:
Contents/MacOS/naev.dSYM
entering nested bundle Contents/MacOS/naev.dSYM
signing bundle at Naev.app/Contents/MacOS/naev.dSYM into Naev.app/Contents/MacOS/naev.dSYM
signing Mach-O file Contents/Resources/DWARF/naev
section #1 size 1768190 out of bounds
Error: __LINKEDIT isn't final Mach-O segment

I can workaround this by removing the subdirectory and transplanting it back into the bundle after signing, but it would be nice to avoid having to do that.

I have found barely any documentation about this .dSYM subdirectory but when creating a debug build and creating an app bundle from it the meson build system spits out one of these .dSYM directories next to the application binary.

Does it make sense to ignore this directory when signing an app bundle? Thanks for making this awesome tool!

indygreg commented 10 months ago

Thanks for the bug report.

This looks like yet another subtle bug with the handling of [nested] bundles, which have historically been a source of bugs in this project.

In this case, the .dSYM directory has a <rules2> entry:

<key>rules2</key>
            <dict>
              <key>.*\.dSYM($|/)</key>
              <dict>
                <key>weight</key>
                <real>11</real>
              </dict>
              <key>^(.*/)?\.DS_Store$</key>
              <dict>
                <key>omit</key>
                <true/>
                <key>weight</key>
                <real>2000</real>
              </dict>
              <key>^[^/]+$</key>
              <dict>
                <key>nested</key>
                <true/>
                <key>weight</key>
                <real>10</real>
              </dict>

I think this rule should prevent that .dSYM directory from getting traversed as a nested bundle. But I need to experiment with Apple's implementation to confirm.

There may also be an issue here where we attempt to sign the debug symbol files as Mach-O. But that bug may go away if we don't treat the .dSYM directory as a bundle.

Thanks again for the report. I'll try to look into this in the next few days. But no promises.

ProjectSynchro commented 10 months ago

No worries, glad you seem to know more about this than I do. 😄

I'd think avoiding traversing the directory would be a valid solution as macOS doesn't seem to care if that directory exists at all, granted I might also be missing something.

I haven't tried to sign with the native macOS codesign tool as we don't use macOS at all during our build process, so I'm not sure what it's behavior is either.

Cheers.

indygreg commented 10 months ago

I created a bundle layout like the following:

test-debug.app/Contents/Info.plist
test-debug.app/Contents/MacOS/test-debug
test-debug.app/Contents/MacOS/test-debug.app.dSYM/Contents/Info.plist
test-debug.app/Contents/MacOS/test-debug.app.dSYM/Contents/Resources/DWARF/test-debug
test-debug.app/Contents/MacOS/test-debug.app.dSYM/Contents/Resources/Relocations/aarch64/test-debug.yml
test-debug.app/Contents/PkgInfo

Signing it with Apple's tooling yielded a single signed bundle with the test-debug.app/Contents/_CodeSignature/CodeResources file having the following:

        <key>files</key>
        <dict/>
        <key>files2</key>
        <dict>
                <key>MacOS/test-debug.app.dSYM/Contents/Info.plist</key>
                <dict>
                        <key>hash2</key>
                        <data>
                        +3v3QRQzy921ytrAeBsl0nGjkBbfP8eMxcpZySarflQ=
                        </data>
                </dict>
                <key>MacOS/test-debug.app.dSYM/Contents/Resources/DWARF/test-debug</key>
                <dict>
                        <key>hash2</key>
                        <data>
                        wM1tIG4YSFOr/yT+zpLAjBTHiUu1dBTJNoKka1eBmE0=
                        </data>
                </dict>
                <key>MacOS/test-debug.app.dSYM/Contents/Resources/Relocations/aarch64/test-debug.yml</key>
                <dict>
                        <key>hash2</key>
                        <data>
                        iVpaMrqj+Canu5LRAFQxZtbxOngH2+IFXQ+uE6P9Z1Y=
                        </data>
                </dict>
        </dict>

It looks like Apple's tooling descends into the .dSYM/ directory just like it is regular file content. This is what I'd expect from the <rules2> entry for <key>.*\.dSYM($|/)</key>.

indygreg commented 10 months ago

I think I just fixed this. If you still experience an issue with the latest commit on the main branch, please reopen. Also please post your bundle file layout (e.g. find . -type f | sort) to help debug the issue.