patchelf 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/patchelf/alt_saver.rb +1052 -0
- data/lib/patchelf/cli.rb +1 -1
- data/lib/patchelf/exceptions.rb +2 -0
- data/lib/patchelf/helper.rb +19 -5
- data/lib/patchelf/logger.rb +1 -1
- data/lib/patchelf/mm.rb +2 -2
- data/lib/patchelf/patcher.rb +10 -3
- data/lib/patchelf/saver.rb +18 -21
- data/lib/patchelf/version.rb +1 -1
- metadata +21 -13
data/lib/patchelf/cli.rb
CHANGED
data/lib/patchelf/exceptions.rb
CHANGED
@@ -6,8 +6,10 @@ require 'elftools/exceptions'
|
|
6
6
|
module PatchELF
|
7
7
|
# Raised on an error during ELF modification.
|
8
8
|
class PatchError < ELFTools::ELFError; end
|
9
|
+
|
9
10
|
# Raised when Dynamic Tag is missing
|
10
11
|
class MissingTagError < PatchError; end
|
12
|
+
|
11
13
|
# Raised on missing Program Header(segment)
|
12
14
|
class MissingSegmentError < PatchError; end
|
13
15
|
end
|
data/lib/patchelf/helper.rb
CHANGED
@@ -3,9 +3,6 @@
|
|
3
3
|
module PatchELF
|
4
4
|
# Helper methods for internal usage.
|
5
5
|
module Helper
|
6
|
-
# The size of one page.
|
7
|
-
PAGE_SIZE = 0x1000
|
8
|
-
|
9
6
|
module_function
|
10
7
|
|
11
8
|
# Color codes for pretty print.
|
@@ -16,6 +13,23 @@ module PatchELF
|
|
16
13
|
error: "\e[38;5;196m" # heavy red
|
17
14
|
}.freeze
|
18
15
|
|
16
|
+
# The size of one page.
|
17
|
+
def page_size(e_machine = nil)
|
18
|
+
# Different architectures have different minimum section alignments.
|
19
|
+
case e_machine
|
20
|
+
when ELFTools::Constants::EM_SPARC,
|
21
|
+
ELFTools::Constants::EM_MIPS,
|
22
|
+
ELFTools::Constants::EM_PPC,
|
23
|
+
ELFTools::Constants::EM_PPC64,
|
24
|
+
ELFTools::Constants::EM_AARCH64,
|
25
|
+
ELFTools::Constants::EM_TILEGX,
|
26
|
+
ELFTools::Constants::EM_LOONGARCH
|
27
|
+
0x10000
|
28
|
+
else
|
29
|
+
0x1000
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
19
33
|
# For wrapping string with color codes for prettier inspect.
|
20
34
|
# @param [String] str
|
21
35
|
# Content to colorize.
|
@@ -48,7 +62,7 @@ module PatchELF
|
|
48
62
|
# #=> 32
|
49
63
|
# aligndown(0x10, 0x8)
|
50
64
|
# #=> 16
|
51
|
-
def aligndown(val, align =
|
65
|
+
def aligndown(val, align = page_size)
|
52
66
|
val - (val & (align - 1))
|
53
67
|
end
|
54
68
|
|
@@ -63,7 +77,7 @@ module PatchELF
|
|
63
77
|
# #=> 64
|
64
78
|
# alignup(0x10, 0x8)
|
65
79
|
# #=> 16
|
66
|
-
def alignup(val, align =
|
80
|
+
def alignup(val, align = page_size)
|
67
81
|
(val & (align - 1)).zero? ? val : (aligndown(val, align) + align)
|
68
82
|
end
|
69
83
|
end
|
data/lib/patchelf/logger.rb
CHANGED
data/lib/patchelf/mm.rb
CHANGED
@@ -115,7 +115,7 @@ module PatchELF
|
|
115
115
|
# prefer backward than forward
|
116
116
|
return extend_backward(loads[idx - 1]) if writable?(loads[idx - 1])
|
117
117
|
|
118
|
-
#
|
118
|
+
# NOTE: loads[idx].file_head has been changed in shift_attributes
|
119
119
|
extend_forward(loads[idx], @extend_size)
|
120
120
|
end
|
121
121
|
|
@@ -161,7 +161,7 @@ module PatchELF
|
|
161
161
|
|
162
162
|
seg.header.p_offset += extend_size
|
163
163
|
# We have to change align of LOAD segment since ld.so checks it.
|
164
|
-
seg.header.p_align = Helper
|
164
|
+
seg.header.p_align = Helper.page_size if seg.is_a?(ELFTools::Segments::LoadSegment)
|
165
165
|
end
|
166
166
|
|
167
167
|
@elf.header.e_shoff += extend_size if @elf.header.e_shoff >= threshold
|
data/lib/patchelf/patcher.rb
CHANGED
@@ -30,7 +30,7 @@ module PatchELF
|
|
30
30
|
@elf = ELFTools::ELFFile.new(File.open(filename))
|
31
31
|
@set = {}
|
32
32
|
@rpath_sym = :runpath
|
33
|
-
@on_error =
|
33
|
+
@on_error = logging ? on_error : :exception
|
34
34
|
|
35
35
|
on_error_syms = %i[exception log silent]
|
36
36
|
raise ArgumentError, "on_error must be one of #{on_error_syms}" unless on_error_syms.include?(@on_error)
|
@@ -173,13 +173,20 @@ module PatchELF
|
|
173
173
|
# Save the patched ELF as +out_file+.
|
174
174
|
# @param [String?] out_file
|
175
175
|
# If +out_file+ is +nil+, the original input file will be modified.
|
176
|
+
# @param [Boolean] patchelf_compatible
|
177
|
+
# When +patchelf_compatible+ is true, tries to produce same ELF as the one produced by NixOS/patchelf.
|
176
178
|
# @return [void]
|
177
|
-
def save(out_file = nil)
|
179
|
+
def save(out_file = nil, patchelf_compatible: false)
|
178
180
|
# If nothing is modified, return directly.
|
179
181
|
return if out_file.nil? && !dirty?
|
180
182
|
|
181
183
|
out_file ||= @in_file
|
182
|
-
saver =
|
184
|
+
saver = if patchelf_compatible
|
185
|
+
require 'patchelf/alt_saver'
|
186
|
+
PatchELF::AltSaver.new(@in_file, out_file, @set)
|
187
|
+
else
|
188
|
+
PatchELF::Saver.new(@in_file, out_file, @set)
|
189
|
+
end
|
183
190
|
|
184
191
|
saver.save!
|
185
192
|
end
|
data/lib/patchelf/saver.rb
CHANGED
@@ -53,8 +53,8 @@ module PatchELF
|
|
53
53
|
def patch_interpreter
|
54
54
|
return if @set[:interpreter].nil?
|
55
55
|
|
56
|
-
new_interp = @set[:interpreter]
|
57
|
-
old_interp = @elf.segment_by_type(:interp).interp_name
|
56
|
+
new_interp = "#{@set[:interpreter]}\x00"
|
57
|
+
old_interp = "#{@elf.segment_by_type(:interp).interp_name}\x00"
|
58
58
|
return if old_interp == new_interp
|
59
59
|
|
60
60
|
# These headers must be found here but not in the proc.
|
@@ -121,30 +121,27 @@ module PatchELF
|
|
121
121
|
def patch_needed
|
122
122
|
original_needs = dynamic.tags_by_type(:needed)
|
123
123
|
@set[:needed].uniq!
|
124
|
+
|
125
|
+
original = original_needs.map(&:name)
|
126
|
+
replace = @set[:needed]
|
127
|
+
|
124
128
|
# 3 sets:
|
125
129
|
# 1. in original and in needs - remain unchanged
|
126
130
|
# 2. in original but not in needs - remove
|
127
131
|
# 3. not in original and in needs - append
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
n.header.d_tag = IGNORE # temporarily mark
|
132
|
-
end
|
133
|
-
|
134
|
-
extra = @set[:needed] - original_needs.map(&:name)
|
135
|
-
original_needs.each do |n|
|
136
|
-
break if extra.empty?
|
137
|
-
next if n.header.d_tag != IGNORE
|
132
|
+
append = replace - original
|
133
|
+
remove = original - replace
|
138
134
|
|
139
|
-
|
140
|
-
|
135
|
+
ignored_dyns = remove.each_with_object([]) do |name, ignored|
|
136
|
+
dyn = original_needs.find { |n| n.name == name }.header
|
137
|
+
dyn.d_tag = IGNORE
|
138
|
+
ignored << dyn
|
141
139
|
end
|
142
|
-
return if extra.empty?
|
143
140
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
reg_str_table(name) { |idx|
|
141
|
+
append.zip(ignored_dyns) do |name, ignored_dyn|
|
142
|
+
dyn = ignored_dyn || lazy_dyn(:needed)
|
143
|
+
dyn.d_tag = ELFTools::Constants::DT_NEEDED
|
144
|
+
reg_str_table(name) { |idx| dyn.d_val = idx }
|
148
145
|
end
|
149
146
|
end
|
150
147
|
|
@@ -187,7 +184,7 @@ module PatchELF
|
|
187
184
|
need_size = strtab_string.size + @strtab_extend_requests.reduce(0) { |sum, (str, _)| sum + str.size + 1 }
|
188
185
|
dynstr = section_header('.dynstr')
|
189
186
|
@mm.malloc(need_size) do |off, vaddr|
|
190
|
-
new_str = strtab_string
|
187
|
+
new_str = "#{strtab_string}#{@strtab_extend_requests.map(&:first).join("\x00")}\x00"
|
191
188
|
inline_patch(off, new_str)
|
192
189
|
cur = strtab_string.size
|
193
190
|
@strtab_extend_requests.each do |str, block|
|
@@ -209,7 +206,7 @@ module PatchELF
|
|
209
206
|
# @yieldparam [Integer] idx
|
210
207
|
# @yieldreturn [void]
|
211
208
|
def reg_str_table(str, &block)
|
212
|
-
idx = strtab_string.index(str
|
209
|
+
idx = strtab_string.index("#{str}\x00")
|
213
210
|
# Request string is already exist
|
214
211
|
return yield idx if idx
|
215
212
|
|
data/lib/patchelf/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patchelf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- david942j
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elftools
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,28 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3
|
47
|
+
version: '3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3
|
54
|
+
version: '3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '1'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: simplecov
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,6 +73,9 @@ dependencies:
|
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0.17'
|
76
|
+
- - "<"
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0.18'
|
76
79
|
type: :development
|
77
80
|
prerelease: false
|
78
81
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -80,6 +83,9 @@ dependencies:
|
|
80
83
|
- - "~>"
|
81
84
|
- !ruby/object:Gem::Version
|
82
85
|
version: '0.17'
|
86
|
+
- - "<"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.18'
|
83
89
|
- !ruby/object:Gem::Dependency
|
84
90
|
name: tty-platform
|
85
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -121,6 +127,7 @@ files:
|
|
121
127
|
- README.md
|
122
128
|
- bin/patchelf.rb
|
123
129
|
- lib/patchelf.rb
|
130
|
+
- lib/patchelf/alt_saver.rb
|
124
131
|
- lib/patchelf/cli.rb
|
125
132
|
- lib/patchelf/exceptions.rb
|
126
133
|
- lib/patchelf/helper.rb
|
@@ -132,7 +139,8 @@ files:
|
|
132
139
|
homepage: https://github.com/david942j/patchelf.rb
|
133
140
|
licenses:
|
134
141
|
- MIT
|
135
|
-
metadata:
|
142
|
+
metadata:
|
143
|
+
rubygems_mfa_required: 'true'
|
136
144
|
post_install_message:
|
137
145
|
rdoc_options: []
|
138
146
|
require_paths:
|
@@ -141,14 +149,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
149
|
requirements:
|
142
150
|
- - ">="
|
143
151
|
- !ruby/object:Gem::Version
|
144
|
-
version: '2.
|
152
|
+
version: '2.6'
|
145
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
154
|
requirements:
|
147
155
|
- - ">="
|
148
156
|
- !ruby/object:Gem::Version
|
149
157
|
version: '0'
|
150
158
|
requirements: []
|
151
|
-
rubygems_version: 3.
|
159
|
+
rubygems_version: 3.1.6
|
152
160
|
signing_key:
|
153
161
|
specification_version: 4
|
154
162
|
summary: patchelf
|