elf: expand $ORIGIN in RUNPATH/RPATH entries
This commit is contained in:
parent
4bc1cc57f3
commit
6ee34832d1
@ -153,6 +153,7 @@ module ELFShim
|
|||||||
|
|
||||||
# Search for dependencies in the runpath/rpath first
|
# Search for dependencies in the runpath/rpath first
|
||||||
local_paths&.each do |local_path|
|
local_paths&.each do |local_path|
|
||||||
|
local_path = OS::Linux::Elf.expand_elf_dst(local_path, "ORIGIN", path.parent)
|
||||||
candidate = Pathname(local_path)/basename
|
candidate = Pathname(local_path)/basename
|
||||||
return candidate if candidate.exist? && candidate.elf?
|
return candidate if candidate.exist? && candidate.elf?
|
||||||
end
|
end
|
||||||
@ -225,3 +226,37 @@ module ELFShim
|
|||||||
metadata.dylibs
|
metadata.dylibs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module OS
|
||||||
|
module Linux
|
||||||
|
# Helper functions for working with ELF objects.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
module Elf
|
||||||
|
sig { params(str: String, ref: String, repl: T.any(String, Pathname)).returns(String) }
|
||||||
|
def self.expand_elf_dst(str, ref, repl)
|
||||||
|
# ELF gABI rules for DSTs:
|
||||||
|
# - Longest possible sequence using the rules (greedy).
|
||||||
|
# - Must start with a $ (enforced by caller).
|
||||||
|
# - Must follow $ with one underscore or ASCII [A-Za-z] (caller
|
||||||
|
# follows these rules for REF) or '{' (start curly quoted name).
|
||||||
|
# - Must follow first two characters with zero or more [A-Za-z0-9_]
|
||||||
|
# (enforced by caller) or '}' (end curly quoted name).
|
||||||
|
# (from https://github.com/bminor/glibc/blob/41903cb6f460d62ba6dd2f4883116e2a624ee6f8/elf/dl-load.c#L182-L228)
|
||||||
|
|
||||||
|
# In addition to capturing a token, also attempt to capture opening/closing braces and check that they are not
|
||||||
|
# mismatched before expanding.
|
||||||
|
str.gsub(/\$({?)([a-zA-Z_][a-zA-Z0-9_]*)(}?)/) do |orig_str|
|
||||||
|
has_opening_brace = ::Regexp.last_match(1).present?
|
||||||
|
matched_text = ::Regexp.last_match(2)
|
||||||
|
has_closing_brace = ::Regexp.last_match(3).present?
|
||||||
|
if (matched_text == ref) && (has_opening_brace == has_closing_brace)
|
||||||
|
repl
|
||||||
|
else
|
||||||
|
orig_str
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
87
Library/Homebrew/test/os/linux/elf_spec.rb
Normal file
87
Library/Homebrew/test/os/linux/elf_spec.rb
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe OS::Linux::Elf do
|
||||||
|
describe "::expand_elf_dst" do
|
||||||
|
it "expands tokens that are not wrapped in curly braces" do
|
||||||
|
str = "$ORIGIN/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "/opt/homebrew/bin/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "expands tokens that are wrapped in curly braces" do
|
||||||
|
str = "${ORIGIN}/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "/opt/homebrew/bin/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "${ORIGIN}new/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "/opt/homebrew/binnew/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "expands multiple occurrences of token" do
|
||||||
|
str = "${ORIGIN}/../..$ORIGIN/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "/opt/homebrew/bin/../../opt/homebrew/bin/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "rejects and passes through tokens containing additional characters" do
|
||||||
|
str = "$ORIGINAL/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "$ORIGINAL/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "$ORIGIN_/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "$ORIGIN_/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "$ORIGIN_STORY/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "$ORIGIN_STORY/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "${ORIGINAL}/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "${ORIGINAL}/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "${ORIGIN_}/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "${ORIGIN_}/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "${ORIGIN_STORY}/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "${ORIGIN_STORY}/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "rejects and passes through tokens with mismatched curly braces" do
|
||||||
|
str = "${ORIGIN/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "${ORIGIN/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
|
||||||
|
str = "$ORIGIN}/../lib"
|
||||||
|
ref = "ORIGIN"
|
||||||
|
repl = "/opt/homebrew/bin"
|
||||||
|
expected = "$ORIGIN}/../lib"
|
||||||
|
expect(described_class.expand_elf_dst(str, ref, repl)).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user