bwrap 1.0.0.pre.alpha3 → 1.0.0.pre.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +39 -0
- data/README.md +2 -0
- data/lib/bwrap/args/args.rb +5 -1
- data/lib/bwrap/args/bind/library.rb +188 -0
- data/lib/bwrap/args/bind/mime.rb +58 -0
- data/lib/bwrap/args/bind.rb +90 -27
- data/lib/bwrap/args/construct.rb +69 -35
- data/lib/bwrap/args/environment.rb +59 -1
- data/lib/bwrap/args/features.rb +128 -0
- data/lib/bwrap/args/library.rb +137 -0
- data/lib/bwrap/args/machine_id.rb +6 -3
- data/lib/bwrap/args/mount.rb +12 -3
- data/lib/bwrap/bwrap.rb +151 -0
- data/lib/bwrap/bwrap_module.rb +26 -0
- data/lib/bwrap/config/features.rb +116 -0
- data/lib/bwrap/config.rb +130 -17
- data/lib/bwrap/execution/exceptions.rb +24 -0
- data/lib/bwrap/execution/execute.rb +5 -2
- data/lib/bwrap/execution/execution.rb +147 -3
- data/lib/bwrap/execution/labels.rb +8 -1
- data/lib/bwrap/execution/path.rb +84 -0
- data/lib/bwrap/execution.rb +6 -172
- data/lib/bwrap/output/colors.rb +0 -2
- data/lib/bwrap/output/log.rb +11 -5
- data/lib/bwrap/output/output_impl.rb +182 -0
- data/lib/bwrap/output.rb +8 -148
- data/lib/bwrap/version.rb +1 -2
- data/lib/bwrap.rb +1 -72
- data.tar.gz.sig +0 -0
- metadata +18 -21
- metadata.gz.sig +0 -0
- data/lib/bwrap/output/output.rb +0 -8
@@ -1,24 +1,82 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bwrap/execution"
|
3
4
|
require "bwrap/output"
|
4
5
|
require_relative "args"
|
5
6
|
|
6
7
|
# Environment variable calculation for bwrap.
|
7
8
|
class Bwrap::Args::Environment < Hash
|
9
|
+
include Bwrap::Execution
|
8
10
|
include Bwrap::Output
|
9
11
|
|
10
12
|
# Instance of {Config}.
|
11
13
|
attr_writer :config
|
12
14
|
|
13
|
-
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
|
18
|
+
self["PATH"] ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns used environment variables wrapped as bwrap arguments.
|
14
22
|
def environment_variables
|
15
23
|
if debug?
|
16
24
|
debug "Passing following environment variables to bwrap:\n" \
|
17
25
|
"#{self}"
|
18
26
|
end
|
19
27
|
|
28
|
+
env_paths
|
29
|
+
|
20
30
|
map do |key, value|
|
31
|
+
if key == "PATH" and value.respond_to? :join
|
32
|
+
value = value.join ":"
|
33
|
+
end
|
34
|
+
|
21
35
|
[ "--setenv", key, value ]
|
22
36
|
end
|
23
37
|
end
|
38
|
+
|
39
|
+
# @return [Array] All environment paths added via {Config#add_env_path} and other parsing logic
|
40
|
+
def env_paths
|
41
|
+
if @config.env_paths.respond_to? :each
|
42
|
+
self["PATH"] |= @config.env_paths
|
43
|
+
end
|
44
|
+
|
45
|
+
features_env_paths
|
46
|
+
|
47
|
+
self["PATH"]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Adds given paths to PATH environment variable defined in the sandbox.
|
51
|
+
#
|
52
|
+
# @param elements [String, Array] Path(s) to be added added to PATH environment variable
|
53
|
+
def add_to_path elements
|
54
|
+
if elements.respond_to? :each
|
55
|
+
self["PATH"] += elements
|
56
|
+
else
|
57
|
+
# Expecting elements to be single path element as a string.
|
58
|
+
self["PATH"] << elements
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Feature specific environment path handling.
|
63
|
+
private def features_env_paths
|
64
|
+
ruby_env_paths
|
65
|
+
end
|
66
|
+
|
67
|
+
# Ruby feature specific environment path handling.
|
68
|
+
private def ruby_env_paths
|
69
|
+
return unless @config.features.ruby.enabled?
|
70
|
+
return unless @config.features.ruby.gem_env_paths?
|
71
|
+
|
72
|
+
unless command_available? "gem"
|
73
|
+
warn "gem is not installed in the system, so can’t add its bindirs to PATH."
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
gempath = execvalue %w{ gem environment gempath }
|
78
|
+
gempath.split(":").each do |path|
|
79
|
+
self["PATH"] << "#{path}/bin"
|
80
|
+
end
|
81
|
+
end
|
24
82
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
require_relative "library"
|
6
|
+
|
7
|
+
# Feature parameter construction.
|
8
|
+
#
|
9
|
+
# @see Config::Features
|
10
|
+
class Bwrap::Args::Features < Hash
|
11
|
+
include Bwrap::Output
|
12
|
+
|
13
|
+
# Implementation for Bash feature set.
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
class BashBinds
|
17
|
+
# Mounts stuff like /bin/bash.
|
18
|
+
def bash_mounts
|
19
|
+
mounts = []
|
20
|
+
|
21
|
+
if File.file? "/bin/bash"
|
22
|
+
mounts << "--ro-bind" << "/bin/bash" << "/bin/bash"
|
23
|
+
end
|
24
|
+
if File.file? "/usr/bin/bash"
|
25
|
+
mounts << "--ro-bind" << "/usr/bin/bash" << "/usr/bin/bash"
|
26
|
+
end
|
27
|
+
|
28
|
+
mounts
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Implementation for nscd feature set.
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
class NscdBinds
|
36
|
+
# Custom binds needed by the feature.
|
37
|
+
def custom_binds
|
38
|
+
mounts = []
|
39
|
+
|
40
|
+
# TODO: Probably some path checking is needed here. Or somewhere.
|
41
|
+
# TODO: Since on many systems /var/run is symlinked to /run, that probably should be handled.
|
42
|
+
mounts << "--ro-bind" << "/var/run/nscd" << "/var/run/nscd"
|
43
|
+
|
44
|
+
mounts
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Implementation for Ruby feature set.
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
class RubyBinds
|
52
|
+
# Returns mounts needed by Ruby feature set.
|
53
|
+
attr_reader :mounts
|
54
|
+
|
55
|
+
# Bind system paths so scripts works inside sandbox.
|
56
|
+
def sitedir_mounts
|
57
|
+
mounts = []
|
58
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["sitedir"] << RbConfig::CONFIG["sitedir"]
|
59
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["rubyhdrdir"] << RbConfig::CONFIG["rubyhdrdir"]
|
60
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["rubylibdir"] << RbConfig::CONFIG["rubylibdir"]
|
61
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["vendordir"] << RbConfig::CONFIG["vendordir"]
|
62
|
+
|
63
|
+
mounts
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create binds for required system libraries.
|
67
|
+
#
|
68
|
+
# These are in path like /usr/lib64/ruby/2.5.0/x86_64-linux-gnu/,
|
69
|
+
# and as they are mostly shared libraries, they may have some extra
|
70
|
+
# dependencies that also need to be bound inside the sandbox.
|
71
|
+
def stdlib_mounts stdlib
|
72
|
+
library_mounts = []
|
73
|
+
library = Bwrap::Args::Library.new
|
74
|
+
stdlib.each do |lib|
|
75
|
+
path = "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
|
76
|
+
|
77
|
+
library.needed_libraries(path).each do |requisite_library|
|
78
|
+
library_mounts << "--ro-bind" << requisite_library << requisite_library
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
library_mounts
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# `Array` of parameters passed to bwrap.
|
87
|
+
attr_writer :args
|
88
|
+
|
89
|
+
# Instance of {Config}.
|
90
|
+
attr_writer :config
|
91
|
+
|
92
|
+
# Resolves binds required by different features.
|
93
|
+
#
|
94
|
+
# Currently implemented feature sets:
|
95
|
+
# - ruby
|
96
|
+
def feature_binds
|
97
|
+
bash_binds
|
98
|
+
nscd_binds
|
99
|
+
ruby_binds
|
100
|
+
end
|
101
|
+
|
102
|
+
private def bash_binds
|
103
|
+
return unless @config.features.bash.enabled?
|
104
|
+
|
105
|
+
binds = BashBinds.new
|
106
|
+
|
107
|
+
@args.append binds.bash_mounts
|
108
|
+
end
|
109
|
+
|
110
|
+
private def nscd_binds
|
111
|
+
return unless @config.features.nscd.enabled?
|
112
|
+
|
113
|
+
binds = NscdBinds.new
|
114
|
+
|
115
|
+
@args.append binds.custom_binds
|
116
|
+
end
|
117
|
+
|
118
|
+
# @note This does not allow development headers needed for compilation for now.
|
119
|
+
# I’ll look at it after I have an use for it.
|
120
|
+
private def ruby_binds
|
121
|
+
return unless @config.features.ruby.enabled?
|
122
|
+
|
123
|
+
binds = RubyBinds.new
|
124
|
+
|
125
|
+
@args.append binds.sitedir_mounts
|
126
|
+
@args.append binds.stdlib_mounts(@config.features.ruby.stdlib)
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/execution"
|
4
|
+
require "bwrap/output"
|
5
|
+
require_relative "args"
|
6
|
+
|
7
|
+
# Class to clean up namespace for implementation specific reasons.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Bwrap::Args::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
|
+
# 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
|
+
def libraries_needed_by executable
|
26
|
+
# %i == interpreter, the library used to load the executable by kernel.
|
27
|
+
# %F == Path to given file.
|
28
|
+
output_format = "%i::SEPARATOR::%F"
|
29
|
+
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} }
|
30
|
+
scanelf_command << executable
|
31
|
+
|
32
|
+
data = execvalue scanelf_command
|
33
|
+
data = data.strip
|
34
|
+
interpreter, _executable_path = data.split "::SEPARATOR::"
|
35
|
+
interpreter = Pathname.new interpreter
|
36
|
+
|
37
|
+
if interpreter.basename.to_s[0..6] == "ld-musl"
|
38
|
+
musl_needed_libraries executable
|
39
|
+
else
|
40
|
+
# For glibc, scanelf can return full paths for us most of time.
|
41
|
+
needed_libraries executable
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
46
|
+
#
|
47
|
+
# @todo Maybe caching should be done here too?
|
48
|
+
def musl_needed_libraries binary_paths
|
49
|
+
trace "Finding musl libraries #{binary_paths} requires"
|
50
|
+
@needed_libraries = []
|
51
|
+
|
52
|
+
if binary_paths.is_a? String
|
53
|
+
binary_paths = [ binary_paths ]
|
54
|
+
end
|
55
|
+
|
56
|
+
binary_paths.each do |binary_path|
|
57
|
+
output = execvalue %W{ ldd #{binary_path} }
|
58
|
+
lines = output.split "\n"
|
59
|
+
_interpreter_line = lines.shift
|
60
|
+
|
61
|
+
lines.each do |line|
|
62
|
+
parse_ldd_line line
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@needed_libraries
|
67
|
+
end
|
68
|
+
|
69
|
+
# Used by {Bwrap::Args::Bind#libs_command_requires}.
|
70
|
+
#
|
71
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
72
|
+
def needed_libraries binary_paths
|
73
|
+
trace "Finding libraries #{binary_paths} requires"
|
74
|
+
@needed_libraries = []
|
75
|
+
|
76
|
+
# %i == interpreter, the library used to load the executable by kernel.
|
77
|
+
output_format = "%F::SEPARATOR::%n"
|
78
|
+
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} --ldcache --needed }
|
79
|
+
|
80
|
+
if binary_paths.is_a? String
|
81
|
+
binary_paths = [ binary_paths ]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Check if the exe is already resolved.
|
85
|
+
binary_paths.delete_if do |binary_path|
|
86
|
+
@@needed_libraries_cache.include? binary_path
|
87
|
+
end
|
88
|
+
|
89
|
+
return [] if binary_paths.empty?
|
90
|
+
|
91
|
+
data = execvalue(scanelf_command + binary_paths)
|
92
|
+
trace "scanelf found following libraries: #{data}"
|
93
|
+
|
94
|
+
lines = data.split "\n"
|
95
|
+
lines.each do |line|
|
96
|
+
parse_scanelf_line line
|
97
|
+
end
|
98
|
+
|
99
|
+
@needed_libraries
|
100
|
+
end
|
101
|
+
|
102
|
+
# Used by {#needed_libraries}.
|
103
|
+
private def parse_scanelf_line line
|
104
|
+
binary_path, libraries_line = line.split "::SEPARATOR::"
|
105
|
+
libraries = libraries_line.split ","
|
106
|
+
|
107
|
+
(@needed_libraries & libraries).each do |library|
|
108
|
+
verb "Binding #{library} as dependency of #{binary_path}"
|
109
|
+
end
|
110
|
+
|
111
|
+
@needed_libraries |= libraries
|
112
|
+
|
113
|
+
# Also check if requisite libraries needs some libraries.
|
114
|
+
inner = Bwrap::Args::Library.new
|
115
|
+
@needed_libraries |= inner.needed_libraries libraries
|
116
|
+
|
117
|
+
@@needed_libraries_cache |= libraries
|
118
|
+
end
|
119
|
+
|
120
|
+
# Used by {#musl_needed_libraries}.
|
121
|
+
private def parse_ldd_line line
|
122
|
+
line = line.strip
|
123
|
+
_library_name, library_data = line.split " => "
|
124
|
+
|
125
|
+
matches = library_data.match(/(.*) \(0x[0-9a-f]+\)/)
|
126
|
+
library_path = matches[1]
|
127
|
+
|
128
|
+
unless @needed_libraries.include? library_path
|
129
|
+
@needed_libraries << library_path
|
130
|
+
end
|
131
|
+
|
132
|
+
# Also check if requisite libraries needs some libraries.
|
133
|
+
inner = Bwrap::Args::Library.new
|
134
|
+
@needed_libraries |= inner.musl_needed_libraries library_path
|
135
|
+
end
|
136
|
+
end
|
137
|
+
# class Library ended
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "securerandom"
|
4
|
+
require "tempfile"
|
4
5
|
|
5
6
|
require "bwrap/output"
|
6
7
|
require_relative "args"
|
@@ -24,7 +25,7 @@ class Bwrap::Args::MachineId
|
|
24
25
|
# Returning [] means that execute() will ignore this fully.
|
25
26
|
# Nil would be converted to empty string, causing spawn() to pass it as argument, causing
|
26
27
|
# bwrap to misbehave.
|
27
|
-
return
|
28
|
+
return unless @config&.machine_id
|
28
29
|
|
29
30
|
machine_id = @config.machine_id
|
30
31
|
|
@@ -51,10 +52,10 @@ class Bwrap::Args::MachineId
|
|
51
52
|
debug "Using random machine id as /etc/machine-id"
|
52
53
|
|
53
54
|
@machine_id_file = Tempfile.new "bwrap-random_machine_id-", @config.tmpdir
|
54
|
-
@machine_id_file.write SecureRandom.uuid.
|
55
|
+
@machine_id_file.write SecureRandom.uuid.tr("-", "")
|
55
56
|
@machine_id_file.flush
|
56
57
|
|
57
|
-
%W{ --ro-bind-data #{machine_id_file.fileno} /etc/machine-id }
|
58
|
+
%W{ --ro-bind-data #{@machine_id_file.fileno} /etc/machine-id }
|
58
59
|
end
|
59
60
|
|
60
61
|
# Uses `10000000000000000000000000000000` as machine id.
|
@@ -79,6 +80,8 @@ class Bwrap::Args::MachineId
|
|
79
80
|
end
|
80
81
|
|
81
82
|
# Uses file inside sandbox directory as machine id.
|
83
|
+
#
|
84
|
+
# TODO: I kind of want to deprecate this one. It may make sense, but eh... Let’s see.
|
82
85
|
private def machine_id_inside_sandbox_dir sandbox_directory
|
83
86
|
machine_id_file = "#{sandbox_directory}/machine-id"
|
84
87
|
|
data/lib/bwrap/args/mount.rb
CHANGED
@@ -4,21 +4,30 @@ require_relative "args"
|
|
4
4
|
|
5
5
|
# Bind arguments for bwrap.
|
6
6
|
module Bwrap::Args::Mount
|
7
|
+
# Arguments for readwrite-binding {Config#root} as /.
|
8
|
+
private def root_mount
|
9
|
+
return unless @config.root
|
10
|
+
|
11
|
+
debug "Binding #{@config.root} as /"
|
12
|
+
@args.append %W{ --bind #{@config.root} / }
|
13
|
+
@args.append %w{ --chdir / }
|
14
|
+
end
|
15
|
+
|
7
16
|
# Arguments for mounting devtmpfs to /dev.
|
8
17
|
private def dev_mount
|
9
18
|
debug "Mounting new devtmpfs to /dev"
|
10
|
-
%w{ --dev /dev }
|
19
|
+
@args.append %w{ --dev /dev }
|
11
20
|
end
|
12
21
|
|
13
22
|
# Arguments for mounting procfs to /proc.
|
14
23
|
private def proc_mount
|
15
24
|
debug "Mounting new procfs to /proc"
|
16
|
-
%w{ --proc /proc }
|
25
|
+
@args.append %w{ --proc /proc }
|
17
26
|
end
|
18
27
|
|
19
28
|
# Arguments for mounting tmpfs to /tmp.
|
20
29
|
private def tmp_as_tmpfs
|
21
30
|
debug "Mounting tmpfs to /tmp"
|
22
|
-
%w{ --tmpfs /tmp }
|
31
|
+
@args.append %w{ --tmpfs /tmp }
|
23
32
|
end
|
24
33
|
end
|
data/lib/bwrap/bwrap.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#require "deep-cover" if ENV["DEEP_COVER"]
|
4
|
+
|
5
|
+
require_relative "bwrap_module"
|
6
|
+
require "bwrap/version"
|
7
|
+
require "bwrap/args/construct"
|
8
|
+
require "bwrap/config"
|
9
|
+
require "bwrap/execution"
|
10
|
+
|
11
|
+
# Executes given command under {https://github.com/containers/bubblewrap bwrap}
|
12
|
+
# using given configuration.
|
13
|
+
#
|
14
|
+
# @see ::Bwrap Bwrap module for usage example
|
15
|
+
class Bwrap::Bwrap
|
16
|
+
include Bwrap::Execution
|
17
|
+
|
18
|
+
# @param config [Bwrap::Config] Configuration used to tailor bwrap
|
19
|
+
def initialize config
|
20
|
+
# TODO: Ensure that costruct.rb and utilities it uses does not enforce Config to be valid object.
|
21
|
+
# Create a test for that also. Well, as long as that makes sense. If it doesn’t work, validate
|
22
|
+
# Config object to be valid here.
|
23
|
+
@config = config
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parses command line arguments given to caller script.
|
27
|
+
#
|
28
|
+
# @note This method automatically sets output levels according parsed
|
29
|
+
# options. It is also possible to set the levels manually using
|
30
|
+
# {Bwrap::Output.handle_output_options}, for example with flags
|
31
|
+
# parsed with optparse’s `OptionParser`, found in Ruby’s standard
|
32
|
+
# library.
|
33
|
+
#
|
34
|
+
# @warning Requires optimist gem to be installed, which is not a dependency of this gem.
|
35
|
+
def parse_command_line_arguments
|
36
|
+
options = parse_options
|
37
|
+
|
38
|
+
Bwrap::Output.handle_output_options options
|
39
|
+
end
|
40
|
+
|
41
|
+
# Binds and executes given command available on running system inside bwrap.
|
42
|
+
#
|
43
|
+
# If {Config#root} has been set, given executable is scanned for necessary
|
44
|
+
# libraries and they are bound inside sandbox. This often reduces amount of
|
45
|
+
# global binds, but some miscellaneous things may need custom handling.
|
46
|
+
#
|
47
|
+
# @see Config#features about binding bigger feature sets to sandbox.
|
48
|
+
#
|
49
|
+
# Executed command is constructed using configuration passed to constructor.
|
50
|
+
# After execution has completed, bwrap will also shut down.
|
51
|
+
#
|
52
|
+
# @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
|
53
|
+
# @see #run_inside_root to execute a command that already is inside sandbox.
|
54
|
+
def run command
|
55
|
+
construct = Bwrap::Args::Construct.new
|
56
|
+
construct.command = command
|
57
|
+
construct.config = @config
|
58
|
+
bwrap_args = construct.construct_bwrap_args
|
59
|
+
|
60
|
+
exec_command = [ "bwrap" ]
|
61
|
+
exec_command += bwrap_args
|
62
|
+
exec_command.append command
|
63
|
+
exec_command += @cli_args if @cli_args
|
64
|
+
|
65
|
+
execute exec_command
|
66
|
+
|
67
|
+
construct.cleanup
|
68
|
+
end
|
69
|
+
|
70
|
+
# Convenience method to executes a command that is inside bwrap.
|
71
|
+
#
|
72
|
+
# Given command is expected to already be inside {Config#root}.
|
73
|
+
#
|
74
|
+
# Calling this method is equivalent to setting {Config#command_inside_root} to `true`.
|
75
|
+
#
|
76
|
+
# @note This may have a bit unintuitive usage, as most things are checked anyway, so this is not
|
77
|
+
# akin to running something inside a chroot, but rather for convenience.
|
78
|
+
#
|
79
|
+
# @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
|
80
|
+
# @see #run to execute a command that needs to be bound to the sandbox.
|
81
|
+
def run_inside_root command
|
82
|
+
if @config
|
83
|
+
config = @config.dup
|
84
|
+
config.command_inside_root = true
|
85
|
+
else
|
86
|
+
config = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
construct = Bwrap::Args::Construct.new
|
90
|
+
construct.command = command
|
91
|
+
construct.config = config
|
92
|
+
bwrap_args = construct.construct_bwrap_args
|
93
|
+
|
94
|
+
exec_command = [ "bwrap" ]
|
95
|
+
exec_command += bwrap_args
|
96
|
+
exec_command.append command
|
97
|
+
exec_command += @cli_args if @cli_args
|
98
|
+
|
99
|
+
execute exec_command
|
100
|
+
|
101
|
+
construct.cleanup
|
102
|
+
end
|
103
|
+
|
104
|
+
# Parses global bwrap flags using Optimist.
|
105
|
+
#
|
106
|
+
# Sets instance variable `@cli_args`.
|
107
|
+
#
|
108
|
+
# @warning Requires optimist gem to be installed, which is not a dependency of this gem.
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
# @return [Hash] options parsed by `Optimist.options`
|
112
|
+
private def parse_options
|
113
|
+
begin
|
114
|
+
require "optimist"
|
115
|
+
rescue LoadError => e
|
116
|
+
puts "Failed to load optimist gem. In order to use Bwrap::Bwrap#parse_command_line_arguments, " \
|
117
|
+
"ensure optimist gem is present for example in your Gemfile."
|
118
|
+
puts
|
119
|
+
raise e
|
120
|
+
end
|
121
|
+
|
122
|
+
options = Optimist.options do
|
123
|
+
version ::Bwrap::VERSION
|
124
|
+
|
125
|
+
banner "Usage:"
|
126
|
+
banner " #{$PROGRAM_NAME} [global options]\n \n"
|
127
|
+
banner "Global options:"
|
128
|
+
opt :verbose,
|
129
|
+
"Show verbose output",
|
130
|
+
short: "v"
|
131
|
+
opt :debug,
|
132
|
+
"Show debug output (useful when debugging a problem)",
|
133
|
+
short: "d"
|
134
|
+
opt :trace,
|
135
|
+
"Show trace output (noisiest, probably not useful for most of time)",
|
136
|
+
short: :none
|
137
|
+
opt :version,
|
138
|
+
"Print version and exit",
|
139
|
+
short: "V"
|
140
|
+
opt :help,
|
141
|
+
"Show help message",
|
142
|
+
short: "h"
|
143
|
+
|
144
|
+
educate_on_error
|
145
|
+
end
|
146
|
+
|
147
|
+
@cli_args = ARGV.dup
|
148
|
+
|
149
|
+
options
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# ruby-bwrap provides easy-to-use interface to run complex programs in sandboxes created with
|
4
|
+
# {https://github.com/containers/bubblewrap bubblewrap}.
|
5
|
+
#
|
6
|
+
# To run a program inside bubblewrap, a wrapper executable can be created. For example:
|
7
|
+
#
|
8
|
+
# require "bwrap"
|
9
|
+
#
|
10
|
+
# config = Bwrap::Config.new
|
11
|
+
# config.user = "dummy_user"
|
12
|
+
# config.full_system_mounts = true
|
13
|
+
# config.binaries_from = %w{
|
14
|
+
# /bin
|
15
|
+
# /usr/bin
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
# bwrap = Bwrap::Bwrap.new config
|
19
|
+
# bwrap.parse_command_line_arguments
|
20
|
+
# bwrap.run "/bin/true"
|
21
|
+
#
|
22
|
+
# There also are few generic utilities, {Bwrap::Output} for handling output of scripts and
|
23
|
+
# {Bwrap::Execution} to run executables.
|
24
|
+
module Bwrap
|
25
|
+
# Empty module.
|
26
|
+
end
|