I recently updated one of my projects Library Inspector for OS X 10.8. After a month of waiting, it was finally rejected (!#@$%!@) due to problems with the code signing entitlements. The Apple Reviewer was very vague about the problem which caused additional frustrations (%!@#$%) but after searching I found a very helpful application RB App Checker Lite which can check the certificates, entitlements and other details of your application likely to cause problems.
I actally emailed Rainer Brockerhoff since I figured he'd have a lot of experience (and I gave him a free copy of Library Inspector to sweeten the deal). He told me that for NSTask
based task invocation I'd need to encode the entitlements directly into the binaries, which I wasn't doing.
To make things even more complex, the binaries I am including in the application bundle are actually copied from Xcode (nm
, otool
, c++filt
, etc) and class-dump (a fantastic tool by the way!). So, I am ripping out the existing Apple signatures and adding my own. This is because you can't submit other people's code signed binaries to the Mac App Store.
Anyway, here is what I ended up with:
Application Entitlements
This is the main entitlements file for Library Inspector.
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>
Auxiliary Executable Entitlements
This is the entitlements used for the auxiliary binaries.
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
Of particular importance is the com.apple.security.inherit
property. When Library Inspector, itself running in a sandbox due to com.apple.security.app-sandbox
invokes tasks using NSTask
, it will itself run in a sandbox and inherit the permissions of Library Inspector so it can read any relevant input files (normally provided as arguments).
Code Signing Script
This Ruby script is used as a build phase within Library Inspector and signs the auxiliary executables if a signature was specified. For your own application you'd need to update the list of tools and the identifier base.
Dir.chdir ENV['BUILT_PRODUCTS_DIR']
# These tools are copied directly to the built products directory in a previous copy files build phase:
tools = ['class-dump', 'otool', 'nm', 'c++filt']
cert = ENV['CODE_SIGN_IDENTITY']
# The base identifier for the tools:
identifier_base = 'nz.co.oriontransfer.Library-Inspector.tools'
# The path to the auxiliary executable entitlements file:
entitlements = File.join(ENV['PROJECT_DIR'], 'Auxiliary Executable.entitlements')
tools.each do |tool|
full_path = File.join(ENV['EXECUTABLE_FOLDER_PATH'], tool)
# The full (new) identifier for the executable:
identifier = identifier_base + '.' + tool
# Use the codesign tool to embed a new signature and entitlements:
system('codesign', '--entitlements', entitlements, '-i', identifier, '--force', '-s', cert, full_path)
end
Now I just have to submit the application and wait for a month for Apple to review it... Fingers crossed that everything is fine this time through the system.
Addendum, March 2013: Quicklook Plugins
I found that there are some issues when the above approach is used with Quicklook Plugins. I found that my external processes were crashing with the following type of error:
Process: nm [45806]
Path: /Applications/Developer/Library Inspector.app/Contents/Library/QuickLook/Library Inspector Quick Look.qlgenerator/Contents/MacOS/nm
Identifier: nm
Version: ???
Code Type: X86-64 (Native)
Parent Process: sh [45805]
User ID: 502
Date/Time: 2013-03-09 19:10:04.506 +1300
OS Version: Mac OS X 10.8.2 (12C60)
Report Version: 10
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Application Specific Information:
XPC domain creation failed: Process is not in an inherited sandbox.
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libxpc.dylib 0x00007fff8678424a _xpc_runtime_init_once + 1077
1 libdispatch.dylib 0x00007fff8cb2f0b6 _dispatch_client_callout + 8
2 libdispatch.dylib 0x00007fff8cb2f041 dispatch_once_f + 50
3 libxpc.dylib 0x00007fff8677b919 _xpc_runtime_set_domain + 190
4 libxpc.dylib 0x00007fff8677ae90 _libxpc_initializer + 430
5 libSystem.B.dylib 0x00007fff8c78bb2d libSystem_initializer + 172
6 dyld 0x00007fff61f38378 ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 236
7 dyld 0x00007fff61f38762 ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 46
8 dyld 0x00007fff61f3506e ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 380
9 dyld 0x00007fff61f34fc4 ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 210
10 dyld 0x00007fff61f34eba ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 54
11 dyld 0x00007fff61f26fc0 dyld::initializeMainExecutable() + 207
12 dyld 0x00007fff61f2ab04 dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 3060
13 dyld 0x00007fff61f26397 dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 761
14 dyld 0x00007fff61f2605e _dyld_start + 54
<...snip...>
I narrowed it down to the entitlements. It turns out that the Quicklook Plugin Host doesn't seem to run in a typical sandbox (as far as I can tell), and thus trying to use the inherit entitlement doesn't work. Simply removing the entitlements file arguments ('--entitlements', entitlements
) from the above code signing script fixes the issue. This works because the executable no longer tries to inherit sandbox permissions from the parent, but I'm not exactly sure why this is an issue. It seems like this is only affects Mac OS X 10.8.2+ but I haven't had a lot of experience with this problem yet.