Skip to content

Commit c55a574

Browse files
committed
Apply an ad-hoc signature after modifying IDs
If we make any changes to a signed binary, we invalidate the signature. Without resigning, the resulting binary is unusable. To my knowledge, there's no disadvantage to signing an unsigned binary using an ad-hoc signature, so we can just do this unconditionally to ensure we don't end up creating bad binaries. The ad-hoc signature should always be available and always work, so this should be safe to do in all circumstances.
1 parent 873499e commit c55a574

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

lib/macho.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require "English"
34
require_relative "macho/structure"
45
require_relative "macho/view"
56
require_relative "macho/headers"
@@ -39,4 +40,22 @@ def self.open(filename)
3940

4041
file
4142
end
43+
44+
# Signs the dylib using an ad-hoc identity.
45+
# Necessary after making any changes to a dylib, since otherwise
46+
# changing a signed file invalidates its signature.
47+
# @param filename [String] the file being opened
48+
# @return [void]
49+
# @raise [ModificationError] if the operation fails
50+
def self.codesign(filename)
51+
# codesign binary is not available on Linux
52+
return unless RUBY_PLATFORM =~ /darwin/
53+
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
54+
55+
system("codesign", "--sign", "-", "--force",
56+
"--preserve-metadata=entitlements,requirements,flags,runtime",
57+
filename)
58+
59+
raise ModificationError, "#{filename}: signing failed!" unless $CHILD_STATUS.success?
60+
end
4261
end

lib/macho/tools.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def self.change_dylib_id(filename, new_id, options = {})
2525

2626
file.change_dylib_id(new_id, options)
2727
file.write!
28+
29+
MachO.codesign(filename)
2830
end
2931

3032
# Changes a shared library install name in a Mach-O or Fat binary,
@@ -41,6 +43,8 @@ def self.change_install_name(filename, old_name, new_name, options = {})
4143

4244
file.change_install_name(old_name, new_name, options)
4345
file.write!
46+
47+
MachO.codesign(filename)
4448
end
4549

4650
# Changes a runtime path in a Mach-O or Fat binary, overwriting the source
@@ -57,6 +61,8 @@ def self.change_rpath(filename, old_path, new_path, options = {})
5761

5862
file.change_rpath(old_path, new_path, options)
5963
file.write!
64+
65+
MachO.codesign(filename)
6066
end
6167

6268
# Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
@@ -71,6 +77,8 @@ def self.add_rpath(filename, new_path, options = {})
7177

7278
file.add_rpath(new_path, options)
7379
file.write!
80+
81+
MachO.codesign(filename)
7482
end
7583

7684
# Delete a runtime path from a Mach-O or Fat binary, overwriting the source
@@ -86,6 +94,8 @@ def self.delete_rpath(filename, old_path, options = {})
8694

8795
file.delete_rpath(old_path, options)
8896
file.write!
97+
98+
MachO.codesign(filename)
8999
end
90100

91101
# Merge multiple Mach-Os into one universal (Fat) binary.
@@ -106,6 +116,8 @@ def self.merge_machos(filename, *files, fat64: false)
106116

107117
fat_macho = MachO::FatFile.new_from_machos(*machos, :fat64 => fat64)
108118
fat_macho.write(filename)
119+
120+
MachO.codesign(filename)
109121
end
110122
end
111123
end

0 commit comments

Comments
 (0)