bwrap 1.2.0 → 1.3.1
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +14 -0
- data/README.md +9 -0
- data/lib/bwrap/args/bind.rb +0 -4
- data/lib/bwrap/args/construct.rb +5 -1
- data/lib/bwrap/args/namespace.rb +25 -0
- data/lib/bwrap/args/network.rb +5 -0
- data/lib/bwrap/bwrap.rb +3 -1
- data/lib/bwrap/config.rb +18 -2
- data/lib/bwrap/exceptions.rb +1 -0
- data/lib/bwrap/execution.rb +1 -0
- data/lib/bwrap/resolvers/library/base.rb +22 -0
- data/lib/bwrap/resolvers/library/library.rb +74 -0
- data/lib/bwrap/resolvers/library/llvm_readelf.rb +133 -0
- data/lib/bwrap/resolvers/library/musl.rb +54 -0
- data/lib/bwrap/resolvers/library.rb +3 -151
- data/lib/bwrap/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +21 -16
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d50d32e5158e20f7a5a1f75124c8b657a12b54b3392612d5aa11e9717add289
|
4
|
+
data.tar.gz: 7ac4aede1519880cd7c4e48d233688d1fb0d2ade75e8dc202bd27969d9c28428
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88dfdab0abd2342289724060107c1a8fcc681eac5a4b24f402e316cc8d4470e33cb9fe11f7be1072b2dc0b97f3b1fc10e7df92bce192f0de9de9978f423237c0
|
7
|
+
data.tar.gz: 76fc0bd2dc04e98b3254a540813212a6b9fb7cba1b7c0f64f49a19577106eb0dc8efac79215e4f689a229e1bfce57e9b9ca0926347d552d28000aa815697892f
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
## 1.3.1 (06.01.2023)
|
4
|
+
|
5
|
+
* Renewed expired key
|
6
|
+
|
7
|
+
## 1.3.0 (06.01.2023)
|
8
|
+
|
9
|
+
NOTE: No gem was released due expired key.
|
10
|
+
|
11
|
+
* Introduced llvm-readelf as additional dependency for library resolution.
|
12
|
+
* Fix library resolution on newer systems.
|
13
|
+
* Made resolv.conf binding to require a configuration option.
|
14
|
+
* Added option for --unshare-all (enabled by default, which is previous behaviour).
|
15
|
+
* Return output of the command with Bwrap#run
|
16
|
+
|
3
17
|
## 1.2.0 (20.07.2022)
|
4
18
|
|
5
19
|
* Properly throw execution failure exception
|
data/README.md
CHANGED
@@ -20,6 +20,15 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
$ gem install bwrap
|
22
22
|
|
23
|
+
Running system must have following executables present:
|
24
|
+
- scanelf (from pax-utils)
|
25
|
+
|
26
|
+
Additionally, for musl executables and libraries, following are necessary:
|
27
|
+
- ldd
|
28
|
+
|
29
|
+
Additionally, for glibc executables and libraries, following are necessary:
|
30
|
+
- llvm-readelf
|
31
|
+
|
23
32
|
## Usage
|
24
33
|
|
25
34
|
For now this is under ongoing development, though semantic versioning will apply.
|
data/lib/bwrap/args/bind.rb
CHANGED
@@ -53,10 +53,6 @@ class Bwrap::Args::Bind
|
|
53
53
|
#
|
54
54
|
# Or maybe the data should be calculated and these are excluded in
|
55
55
|
# Construct#bwrap_arguments?
|
56
|
-
#
|
57
|
-
# NOTE: After making Config optional, now this requires config to be preset
|
58
|
-
# for full_system_mounts option to have any effect. Maybe it should always
|
59
|
-
# be like so by default...?
|
60
56
|
return if @config && !@config&.full_system_mounts
|
61
57
|
|
62
58
|
@library_bind.handle_given_command
|
data/lib/bwrap/args/construct.rb
CHANGED
@@ -10,6 +10,7 @@ require_relative "environment"
|
|
10
10
|
require_relative "features"
|
11
11
|
require_relative "machine_id"
|
12
12
|
require_relative "mount"
|
13
|
+
require_relative "namespace"
|
13
14
|
require_relative "network"
|
14
15
|
require_relative "user"
|
15
16
|
|
@@ -63,7 +64,7 @@ class Bwrap::Args::Construct
|
|
63
64
|
proc_mount
|
64
65
|
tmp_as_tmpfs
|
65
66
|
@bind.bind_home_directory
|
66
|
-
@
|
67
|
+
@namespace.shares
|
67
68
|
@network.share_net
|
68
69
|
@network.hostname
|
69
70
|
@args.add :environment, @environment.environment_variables
|
@@ -145,6 +146,9 @@ class Bwrap::Args::Construct
|
|
145
146
|
@machine_id = Bwrap::Args::MachineId.new
|
146
147
|
@machine_id.config = @config
|
147
148
|
|
149
|
+
@namespace = Bwrap::Args::Namespace.new @args
|
150
|
+
@namespace.config = @config
|
151
|
+
|
148
152
|
@network = Bwrap::Args::Network.new @args
|
149
153
|
@network.config = @config
|
150
154
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
|
6
|
+
# Namespace related arguments.
|
7
|
+
#
|
8
|
+
# Mostly for handling --unshare-*
|
9
|
+
class Bwrap::Args::Namespace
|
10
|
+
include Bwrap::Output
|
11
|
+
|
12
|
+
# Instance of {Config}.
|
13
|
+
attr_writer :config
|
14
|
+
|
15
|
+
# @param args [Bwrap::Args::Args] Arguments to be passed to bwrap.
|
16
|
+
def initialize args
|
17
|
+
@args = args
|
18
|
+
end
|
19
|
+
|
20
|
+
def shares
|
21
|
+
return unless @config&.unshare_all
|
22
|
+
|
23
|
+
@args.add :unshare_all, "--unshare-all" # Practically means that there would be nothing in the sandbox by default.
|
24
|
+
end
|
25
|
+
end
|
data/lib/bwrap/args/network.rb
CHANGED
@@ -24,7 +24,12 @@ class Bwrap::Args::Network
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Arguments to read-only bind /etc/resolv.conf.
|
27
|
+
#
|
28
|
+
# TODO: Probably it should be checked if target will have the symlink present before
|
29
|
+
# doing this automatically. For that reason, now this will need a flag.
|
27
30
|
def resolv_conf
|
31
|
+
return unless @config&.resolv_conf
|
32
|
+
|
28
33
|
# We can’t really bind symlinks, so let’s resolve real path to resolv.conf, in case it is symlinked.
|
29
34
|
source_resolv_conf = Pathname.new "/etc/resolv.conf"
|
30
35
|
source_resolv_conf = source_resolv_conf.realpath
|
data/lib/bwrap/bwrap.rb
CHANGED
@@ -98,9 +98,11 @@ class Bwrap::Bwrap
|
|
98
98
|
kwargs[:log_callback] ||= 1
|
99
99
|
kwargs[:log_callback] += 1
|
100
100
|
|
101
|
-
execute exec_command, **kwargs
|
101
|
+
result = execute exec_command, **kwargs
|
102
102
|
|
103
103
|
@construct.cleanup
|
104
|
+
|
105
|
+
result
|
104
106
|
end
|
105
107
|
|
106
108
|
# Convenience method to executes a command that is inside bwrap.
|
data/lib/bwrap/config.rb
CHANGED
@@ -53,8 +53,6 @@ class Bwrap::Config
|
|
53
53
|
# @return [#each] Array of executables to bind
|
54
54
|
attr_accessor :extra_executables
|
55
55
|
|
56
|
-
# TODO: IIRC this doesn’t match the reality any more. So write correct documentation.
|
57
|
-
#
|
58
56
|
# Causes libraries required by the executable given to {Bwrap#run} to be
|
59
57
|
# mounted inside sandbox.
|
60
58
|
#
|
@@ -62,6 +60,10 @@ class Bwrap::Config
|
|
62
60
|
# using {#libdir_mounts=}
|
63
61
|
#
|
64
62
|
# @return [Boolean] true if Linux library loaders are mounted inside chroot
|
63
|
+
#
|
64
|
+
# TODO: Since this only causes given executable be scanned for dependencies,
|
65
|
+
# and not ”--bind / /”, this one should be deprecated and something like
|
66
|
+
# ”@config.bind_dependents = true” should be added as alias of this.
|
65
67
|
attr_accessor :full_system_mounts
|
66
68
|
|
67
69
|
# If set to `true`, things like /dev/dri is bound to sandbox to enable usage
|
@@ -98,9 +100,22 @@ class Bwrap::Config
|
|
98
100
|
# Given file as bound as /etc/machine_id.
|
99
101
|
attr_accessor :machine_id
|
100
102
|
|
103
|
+
# If set to truthy, /etc/resolv.conf will be bound to target.
|
104
|
+
attr_accessor :resolv_conf
|
105
|
+
|
101
106
|
# @return [Boolean] true if network should be shared from host.
|
102
107
|
attr_accessor :share_net
|
103
108
|
|
109
|
+
# Set to truthy to remove (see bwrap’s --unshare-all) all namespaces from
|
110
|
+
# target chroot.
|
111
|
+
#
|
112
|
+
# Defaults to true.
|
113
|
+
#
|
114
|
+
# TODO: Create more fine grained control for sharing logic than this one.
|
115
|
+
#
|
116
|
+
# @return [Boolean] true if all namespaces are tried to be removed from target.
|
117
|
+
attr_accessor :unshare_all
|
118
|
+
|
104
119
|
# Name of the user inside chroot.
|
105
120
|
#
|
106
121
|
# This is optional and defaults to no user.
|
@@ -166,6 +181,7 @@ class Bwrap::Config
|
|
166
181
|
@env_paths = []
|
167
182
|
@ro_binds = {}
|
168
183
|
@tmpdir = Dir.tmpdir
|
184
|
+
@unshare_all = true
|
169
185
|
end
|
170
186
|
|
171
187
|
def binaries_from= array
|
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
data/lib/bwrap/execution.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/execution"
|
4
|
+
require "bwrap/output"
|
5
|
+
require_relative "../library"
|
6
|
+
|
7
|
+
# Base definitions for library resolver subclasses.
|
8
|
+
class Bwrap::Resolvers::Library::Base
|
9
|
+
include Bwrap::Execution
|
10
|
+
include Bwrap::Output
|
11
|
+
|
12
|
+
private def convert_binary_paths binary_paths
|
13
|
+
case binary_paths
|
14
|
+
when String
|
15
|
+
[ binary_paths ]
|
16
|
+
when Pathname
|
17
|
+
[ binary_paths.to_s ]
|
18
|
+
else
|
19
|
+
binary_paths
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/execution"
|
4
|
+
require "bwrap/output"
|
5
|
+
require_relative "llvm_readelf"
|
6
|
+
require_relative "musl"
|
7
|
+
require_relative "../resolvers"
|
8
|
+
|
9
|
+
# See ../library.rb for class documentation.
|
10
|
+
class Bwrap::Resolvers::Library
|
11
|
+
include Bwrap::Execution
|
12
|
+
include Bwrap::Output
|
13
|
+
|
14
|
+
# NOTE: This caching can be made more efficient, but need to look at it later, what to do about it.
|
15
|
+
@@needed_libraries_cache ||= []
|
16
|
+
|
17
|
+
# Empties `@@needed_libraries_cache`.
|
18
|
+
def self.clear_needed_libraries_cache
|
19
|
+
@@needed_libraries_cache.clear
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def needed_libraries_cache
|
24
|
+
@@needed_libraries_cache
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Otherwise similar to {#needed_libraries}, but checks used libc to handle musl executables.
|
29
|
+
#
|
30
|
+
# @param executable [String] Path to the executable to find dependencies for
|
31
|
+
# @return [Array] Libraries the executable needs, if any
|
32
|
+
def libraries_needed_by executable
|
33
|
+
trace "Finding libraries needed by #{executable}"
|
34
|
+
|
35
|
+
# %i == interpreter, the library used to load the executable by kernel.
|
36
|
+
# %F == Path to given file.
|
37
|
+
output_format = "%i::SEPARATOR::%F"
|
38
|
+
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} }
|
39
|
+
scanelf_command << executable
|
40
|
+
|
41
|
+
data = execvalue scanelf_command
|
42
|
+
|
43
|
+
# If data is empty, target probably is a script of some sort.
|
44
|
+
if data.empty?
|
45
|
+
return []
|
46
|
+
end
|
47
|
+
|
48
|
+
data = data.strip
|
49
|
+
interpreter, _executable_path = data.split "::SEPARATOR::"
|
50
|
+
interpreter = Pathname.new interpreter
|
51
|
+
|
52
|
+
if interpreter.basename.to_s[0..6] == "ld-musl"
|
53
|
+
trace "Resolved to musl interpreter: #{interpreter}"
|
54
|
+
musl_needed_libraries executable
|
55
|
+
else
|
56
|
+
trace "Defaulting to glibc interpreter: #{interpreter}"
|
57
|
+
# For glibc, scanelf can return full paths for us most of time.
|
58
|
+
needed_libraries executable
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
63
|
+
def musl_needed_libraries binary_paths
|
64
|
+
musl = Musl.new
|
65
|
+
@needed_libraries = musl.needed_libraries binary_paths
|
66
|
+
end
|
67
|
+
|
68
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
69
|
+
def needed_libraries binary_paths
|
70
|
+
llvm_readelf = LLVMReadelf.new
|
71
|
+
@needed_libraries = llvm_readelf.needed_libraries binary_paths
|
72
|
+
end
|
73
|
+
end
|
74
|
+
# class Library ended
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
# Used via {Bwrap::Resolvers::Library}.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Bwrap::Resolvers::Library::LLVMReadelf < Bwrap::Resolvers::Library::Base
|
9
|
+
# Resolve dependents using llvm-readelf.
|
10
|
+
#
|
11
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
12
|
+
def needed_libraries binary_paths
|
13
|
+
raise ArgumentError, "binary_paths is nil, expected an Array" if binary_paths.nil?
|
14
|
+
|
15
|
+
trace "Finding libraries #{binary_paths} requires"
|
16
|
+
@needed_libraries = []
|
17
|
+
|
18
|
+
llvm_readelf_command = %w{ llvm-readelf --needed-libs }
|
19
|
+
|
20
|
+
binary_paths = convert_binary_paths binary_paths
|
21
|
+
|
22
|
+
# Check if the exe is already resolved.
|
23
|
+
binary_paths.delete_if do |binary_path|
|
24
|
+
Bwrap::Resolvers::Library.needed_libraries_cache.include? binary_path
|
25
|
+
end
|
26
|
+
|
27
|
+
return [] if binary_paths.empty?
|
28
|
+
|
29
|
+
data = execvalue(llvm_readelf_command + binary_paths)
|
30
|
+
parse_llvm_readelf_output binary_paths, data
|
31
|
+
|
32
|
+
@needed_libraries
|
33
|
+
end
|
34
|
+
|
35
|
+
# Parses output returned by llvm-readelf --needed-libraries
|
36
|
+
#
|
37
|
+
# Sets libraries to @needed_libraries variable.
|
38
|
+
private def parse_llvm_readelf_output binary_paths, data
|
39
|
+
iter = data.split("\n").each
|
40
|
+
source_binary = binary_paths.first
|
41
|
+
begin
|
42
|
+
while (line = iter.next)
|
43
|
+
source_binary = line[6..-1].strip if line[0..5] == "File: "
|
44
|
+
next unless line[0..16] == "NeededLibraries ["
|
45
|
+
|
46
|
+
while (library = iter.next)
|
47
|
+
library = library.strip
|
48
|
+
# End of library list for current NeededLibraries block.
|
49
|
+
break if library == "]"
|
50
|
+
|
51
|
+
library = convert_to_full_path source_binary, library
|
52
|
+
|
53
|
+
add_library_to_needed_libraries library
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue StopIteration
|
57
|
+
# End of the iteration.
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# NOTE: Maybe this could be in general file here, if needed elsewhere also?
|
62
|
+
# This also applies to some other methods here.
|
63
|
+
#
|
64
|
+
# Finds where given library would be loaded from.
|
65
|
+
#
|
66
|
+
# source_binary is used to to if it has RPATH set as third possibility.
|
67
|
+
# TODO: Implement above.
|
68
|
+
#
|
69
|
+
# @param source_binary [String] Executable or library which is loading the binary
|
70
|
+
private def convert_to_full_path source_binary, library
|
71
|
+
# TODO: Somewhere put a cleanup for this variable, so this is erased
|
72
|
+
# before application is run. That will save at least 200 kB of memory.
|
73
|
+
@@ld_so_cache ||= File.read("/etc/ld.so.cache", mode: "rb")
|
74
|
+
|
75
|
+
path_regex = %r{[\w\-/. ]{3,}}
|
76
|
+
|
77
|
+
check_next = false
|
78
|
+
@@ld_so_cache.scan(path_regex).each do |match|
|
79
|
+
if check_next
|
80
|
+
# TODO: Any sense checking for executable bit?
|
81
|
+
return match if File.exist? match
|
82
|
+
|
83
|
+
check_next = false
|
84
|
+
end
|
85
|
+
|
86
|
+
check_next = true if match == library
|
87
|
+
end
|
88
|
+
|
89
|
+
warn "Failed to resolve full path of library #{library}, needed by #{source_binary}."
|
90
|
+
library
|
91
|
+
end
|
92
|
+
|
93
|
+
# @param library [Array] library to add.
|
94
|
+
private def add_library_to_needed_libraries library
|
95
|
+
raise ArgumentError, "library is nil, expected a String" if library.nil?
|
96
|
+
|
97
|
+
return if @needed_libraries.include? library
|
98
|
+
|
99
|
+
# Probably no sense to log these unless tracing,
|
100
|
+
# as dependencies should work most of time.
|
101
|
+
#
|
102
|
+
# It also outputs tons of output for more complex programs.
|
103
|
+
trace "Binding #{library}"
|
104
|
+
|
105
|
+
@needed_libraries << library
|
106
|
+
|
107
|
+
# Also check if requisite libraries needs some libraries.
|
108
|
+
inner = Bwrap::Resolvers::Library.new
|
109
|
+
@needed_libraries |= inner.needed_libraries library
|
110
|
+
|
111
|
+
Bwrap::Resolvers::Library.needed_libraries_cache << library
|
112
|
+
end
|
113
|
+
|
114
|
+
# @param libraries [Array] libraries to add.
|
115
|
+
private def add_libraries_to_needed_libraries libraries
|
116
|
+
# Add to needed libraries if not already added.
|
117
|
+
(@needed_libraries & libraries).each do |library|
|
118
|
+
# Probably no sense to log these unless tracing,
|
119
|
+
# as dependencies should work most of time.
|
120
|
+
#
|
121
|
+
# It also outputs tons of output for more complex programs.
|
122
|
+
trace "Binding #{library}"
|
123
|
+
end
|
124
|
+
|
125
|
+
@needed_libraries |= libraries
|
126
|
+
|
127
|
+
# Also check if requisite libraries needs some libraries.
|
128
|
+
inner = Bwrap::Resolvers::Library.new
|
129
|
+
@needed_libraries |= inner.needed_libraries libraries
|
130
|
+
|
131
|
+
Bwrap::Resolvers::Library.needed_libraries_cache |= libraries
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
# Used via {Bwrap::Resolvers::Library}.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Bwrap::Resolvers::Library::Musl < Bwrap::Resolvers::Library::Base
|
9
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
10
|
+
def needed_libraries binary_paths
|
11
|
+
trace "Finding musl libraries #{binary_paths} requires"
|
12
|
+
@needed_libraries = []
|
13
|
+
|
14
|
+
binary_paths = convert_binary_paths binary_paths
|
15
|
+
|
16
|
+
# Check if the exe is already resolved.
|
17
|
+
binary_paths.delete_if do |binary_path|
|
18
|
+
Bwrap::Resolvers::Library.needed_libraries_cache.include? binary_path
|
19
|
+
end
|
20
|
+
|
21
|
+
return [] if binary_paths.empty?
|
22
|
+
|
23
|
+
binary_paths.each do |binary_path|
|
24
|
+
output = execvalue %W{ ldd #{binary_path} }
|
25
|
+
lines = output.split "\n"
|
26
|
+
_interpreter_line = lines.shift
|
27
|
+
|
28
|
+
lines.each do |line|
|
29
|
+
parse_ldd_line line
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
@needed_libraries
|
34
|
+
end
|
35
|
+
|
36
|
+
# Used by {#musl_needed_libraries}.
|
37
|
+
private def parse_ldd_line line
|
38
|
+
line = line.strip
|
39
|
+
_library_name, library_data = line.split " => "
|
40
|
+
|
41
|
+
matches = library_data.match(/(.*) \(0x[0-9a-f]+\)/)
|
42
|
+
library_path = matches[1]
|
43
|
+
|
44
|
+
unless @needed_libraries.include? library_path
|
45
|
+
@needed_libraries << library_path
|
46
|
+
end
|
47
|
+
|
48
|
+
# Also check if requisite libraries needs some libraries.
|
49
|
+
inner = Bwrap::Resolvers::Library.new
|
50
|
+
@needed_libraries |= inner.musl_needed_libraries library_path
|
51
|
+
|
52
|
+
Bwrap::Resolvers::Library.needed_libraries_cache << library_path
|
53
|
+
end
|
54
|
+
end
|
@@ -1,160 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "bwrap/execution"
|
4
|
-
require "bwrap/output"
|
5
3
|
require_relative "resolvers"
|
6
4
|
|
7
5
|
# Class to clean up namespace for implementation specific reasons.
|
8
6
|
#
|
9
7
|
# @api private
|
10
8
|
class Bwrap::Resolvers::Library
|
11
|
-
|
12
|
-
include Bwrap::Output
|
13
|
-
|
14
|
-
# NOTE: This caching can be made more efficient, but need to look at it later, what to do about it.
|
15
|
-
@@needed_libraries_cache ||= []
|
16
|
-
|
17
|
-
# Empties `@@needed_libraries_cache`.
|
18
|
-
def self.clear_needed_libraries_cache
|
19
|
-
@@needed_libraries_cache.clear
|
20
|
-
end
|
21
|
-
|
22
|
-
# Otherwise similar to {#needed_libraries}, but checks used libc to handle musl executables.
|
23
|
-
#
|
24
|
-
# @param executable [String] Path to the executable to find dependencies for
|
25
|
-
# @return [Array] Libraries the executable needs, if any
|
26
|
-
def libraries_needed_by executable
|
27
|
-
# %i == interpreter, the library used to load the executable by kernel.
|
28
|
-
# %F == Path to given file.
|
29
|
-
output_format = "%i::SEPARATOR::%F"
|
30
|
-
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} }
|
31
|
-
scanelf_command << executable
|
32
|
-
|
33
|
-
data = execvalue scanelf_command
|
34
|
-
|
35
|
-
# If data is empty, target probably is a script of some sort.
|
36
|
-
if data.empty?
|
37
|
-
return []
|
38
|
-
end
|
39
|
-
|
40
|
-
data = data.strip
|
41
|
-
interpreter, _executable_path = data.split "::SEPARATOR::"
|
42
|
-
interpreter = Pathname.new interpreter
|
43
|
-
|
44
|
-
if interpreter.basename.to_s[0..6] == "ld-musl"
|
45
|
-
musl_needed_libraries executable
|
46
|
-
else
|
47
|
-
# For glibc, scanelf can return full paths for us most of time.
|
48
|
-
needed_libraries executable
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# @param binary_paths [String, Array] one or more paths to be resolved
|
53
|
-
def musl_needed_libraries binary_paths
|
54
|
-
trace "Finding musl libraries #{binary_paths} requires"
|
55
|
-
@needed_libraries = []
|
56
|
-
|
57
|
-
binary_paths = convert_binary_paths binary_paths
|
58
|
-
|
59
|
-
# Check if the exe is already resolved.
|
60
|
-
binary_paths.delete_if do |binary_path|
|
61
|
-
@@needed_libraries_cache.include? binary_path
|
62
|
-
end
|
63
|
-
|
64
|
-
return [] if binary_paths.empty?
|
65
|
-
|
66
|
-
binary_paths.each do |binary_path|
|
67
|
-
output = execvalue %W{ ldd #{binary_path} }
|
68
|
-
lines = output.split "\n"
|
69
|
-
_interpreter_line = lines.shift
|
70
|
-
|
71
|
-
lines.each do |line|
|
72
|
-
parse_ldd_line line
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
@needed_libraries
|
77
|
-
end
|
78
|
-
|
79
|
-
# @param binary_paths [String, Array] one or more paths to be resolved
|
80
|
-
def needed_libraries binary_paths
|
81
|
-
trace "Finding libraries #{binary_paths} requires"
|
82
|
-
@needed_libraries = []
|
83
|
-
|
84
|
-
# %i == interpreter, the library used to load the executable by kernel.
|
85
|
-
output_format = "%F::SEPARATOR::%n"
|
86
|
-
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} --ldcache --needed }
|
87
|
-
|
88
|
-
binary_paths = convert_binary_paths binary_paths
|
89
|
-
|
90
|
-
# Check if the exe is already resolved.
|
91
|
-
binary_paths.delete_if do |binary_path|
|
92
|
-
@@needed_libraries_cache.include? binary_path
|
93
|
-
end
|
94
|
-
|
95
|
-
return [] if binary_paths.empty?
|
96
|
-
|
97
|
-
data = execvalue(scanelf_command + binary_paths)
|
98
|
-
trace "scanelf found following libraries: #{data}"
|
99
|
-
|
100
|
-
lines = data.split "\n"
|
101
|
-
lines.each do |line|
|
102
|
-
parse_scanelf_line line
|
103
|
-
end
|
104
|
-
|
105
|
-
@needed_libraries
|
106
|
-
end
|
107
|
-
|
108
|
-
private def convert_binary_paths binary_paths
|
109
|
-
if binary_paths.is_a? String
|
110
|
-
[ binary_paths ]
|
111
|
-
elsif binary_paths.is_a? Pathname
|
112
|
-
[ binary_paths.to_s ]
|
113
|
-
else
|
114
|
-
binary_paths
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Used by {#needed_libraries}.
|
119
|
-
private def parse_scanelf_line line
|
120
|
-
binary_path, libraries_line = line.split "::SEPARATOR::"
|
121
|
-
libraries = libraries_line.split ","
|
122
|
-
|
123
|
-
# Add to needed libraries if not already added.
|
124
|
-
(@needed_libraries & libraries).each do |library|
|
125
|
-
# Probably no sense to log these unless tracing,
|
126
|
-
# as dependencies should work most of time.
|
127
|
-
#
|
128
|
-
# It also outputs tons of output for more complex programs.
|
129
|
-
trace "Binding #{library} as dependency of #{binary_path}"
|
130
|
-
end
|
131
|
-
|
132
|
-
@needed_libraries |= libraries
|
133
|
-
|
134
|
-
# Also check if requisite libraries needs some libraries.
|
135
|
-
inner = Bwrap::Resolvers::Library.new
|
136
|
-
@needed_libraries |= inner.needed_libraries libraries
|
137
|
-
|
138
|
-
@@needed_libraries_cache |= libraries
|
139
|
-
end
|
140
|
-
|
141
|
-
# Used by {#musl_needed_libraries}.
|
142
|
-
private def parse_ldd_line line
|
143
|
-
line = line.strip
|
144
|
-
_library_name, library_data = line.split " => "
|
145
|
-
|
146
|
-
matches = library_data.match(/(.*) \(0x[0-9a-f]+\)/)
|
147
|
-
library_path = matches[1]
|
148
|
-
|
149
|
-
unless @needed_libraries.include? library_path
|
150
|
-
@needed_libraries << library_path
|
151
|
-
end
|
152
|
-
|
153
|
-
# Also check if requisite libraries needs some libraries.
|
154
|
-
inner = Bwrap::Resolvers::Library.new
|
155
|
-
@needed_libraries |= inner.musl_needed_libraries library_path
|
156
|
-
|
157
|
-
@@needed_libraries_cache << library_path
|
158
|
-
end
|
9
|
+
# Declared here only for convenience.
|
159
10
|
end
|
160
|
-
|
11
|
+
|
12
|
+
require_relative "library/library"
|
data/lib/bwrap/version.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bwrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samu Voutilainen
|
@@ -10,8 +10,8 @@ bindir: bin
|
|
10
10
|
cert_chain:
|
11
11
|
- |
|
12
12
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
13
|
+
MIID8DCCAligAwIBAgIBAjANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBNid3Jh
|
14
|
+
cC9EQz1zbWFyL0RDPWZpMB4XDTIzMDEwNjA2NTUyNFoXDTI0MDEwNjA2NTUyNFow
|
15
15
|
HjEcMBoGA1UEAwwTYndyYXAvREM9c21hci9EQz1maTCCAaIwDQYJKoZIhvcNAQEB
|
16
16
|
BQADggGPADCCAYoCggGBAKUQ5wFdLLIejwiCNeGMlbApquoC0jT59H+d6zOLWxYd
|
17
17
|
RRdum9G1lxFFFolEsFj5RSplg/SlhAhYRMUjDHiSk/usxVcOt28h4sdiFTbi1zKA
|
@@ -21,20 +21,19 @@ cert_chain:
|
|
21
21
|
NqpsI0mQejnq+QdiNz9gAWObO+UhrOv5S7E0NYQTaf1e3G56kCmIG9p0pFXjWNPx
|
22
22
|
DhL6YDoizVSQKTllYWbDhBx0+D+sevtmKAy0vHDAY33teAQYOxgeE/iXqvvROPU7
|
23
23
|
HNOAqNazQHwPsTepLT9Dc/5bVbazL1MNNiWh5ZYjmJnlGSttHhM/xsZZkckJ20oh
|
24
|
-
|
25
|
-
sDAdBgNVHQ4EFgQUywyVCkA/
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
MRxVMHiVAqY=
|
24
|
+
0iJSyUprpR2epHP8832n6wIDAQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE
|
25
|
+
sDAdBgNVHQ4EFgQUywyVCkA/Pr5zdaaMvAVlHKSXeJkwDQYJKoZIhvcNAQELBQAD
|
26
|
+
ggGBAGmSe4zkcmNd3JfmTA9CDpBu3j6qiPnbk2x8vTjDQAyAGRjX8Depzz39jUbF
|
27
|
+
cmmL/J5XqqkZaYy7X+w2nWVYk8BwmAP3ft6L6qO0rmZhOtfsyTzf0fI1zY20Y98W
|
28
|
+
uoDoS2cL6fIJ8Gv6B4tXCSZO1cQOHMAhzAeRGbfn0InbDtalfVbYFmnmo9PqJz4C
|
29
|
+
kRUFHNCTRt+YAneAZ2gAU4r89EuNheyyEmPonWHjCwPIGKS/rsChFWIU22wrZkGd
|
30
|
+
aWT3as+jC2gDiQTw82JalFWsqK9p9UxsRt1lkV4mb5NSDcKl7ApI1TAW2EANeLOx
|
31
|
+
PWJbiDgQIrErC5lDu25gzWF+g5sYc7uaMcKxS8BqAggMWuW/lUcNX8e+4WdDAPgO
|
32
|
+
tDIK8ZQo4kVJE9EQTA4LsP4TMNDn18vBr0aIY92p+uq31rocusojfAszU50DSw3M
|
33
|
+
7a31nUjVeQjpooaUQi6ECFr+Neidh3jhzreVfXqjxMkPOYLlCAmd9E1izCTRIgLS
|
34
|
+
cAzqsw==
|
36
35
|
-----END CERTIFICATE-----
|
37
|
-
date:
|
36
|
+
date: 2023-01-06 00:00:00.000000000 Z
|
38
37
|
dependencies:
|
39
38
|
- !ruby/object:Gem::Dependency
|
40
39
|
name: bundler
|
@@ -158,6 +157,7 @@ files:
|
|
158
157
|
- lib/bwrap/args/features/ruby_binds.rb
|
159
158
|
- lib/bwrap/args/machine_id.rb
|
160
159
|
- lib/bwrap/args/mount.rb
|
160
|
+
- lib/bwrap/args/namespace.rb
|
161
161
|
- lib/bwrap/args/network.rb
|
162
162
|
- lib/bwrap/args/user.rb
|
163
163
|
- lib/bwrap/bwrap.rb
|
@@ -166,6 +166,7 @@ files:
|
|
166
166
|
- lib/bwrap/config/features.rb
|
167
167
|
- lib/bwrap/config/features/base.rb
|
168
168
|
- lib/bwrap/config/features/ruby.rb
|
169
|
+
- lib/bwrap/exceptions.rb
|
169
170
|
- lib/bwrap/execution.rb
|
170
171
|
- lib/bwrap/execution/exceptions.rb
|
171
172
|
- lib/bwrap/execution/exec.rb
|
@@ -182,6 +183,10 @@ files:
|
|
182
183
|
- lib/bwrap/output/output_impl.rb
|
183
184
|
- lib/bwrap/resolvers/executable.rb
|
184
185
|
- lib/bwrap/resolvers/library.rb
|
186
|
+
- lib/bwrap/resolvers/library/base.rb
|
187
|
+
- lib/bwrap/resolvers/library/library.rb
|
188
|
+
- lib/bwrap/resolvers/library/llvm_readelf.rb
|
189
|
+
- lib/bwrap/resolvers/library/musl.rb
|
185
190
|
- lib/bwrap/resolvers/mime.rb
|
186
191
|
- lib/bwrap/resolvers/resolvers.rb
|
187
192
|
- lib/bwrap/version.rb
|
metadata.gz.sig
CHANGED
Binary file
|