From ce2d8adf38ef21e01bbe03e306605abd98075a10 Mon Sep 17 00:00:00 2001 From: danielnachun Date: Fri, 11 Mar 2022 13:38:01 -0800 Subject: [PATCH 1/5] keg_relocate.rb: rebase --- Library/Homebrew/keg_relocate.rb | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index 197b01a942..e97b255967 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -165,6 +165,45 @@ class Keg changed_files end + def relocate_build_prefix(keg, old_prefix, new_prefix) + each_unique_file_matching(old_prefix) do |file| + # Skip files which are not binary, as they do not need null padding. + next unless keg.binary_file?(file) + + # Skip sharballs, which appear to break if patched. + next if file.text_executable? + + # Split binary by null characters into array and substitute new prefix for old prefix. + # Null padding is added if the new string is too short. + file.ensure_writable do + binary = File.binread file + odebug "Replacing build prefix in: #{file}" + binary_strings = binary.split(/#{NULL_BYTE}/o, -1) + match_indices = binary_strings.each_index.select { |i| binary_strings[i].include?(old_prefix) } + + # Only perform substitution on strings which match prefix regex. + match_indices.each do |i| + s = binary_strings[i] + binary_strings[i] = s.gsub(old_prefix, new_prefix) + .ljust(s.size, NULL_BYTE) + end + + # Rejoin strings by null bytes. + patched_binary = binary_strings.join(NULL_BYTE) + if patched_binary.size != binary.size + raise <<~EOS + Patching failed! Original and patched binary sizes do not match. + Original size: #{binary.size} + Patched size: #{patched_binary.size} + EOS + end + + file.atomic_write patched_binary + end + codesign_patched_binary(file) + end + end + def detect_cxx_stdlibs(_options = {}) [] end From bff8c9aca8e79710540a479e724002fee82c378a Mon Sep 17 00:00:00 2001 From: danielnachun Date: Tue, 7 Dec 2021 10:59:08 -0800 Subject: [PATCH 2/5] formula_installer.rb: call relocate_build_prefix --- Library/Homebrew/formula_installer.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 288fc09eff..6e5848c372 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1228,6 +1228,14 @@ class FormulaInstaller keg = Keg.new(formula.prefix) skip_linkage = formula.bottle_specification.skip_relocation? keg.replace_placeholders_with_locations tab.changed_files, skip_linkage: skip_linkage + + cellar = formula.bottle_specification.tag_to_cellar(Utils::Bottles.tag) + return if [:any, :any_skip_relocation].include?(cellar) + + prefix = Pathname(cellar).parent.to_s + return if cellar == HOMEBREW_CELLAR.to_s && prefix == HOMEBREW_PREFIX.to_s + + keg.relocate_build_prefix(keg, prefix, HOMEBREW_PREFIX) end sig { params(output: T.nilable(String)).void } From 70bc181029164a037e5ec327b3a4e168126866b3 Mon Sep 17 00:00:00 2001 From: danielnachun Date: Mon, 6 Dec 2021 02:10:55 -0800 Subject: [PATCH 3/5] software_spec.rb: change compatible_location --- Library/Homebrew/software_spec.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index f6eb79b225..e3e549fa23 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -473,6 +473,8 @@ class Bottle end class BottleSpecification + RELOCATABLE_CELLARS = [:any, :any_skip_relocation].freeze + extend T::Sig attr_rw :rebuild @@ -518,12 +520,15 @@ class BottleSpecification def compatible_locations?(tag: Utils::Bottles.tag) cellar = tag_to_cellar(tag) - return true if [:any, :any_skip_relocation].include?(cellar) + return true if RELOCATABLE_CELLARS.include?(cellar) prefix = Pathname(cellar).parent.to_s - compatible_cellar = cellar == HOMEBREW_CELLAR.to_s - compatible_prefix = prefix == HOMEBREW_PREFIX.to_s + cellar_relocatable = cellar.size >= HOMEBREW_CELLAR.to_s.size && ENV["HOMEBREW_RELOCATE_BUILD_PREFIX"] + prefix_relocatable = prefix.size >= HOMEBREW_PREFIX.to_s.size && ENV["HOMEBREW_RELOCATE_BUILD_PREFIX"] + + compatible_cellar = cellar == HOMEBREW_CELLAR.to_s || cellar_relocatable + compatible_prefix = prefix == HOMEBREW_PREFIX.to_s || prefix_relocatable compatible_cellar && compatible_prefix end From 843a189d40996822125550effa39da06c2a550b5 Mon Sep 17 00:00:00 2001 From: danielnachun Date: Mon, 28 Feb 2022 15:40:39 -0800 Subject: [PATCH 4/5] test/keg_relocate/binary_relocation_spec.rb: add new unit test --- .../keg_relocate/binary_relocation_spec.rb | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Library/Homebrew/test/keg_relocate/binary_relocation_spec.rb diff --git a/Library/Homebrew/test/keg_relocate/binary_relocation_spec.rb b/Library/Homebrew/test/keg_relocate/binary_relocation_spec.rb new file mode 100644 index 0000000000..29bf25703a --- /dev/null +++ b/Library/Homebrew/test/keg_relocate/binary_relocation_spec.rb @@ -0,0 +1,44 @@ +# typed: false +# frozen_string_literal: true + +require "keg_relocate" + +describe Keg do + subject(:keg) { described_class.new(HOMEBREW_CELLAR/"foo/1.0.0") } + + let(:dir) { HOMEBREW_CELLAR/"foo/1.0.0" } + let(:newdir) { HOMEBREW_CELLAR/"foo" } + let(:binary_file) { dir/"file.bin" } + + before do + dir.mkpath + end + + def setup_binary_file + binary_file.atomic_write <<~EOS + \x00#{dir}\x00 + EOS + end + + describe "#relocate_build_prefix" do + specify "replace prefix in binary files" do + setup_binary_file + + keg.relocate_build_prefix(keg, dir, newdir) + + old_prefix_matches = Set.new + keg.each_unique_file_matching(dir) do |file| + old_prefix_matches << file + end + + expect(old_prefix_matches.size).to eq 0 + + new_prefix_matches = Set.new + keg.each_unique_file_matching(newdir) do |file| + new_prefix_matches << file + end + + expect(new_prefix_matches.size).to eq 1 + end + end +end From 35f426e3e23efe1385bc30cda9923367dbd77ac6 Mon Sep 17 00:00:00 2001 From: danielnachun Date: Sat, 12 Mar 2022 17:45:25 -0800 Subject: [PATCH 5/5] keg.rb: add generic codesign_patched_binary method --- Library/Homebrew/keg.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index 6287d60708..18e5d1ac23 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -529,6 +529,8 @@ class Keg elf_files end + def codesign_patched_binary(_binary_file); end + private def resolve_any_conflicts(dst, dry_run: false, verbose: false, overwrite: false)