patchelf 1.2.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|