Skip to content

Commit

Permalink
wip(libs): attempt to fix code signing issue on Intel-based macs
Browse files Browse the repository at this point in the history
This is a horrible hack attempt to fix a application signing
verification bug with the x86_64 builds. It seems that most of the Intel
based libraries from Nix uses `LC_VERSION_MIN_MACOSX`, most specify both
`version` and `sdk` values. However some don't specify a `sdk` value,
and when checked with `codeside -vv -d <path/to/file>`, it complains
with a warning:

    Library validation warning=OS X SDK version before 10.9 does not support Library Validation

I suspect this is why the Intel builds fail signing verification. This
is an attempt to fix that. It uses `vtool` to force set the newer
`LC_BUILD_VERSION` load command's `minos` and `sdk` values to that of
the old load command's `version` value. But only if the old load command
is present and missing an `sdk` value.
  • Loading branch information
jimeh committed Nov 4, 2024
1 parent 91e3324 commit 680935a
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 1 deletion.
90 changes: 90 additions & 0 deletions build-emacs-for-macos
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,7 @@ class LibEmbedder < AbstractEmbedder
debug "Copying '#{source}' to: '#{relative_path(target)}' ('#{dylib_id}')"
FileUtils.mkdir_p(File.dirname(target))
cmd('cp', '-pRL', source, target)
fix_macho_sdk_version(target)

next if dylib_id.nil? || dylib_id == ''

Expand Down Expand Up @@ -1400,6 +1401,95 @@ class LibEmbedder < AbstractEmbedder
end
end

# This is a horrible hack attempt to fix a application signing verification
# bug with the x86_64 builds. It seems that most of the Intel based libraries
# from Nix uses `LC_VERSION_MIN_MACOSX`, most specify both `version` and `sdk`
# values. However some don't specify a `sdk` value, and when checked with
# `codeside -vv -d <path/to/file>`, it complains with a warning:
#
# Library validation warning=OS X SDK version before 10.9 does not support Library Validation
#
# I suspect this is why the Intel builds fail signing verification. This is an
# attempt to fix that. It uses `vtool` to force set the newer
# `LC_BUILD_VERSION` load command's `minos` and `sdk` values to that of the
# old load command's `version` value. But only if the old load command is
# present and missing an `sdk` value.
def fix_macho_sdk_version(target_file)
mf = nil

begin
mf = MachO.open(target_file)
rescue MachO::NotAMachOError => e
debug '-- Skipping Mach-O SDK version check/fix, not a Mach-O file'
return
end

blank_legacy_sdk = false
legacy_version = nil
legacy_version_string = nil
lc_build_version = false

mf.load_commands.each do |lc|
if lc.is_a?(MachO::LoadCommands::VersionMinCommand) &&
lc.sdk.zero? && !lc.version.zero?
blank_legacy_sdk = true
legacy_version = lc.version
legacy_version_string = lc.version_string
end

if lc.is_a?(MachO::LoadCommands::BuildVersionCommand)
lc_build_version = true
end
end

return unless blank_legacy_sdk && !lc_build_version && legacy_version

debug '-- Adding LC_BUILD_VERSION to Mach-O header'
run_cmd(
vtool_path, '-set-build-version',
'macos', legacy_version_string, legacy_version_string,
'-replace', '-output', "#{target_file}.patched", target_file
)

while_writable(target_file) do
FileUtils.remove_file(target_file)
FileUtils.mv("#{target_file}.patched", target_file)
end

begin
success = MachO.open(target_file).load_commands.any? do |lc|
lc.is_a?(MachO::LoadCommands::BuildVersionCommand) &&
lc.minos == legacy_version && lc.sdk == legacy_version
end

error "Failed to set LC_BUILD_VERSION in #{target_file}" unless success
rescue StandardError => e
debug '-- Failed to verify LC_BUILD_VERSION in Mach-O header'
raise e
end
end

# Try and locate vtool.
def vtool_path
return @vtool_path if @vtool_path

# Default approach
path = `xcrun -f vtool`.strip
return @vtool_path = path unless path.empty?

# Unset DEVELOPER_DIR and try again.
path = `env DEVELOPER_DIR='' xcrun -f vtool`.strip
return @vtool_path = path unless path.empty?

# Try with full path to xcrun. This should escape out of the nix environment
# and pull in vtool from macOS itself.
path = `env DEVELOPER_DIR='' /usr/bin/xcrun -f vtool`.strip
return @vtool_path = path unless path.empty?

error 'Could not locate vtool, please ensure Xcode Command Line Tools ' \
'are installed'
end

def while_writable(file)
mode = File.stat(file).mode
File.chmod(0o775, file)
Expand Down
5 changes: 4 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
apple-sdk_11
autoconf
clang
coreutils
curl
apple-sdk
darwin.DarwinTools # sw_vers
dbus
expat
findutils
Expand Down Expand Up @@ -57,6 +58,8 @@
];

shellHook = ''
export MACOSX_DEPLOYMENT_TARGET="11.0"
export DEVELOPER_DIR="${pkgs.apple-sdk_11}"
export EMACS_BUILD_USE_NIX="true"
export NIX_GCC_LIB_VERSION="${pkgs.gcc.cc.lib.version}"
export NIX_GCC_LIB_ROOT="${pkgs.gcc.cc.lib.outPath}"
Expand Down

0 comments on commit 680935a

Please sign in to comment.