bwrap 1.0.0.pre.alpha3 → 1.0.0.pre.alpha4
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 +11 -0
- data/lib/bwrap/args/bind.rb +146 -25
- data/lib/bwrap/args/construct.rb +68 -35
- data/lib/bwrap/args/features.rb +55 -0
- data/lib/bwrap/args/library.rb +63 -0
- data/lib/bwrap/args/machine_id.rb +1 -1
- data/lib/bwrap/args/mount.rb +11 -3
- data/lib/bwrap/config.rb +108 -0
- data/lib/bwrap/version.rb +1 -1
- data/lib/bwrap.rb +11 -10
- data.tar.gz.sig +0 -0
- metadata +7 -4
- 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: 5101d7848dccd6da3f68fc02f08b37ec1cfadc516b45cb964265a3f0a60e8ea3
|
4
|
+
data.tar.gz: 6dbf98ccc5faba3385ce8fe6f9890f9e7369860531e4161c8092611c18a8ca02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 690e7e3f4911d80d5384aa10fc8c7dab6ed86c597dc691a66a396efccf15dc06e3ee29586afe687e4f92670eea049d2e76e034a2147eed9a9abcb9b894c99e67
|
7
|
+
data.tar.gz: d0a5312ab4ef5814885fd928f1359fd9ba69d7f36224c8671d79396ab635f1f8c23fd21a16712e62ca4b566cc51138b0f654e5cd8e3304f30cf10d492bbdc991
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
## 1.0.0-alpha4 (22.11.2021)
|
4
|
+
|
5
|
+
* Allow use without home directory set
|
6
|
+
* Bwrap#parse_command_line_arguments is no longer run when Bwrap is initialized
|
7
|
+
* Made pulseaudio optional
|
8
|
+
* Changed --share-net to be added only if requested
|
9
|
+
* Added Config#root= to specify path used as writable root
|
10
|
+
* Added Config#full_system_mounts to control whether library loaders are mounted inside chroot
|
11
|
+
* Added Config#libdir_mounts
|
12
|
+
* Added Config#features
|
13
|
+
|
3
14
|
## 1.0.0-alpha3 (14.11.2021)
|
4
15
|
|
5
16
|
* Avoid frozen string literal modification
|
data/lib/bwrap/args/bind.rb
CHANGED
@@ -1,32 +1,90 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bwrap/execution"
|
4
|
+
require "bwrap/output"
|
3
5
|
require_relative "args"
|
6
|
+
require_relative "library"
|
4
7
|
|
5
8
|
# Bind arguments for bwrap.
|
6
|
-
|
9
|
+
class Bwrap::Args::Bind
|
10
|
+
include Bwrap::Execution
|
11
|
+
include Bwrap::Output
|
12
|
+
|
13
|
+
# Array of parameters passed to bwrap.
|
14
|
+
attr_writer :args
|
15
|
+
|
16
|
+
# @see Bwrap::Args::Construct#command=
|
17
|
+
#
|
18
|
+
# @see (see Bwrap::Args::Construct#command=)
|
19
|
+
attr_writer :command
|
20
|
+
|
21
|
+
# Instance of {Config}.
|
22
|
+
attr_writer :config
|
23
|
+
|
24
|
+
# Instance of {Bwrap::Args::Environment}.
|
25
|
+
attr_writer :environment
|
26
|
+
|
27
|
+
# Inner class to clean up namespace for implementation specific reasons.
|
28
|
+
#
|
29
|
+
# @api internal
|
30
|
+
class Mime
|
31
|
+
include Bwrap::Execution
|
32
|
+
include Bwrap::Output
|
33
|
+
|
34
|
+
# Name given to {#initialize}.
|
35
|
+
attr_reader :executable_name
|
36
|
+
|
37
|
+
# Either path given to {#initialize} or one parsed from shebang.
|
38
|
+
attr_reader :executable_path
|
39
|
+
|
40
|
+
def initialize executable_name, executable_path
|
41
|
+
@executable_name = executable_name
|
42
|
+
@executable_path = executable_path
|
43
|
+
end
|
44
|
+
|
45
|
+
# Used by {Bwrap::Args::Bind#libs_command_requires}.
|
46
|
+
#
|
47
|
+
# @return false if caller should also return
|
48
|
+
def resolve_mime_type
|
49
|
+
mime_type = execvalue %W{ file --brief --mime-type #{@executable_path} }
|
50
|
+
return true unless mime_type[0..6] == "text/x-"
|
51
|
+
|
52
|
+
shebang = File.open @executable_path, &:readline
|
53
|
+
if shebang[0..1] != "#!"
|
54
|
+
warn "Executable #{@executable_name} was recognized as #{mime_type} but does not have " \
|
55
|
+
"proper shebang line. Skipping automatic library mounts."
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
shebang = shebang.delete_prefix("#!").strip
|
60
|
+
real_executable, _args = shebang.split " ", 2
|
61
|
+
@executable_path = real_executable
|
62
|
+
|
63
|
+
true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
7
67
|
# Arguments to bind /dev/dri from host to sandbox.
|
8
|
-
|
9
|
-
%w{ --dev-bind /dev/dri /dev/dri }
|
68
|
+
def bind_dev_dri
|
69
|
+
@args.append %w{ --dev-bind /dev/dri /dev/dri }
|
10
70
|
end
|
11
71
|
|
12
72
|
# Arguments to bind /sys/dev/char from host to sandbox.
|
13
|
-
|
14
|
-
%w{ --ro-bind /sys/dev/char /sys/dev/char }
|
73
|
+
def bind_sys_dev_char
|
74
|
+
@args.append %w{ --ro-bind /sys/dev/char /sys/dev/char }
|
15
75
|
end
|
16
76
|
|
17
77
|
# Arguments to bind /sys/devices/pci0000:00 from host to sandbox.
|
18
|
-
|
19
|
-
%w{ --ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 }
|
78
|
+
def bind_pci_devices
|
79
|
+
@args.append %w{ --ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 }
|
20
80
|
end
|
21
81
|
|
22
82
|
# Arguments to bind home directory from sandbox directory (`#{@config.sandbox_directory}/home`)
|
23
83
|
# as `/home/#{@config.user}`.
|
24
84
|
#
|
25
85
|
# @note Requires @config.user to be set.
|
26
|
-
|
27
|
-
unless @config.user
|
28
|
-
raise "Tried to bind user directory without user being set."
|
29
|
-
end
|
86
|
+
def bind_home_directory
|
87
|
+
return unless @config.user
|
30
88
|
|
31
89
|
home_directory = "#{@config.sandbox_directory}/home"
|
32
90
|
|
@@ -36,11 +94,12 @@ module Bwrap::Args::Bind
|
|
36
94
|
|
37
95
|
@environment["HOME"] = "/home/#{@config.user}"
|
38
96
|
|
39
|
-
|
97
|
+
debug "Using #{home_directory} as /home/#{@config.user}"
|
98
|
+
@args.append %W{ --bind #{home_directory} /home/#{@config.user} }
|
40
99
|
end
|
41
100
|
|
42
101
|
# Arguments to read-only bind whole system inside sandbox.
|
43
|
-
|
102
|
+
def full_system_mounts
|
44
103
|
bindir_mounts = []
|
45
104
|
binaries_from = @config.binaries_from
|
46
105
|
binaries_from.each do |path|
|
@@ -48,6 +107,38 @@ module Bwrap::Args::Bind
|
|
48
107
|
end
|
49
108
|
@environment["PATH"] = binaries_from.join(":")
|
50
109
|
|
110
|
+
@args.append bindir_mounts
|
111
|
+
|
112
|
+
if debug?
|
113
|
+
debug "Using following bindir mounts:\n" \
|
114
|
+
"#{bindir_mounts}\n" \
|
115
|
+
"(Odd is key, even is value)"
|
116
|
+
end
|
117
|
+
|
118
|
+
libdir_mounts
|
119
|
+
|
120
|
+
return unless @config.full_system_mounts
|
121
|
+
|
122
|
+
loader_binds
|
123
|
+
libs_command_requires
|
124
|
+
end
|
125
|
+
|
126
|
+
# These are something user can specify to do custom --ro-bind binds.
|
127
|
+
def custom_read_only_binds
|
128
|
+
return unless @config.ro_binds
|
129
|
+
|
130
|
+
binds = []
|
131
|
+
@config.ro_binds.each do |source_path, destination_path|
|
132
|
+
binds << "--ro-bind" << source_path.to_s << destination_path.to_s
|
133
|
+
end
|
134
|
+
|
135
|
+
@args.append binds
|
136
|
+
end
|
137
|
+
|
138
|
+
# Used by {#full_system_mounts}.
|
139
|
+
private def libdir_mounts
|
140
|
+
return unless @config.libdir_mounts
|
141
|
+
|
51
142
|
libdir_mounts = %w{
|
52
143
|
--ro-bind /lib /lib
|
53
144
|
--ro-bind /lib64 /lib64
|
@@ -55,24 +146,54 @@ module Bwrap::Args::Bind
|
|
55
146
|
--ro-bind /usr/lib64 /usr/lib64
|
56
147
|
}
|
57
148
|
|
58
|
-
system_mounts = bindir_mounts + libdir_mounts
|
59
149
|
if debug?
|
60
|
-
debug "Using following
|
61
|
-
"#{
|
150
|
+
debug "Using following libdir mounts:\n" \
|
151
|
+
"#{libdir_mounts}\n" \
|
62
152
|
"(Odd is key, even is value)"
|
63
153
|
end
|
64
|
-
|
154
|
+
|
155
|
+
@args.append libdir_mounts
|
65
156
|
end
|
66
157
|
|
67
|
-
#
|
68
|
-
private def
|
69
|
-
|
158
|
+
# Used by {#full_system_mounts}.
|
159
|
+
private def loader_binds
|
160
|
+
loader_mounts = []
|
161
|
+
path = "/lib64/ld-linux-x86-64.so.2"
|
162
|
+
loader_mounts << "--ro-bind" << path << path if File.exist? path
|
163
|
+
path = "/lib/ld-linux.so.2"
|
164
|
+
loader_mounts << "--ro-bind" << path << path if File.exist? path
|
70
165
|
|
71
|
-
|
72
|
-
|
73
|
-
|
166
|
+
@args.append loader_mounts
|
167
|
+
end
|
168
|
+
|
169
|
+
# Does some inspection to find out libraries given executable needs in order to work.
|
170
|
+
#
|
171
|
+
# Used by {#full_system_mounts}.
|
172
|
+
#
|
173
|
+
# @warning scanelf does not play with spaces in names well. This method assumes that libraries
|
174
|
+
# have no spaces in names, though binaries can have.
|
175
|
+
#
|
176
|
+
# @todo Ensure scanelf is available (and throw proper error if it is not, telling to not use full_system_mounts option.)
|
177
|
+
private def libs_command_requires
|
178
|
+
executable_name = @command.is_a?(String) && @command || @command[0]
|
179
|
+
executable_path = which executable_name
|
180
|
+
|
181
|
+
# TODO: Put this behind additional flag for extra control/sanity.
|
182
|
+
# Some executables are shell scripts and similar. For them we need to use the interpreter.
|
183
|
+
|
184
|
+
mime = Mime.new executable_name, executable_path
|
185
|
+
return unless mime.resolve_mime_type
|
186
|
+
|
187
|
+
# Then find out required libraries
|
188
|
+
|
189
|
+
library_mounts = []
|
190
|
+
|
191
|
+
library_object = Bwrap::Args::Library.new
|
192
|
+
library_object.needed_libraries(mime.executable_path).each do |library|
|
193
|
+
library_mounts << "--ro-bind" << library << library
|
74
194
|
end
|
75
195
|
|
76
|
-
|
196
|
+
@args.append library_mounts
|
77
197
|
end
|
78
|
-
|
198
|
+
|
199
|
+
end
|
data/lib/bwrap/args/construct.rb
CHANGED
@@ -5,46 +5,56 @@ require "tempfile"
|
|
5
5
|
require "bwrap/output"
|
6
6
|
require_relative "bind"
|
7
7
|
require_relative "environment"
|
8
|
+
require_relative "features"
|
8
9
|
require_relative "machine_id"
|
9
10
|
require_relative "mount"
|
10
11
|
|
11
12
|
# Constructs arguments for bwrap execution.
|
12
13
|
class Bwrap::Args::Construct
|
13
14
|
include Bwrap::Output
|
14
|
-
include Bwrap::Args::Bind
|
15
15
|
include Bwrap::Args::Mount
|
16
16
|
|
17
17
|
attr_writer :config
|
18
18
|
|
19
|
+
# Command that is executed inside bwrap sandbox.
|
20
|
+
#
|
21
|
+
# @note This is not used for anything vital, but some things, like
|
22
|
+
# setting {Config#full_system_mounts=} uses this to resolve some
|
23
|
+
# additional data.
|
24
|
+
#
|
25
|
+
# @param command [Array, String] Command with arguments
|
26
|
+
attr_writer :command
|
27
|
+
|
19
28
|
# Constructs arguments for bwrap execution.
|
20
29
|
def construct_bwrap_args
|
21
|
-
@
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
30
|
+
@args = []
|
31
|
+
create_objects
|
32
|
+
|
33
|
+
root_mount
|
34
|
+
xauthority_args
|
35
|
+
machine_id = @machine_id.machine_id
|
36
|
+
@args.append machine_id if machine_id
|
37
|
+
resolv_conf
|
38
|
+
@bind.full_system_mounts
|
39
|
+
@features.feature_binds
|
40
|
+
@bind.custom_read_only_binds
|
41
|
+
create_user_dir
|
42
|
+
read_only_pulseaudio
|
43
|
+
dev_mount
|
44
|
+
@bind.bind_dev_dri
|
45
|
+
@bind.bind_sys_dev_char
|
46
|
+
@bind.bind_pci_devices
|
47
|
+
proc_mount
|
48
|
+
tmp_as_tmpfs
|
49
|
+
@bind.bind_home_directory
|
50
|
+
@args.append "--unshare-all"
|
51
|
+
share_net
|
52
|
+
hostname
|
53
|
+
@args.append @environment.environment_variables
|
54
|
+
@args.append "--die-with-parent"
|
55
|
+
@args.append "--new-session"
|
56
|
+
|
57
|
+
@args.compact
|
48
58
|
end
|
49
59
|
|
50
60
|
# Performs cleanup operations after execution.
|
@@ -52,13 +62,32 @@ class Bwrap::Args::Construct
|
|
52
62
|
@machine_id&.cleanup
|
53
63
|
end
|
54
64
|
|
65
|
+
# Used by {#construct_bwrap_args}.
|
66
|
+
private def create_objects
|
67
|
+
@bind = Bwrap::Args::Bind.new
|
68
|
+
@bind.args = @args
|
69
|
+
@bind.command = @command
|
70
|
+
@bind.config = @config
|
71
|
+
|
72
|
+
@environment = Bwrap::Args::Environment.new
|
73
|
+
@environment.config = @config
|
74
|
+
@bind.environment = @environment
|
75
|
+
|
76
|
+
@features = Bwrap::Args::Features.new
|
77
|
+
@features.args = @args
|
78
|
+
@features.config = @config
|
79
|
+
|
80
|
+
@machine_id = Bwrap::Args::MachineId.new
|
81
|
+
@machine_id.config = @config
|
82
|
+
end
|
83
|
+
|
55
84
|
# Arguments for generating .Xauthority file.
|
56
85
|
private def xauthority_args
|
57
|
-
return
|
86
|
+
return unless @config.xorg_application
|
58
87
|
|
59
88
|
xauth_args = %W{ --ro-bind #{Dir.home}/.Xauthority #{Dir.home}/.Xauthority }
|
60
89
|
debug "Binding following .Xauthority file: #{Dir.home}/.Xauthority"
|
61
|
-
xauth_args
|
90
|
+
@args.append xauth_args
|
62
91
|
end
|
63
92
|
|
64
93
|
# Arguments to read-only bind /etc/resolv.conf.
|
@@ -68,25 +97,29 @@ class Bwrap::Args::Construct
|
|
68
97
|
source_resolv_conf = source_resolv_conf.realpath
|
69
98
|
|
70
99
|
debug "Binding #{source_resolv_conf} as /etc/resolv.conf"
|
71
|
-
%W{ --ro-bind #{source_resolv_conf} /etc/resolv.conf }
|
100
|
+
@args.append %W{ --ro-bind #{source_resolv_conf} /etc/resolv.conf }
|
72
101
|
end
|
73
102
|
|
74
103
|
# Arguments to create `/run/user/#{uid}`.
|
75
104
|
private def create_user_dir
|
76
105
|
trace "Creating directory /run/user/#{uid}"
|
77
|
-
%W{ --dir /run/user/#{uid} }
|
106
|
+
@args.append %W{ --dir /run/user/#{uid} }
|
78
107
|
end
|
79
108
|
|
80
109
|
# Arguments to bind necessary pulseaudio data for audio support.
|
81
110
|
private def read_only_pulseaudio
|
111
|
+
return unless @config.audio.include? :pulseaudio
|
112
|
+
|
82
113
|
debug "Binding pulseaudio"
|
83
|
-
%W{ --ro-bind /run/user/#{uid}/pulse /run/user/#{uid}/pulse }
|
114
|
+
@args.append %W{ --ro-bind /run/user/#{uid}/pulse /run/user/#{uid}/pulse }
|
84
115
|
end
|
85
116
|
|
86
117
|
# Arguments to allow network connection inside sandbox.
|
87
118
|
private def share_net
|
119
|
+
return unless @config.share_net
|
120
|
+
|
88
121
|
verb "Sharing network"
|
89
|
-
%w{ --share-net }
|
122
|
+
@args.append %w{ --share-net }
|
90
123
|
end
|
91
124
|
|
92
125
|
# Arguments to set hostname to whatever is configured.
|
@@ -94,7 +127,7 @@ class Bwrap::Args::Construct
|
|
94
127
|
return unless @config.hostname
|
95
128
|
|
96
129
|
debug "Setting hostname to #{@config.hostname}"
|
97
|
-
%W{ --hostname #{@config.hostname} }
|
130
|
+
@args.append %W{ --hostname #{@config.hostname} }
|
98
131
|
end
|
99
132
|
|
100
133
|
# Returns current user id.
|
@@ -0,0 +1,55 @@
|
|
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
|
+
# {Array} of parameters passed to bwrap.
|
14
|
+
attr_writer :args
|
15
|
+
|
16
|
+
# Instance of {Config}.
|
17
|
+
attr_writer :config
|
18
|
+
|
19
|
+
def feature_binds
|
20
|
+
ruby_binds
|
21
|
+
end
|
22
|
+
|
23
|
+
# @note This does not allow development headers needed for compilation for now. I’ll look at it after I have an use for it.
|
24
|
+
private def ruby_binds
|
25
|
+
return unless @config.features.ruby.enabled?
|
26
|
+
|
27
|
+
# Bind system paths so scripts works inside sandbox.
|
28
|
+
|
29
|
+
mounts = []
|
30
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["sitedir"] << RbConfig::CONFIG["sitedir"]
|
31
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["rubyhdrdir"] << RbConfig::CONFIG["rubyhdrdir"]
|
32
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["rubylibdir"] << RbConfig::CONFIG["rubylibdir"]
|
33
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["vendordir"] << RbConfig::CONFIG["vendordir"]
|
34
|
+
|
35
|
+
@args.append mounts
|
36
|
+
|
37
|
+
# Create binds for required system libraries.
|
38
|
+
#
|
39
|
+
# These are in path like /usr/lib64/ruby/2.5.0/x86_64-linux-gnu/,
|
40
|
+
# and as they are mostly shared libraries, they may have some extra
|
41
|
+
# dependencies that also need to be bound inside the sandbox.
|
42
|
+
|
43
|
+
library_mounts = []
|
44
|
+
library = Bwrap::Args::Library.new
|
45
|
+
@config.features.ruby.stdlib.each do |lib|
|
46
|
+
path = "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
|
47
|
+
|
48
|
+
library.needed_libraries(path).each do |library|
|
49
|
+
library_mounts << "--ro-bind" << library << library
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@args.append library_mounts
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
require "bwrap/execution"
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
|
6
|
+
# Class to clean up namespace for implementation specific reasons.
|
7
|
+
#
|
8
|
+
# @api internal
|
9
|
+
class Bwrap::Args::Library
|
10
|
+
include Bwrap::Execution
|
11
|
+
include Bwrap::Output
|
12
|
+
|
13
|
+
# Used by {Bwrap::Args::Bind#libs_command_requires}.
|
14
|
+
def needed_libraries binary_paths
|
15
|
+
trace "Finding libraries #{binary_paths} requires"
|
16
|
+
@needed_libraries = []
|
17
|
+
# NOTE: This caching can be made more efficient, but need to look at it later, what to do about it.
|
18
|
+
@@needed_libraries_cache ||= []
|
19
|
+
|
20
|
+
output_format = "%F:libraries:%n"
|
21
|
+
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} --ldcache --needed }
|
22
|
+
|
23
|
+
if binary_paths.is_a? String
|
24
|
+
binary_paths = [ binary_paths ]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Check if the exe is already resolved.
|
28
|
+
binary_paths.delete_if do |binary_path|
|
29
|
+
@@needed_libraries_cache.include? binary_path
|
30
|
+
end
|
31
|
+
|
32
|
+
return [] if binary_paths.empty?
|
33
|
+
|
34
|
+
data = execvalue(scanelf_command + binary_paths)
|
35
|
+
trace "scanelf found following libraries: #{data}"
|
36
|
+
|
37
|
+
lines = data.split "\n"
|
38
|
+
lines.each do |line|
|
39
|
+
parse_scanelf_line line
|
40
|
+
end
|
41
|
+
|
42
|
+
@needed_libraries
|
43
|
+
end
|
44
|
+
|
45
|
+
# Used by {#needed_libraries}.
|
46
|
+
private def parse_scanelf_line line
|
47
|
+
binary_path, libraries_line = line.split ":libraries:"
|
48
|
+
libraries = libraries_line.split ","
|
49
|
+
|
50
|
+
@needed_libraries += libraries
|
51
|
+
|
52
|
+
# Also check if requisite libraries needs some libraries.
|
53
|
+
inner = Bwrap::Args::Library.new
|
54
|
+
@needed_libraries += inner.needed_libraries libraries
|
55
|
+
|
56
|
+
# Mark library cached only after its dependencies have been also handled.
|
57
|
+
libraries.each do |library|
|
58
|
+
verb "Binding #{library} as dependency of #{binary_path}"
|
59
|
+
@@needed_libraries_cache << library
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
# class Library ended
|
@@ -24,7 +24,7 @@ class Bwrap::Args::MachineId
|
|
24
24
|
# Returning [] means that execute() will ignore this fully.
|
25
25
|
# Nil would be converted to empty string, causing spawn() to pass it as argument, causing
|
26
26
|
# bwrap to misbehave.
|
27
|
-
return
|
27
|
+
return unless @config.machine_id
|
28
28
|
|
29
29
|
machine_id = @config.machine_id
|
30
30
|
|
data/lib/bwrap/args/mount.rb
CHANGED
@@ -4,21 +4,29 @@ 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
|
+
end
|
14
|
+
|
7
15
|
# Arguments for mounting devtmpfs to /dev.
|
8
16
|
private def dev_mount
|
9
17
|
debug "Mounting new devtmpfs to /dev"
|
10
|
-
%w{ --dev /dev }
|
18
|
+
@args.append %w{ --dev /dev }
|
11
19
|
end
|
12
20
|
|
13
21
|
# Arguments for mounting procfs to /proc.
|
14
22
|
private def proc_mount
|
15
23
|
debug "Mounting new procfs to /proc"
|
16
|
-
%w{ --proc /proc }
|
24
|
+
@args.append %w{ --proc /proc }
|
17
25
|
end
|
18
26
|
|
19
27
|
# Arguments for mounting tmpfs to /tmp.
|
20
28
|
private def tmp_as_tmpfs
|
21
29
|
debug "Mounting tmpfs to /tmp"
|
22
|
-
%w{ --tmpfs /tmp }
|
30
|
+
@args.append %w{ --tmpfs /tmp }
|
23
31
|
end
|
24
32
|
end
|
data/lib/bwrap/config.rb
CHANGED
@@ -24,6 +24,9 @@ class Bwrap::Config
|
|
24
24
|
# Given file as bound as /etc/machine_id.
|
25
25
|
attr_accessor :machine_id
|
26
26
|
|
27
|
+
# Name of the user inside chroot.
|
28
|
+
#
|
29
|
+
# This is optional and defaults to no user.
|
27
30
|
attr_accessor :user
|
28
31
|
|
29
32
|
# Set to true to indicate we’re running a X.org application, meaning we need to do some extra holes,
|
@@ -32,11 +35,43 @@ class Bwrap::Config
|
|
32
35
|
# @return [Boolean] Whether Xorg specific binds are used.
|
33
36
|
attr_accessor :xorg_application
|
34
37
|
|
38
|
+
# Array of audio schemes usable inside chroot.
|
39
|
+
#
|
40
|
+
# Currently supports:
|
41
|
+
# - :pulseaudio
|
42
|
+
#
|
43
|
+
attr_accessor :audio
|
44
|
+
|
45
|
+
# @return [Boolean] true if network should be shared from host.
|
46
|
+
attr_accessor :share_net
|
47
|
+
|
48
|
+
# TODO: This should cause Bind#full_system_mounts to mount /lib64/ld-linux-x86-64.so.2 and so on,
|
49
|
+
# probably according executable type of specified command. But that needs some magic.
|
50
|
+
#
|
51
|
+
# For now this just mounts all relevant files it can find.
|
52
|
+
#
|
53
|
+
# @return [Boolean] true if Linux library loaders are mounted inside chroot
|
54
|
+
attr_accessor :full_system_mounts
|
55
|
+
|
56
|
+
# Set to true if basic system directories, like /usr/lib and /usr/lib64,
|
57
|
+
# should be bound inside chroot.
|
58
|
+
#
|
59
|
+
# /usr/bin can be mounted using {Config#binaries_from=}.
|
60
|
+
#
|
61
|
+
# @return [Boolean] true if libdirs are mounted to the chroot
|
62
|
+
attr_accessor :libdir_mounts
|
63
|
+
|
35
64
|
# Array of directories to be bind mounted and used to construct PATH environment variable.
|
36
65
|
attr_reader :binaries_from
|
37
66
|
|
67
|
+
# TODO: Document this.
|
68
|
+
# TODO: I wonder if this should just be removed. I don’t know, this is a bit ...
|
69
|
+
# Well, I can see it can have some merit, but very hard to say.
|
38
70
|
attr_reader :sandbox_directory
|
39
71
|
|
72
|
+
# Use given directory as root. End result is similar to classic chroot.
|
73
|
+
attr_reader :root
|
74
|
+
|
40
75
|
# `Hash`[`Pathname`] => `Pathname` containing custom read-only binds.
|
41
76
|
attr_reader :ro_binds
|
42
77
|
|
@@ -45,9 +80,62 @@ class Bwrap::Config
|
|
45
80
|
# Defaults to Dir.tmpdir.
|
46
81
|
attr_reader :tmpdir
|
47
82
|
|
83
|
+
# Methods to enable or disable feature sets to control various aspects of sandboxing.
|
84
|
+
class Features
|
85
|
+
# Defines Ruby feature set.
|
86
|
+
class Ruby
|
87
|
+
# @return [Array] list of needed libraries.
|
88
|
+
attr_reader :stdlib
|
89
|
+
|
90
|
+
def initialize
|
91
|
+
@stdlib = []
|
92
|
+
end
|
93
|
+
|
94
|
+
# @see enabled=
|
95
|
+
def enabled?
|
96
|
+
@enabled
|
97
|
+
end
|
98
|
+
|
99
|
+
# Enable Ruby feature set.
|
100
|
+
#
|
101
|
+
# Among others, binds RbConfig::CONFIG["sitedir"] so scripts works.
|
102
|
+
#
|
103
|
+
# @note This does not allow development headers needed for compilation for now. I’ll look at it after I have an use for it.
|
104
|
+
def enable
|
105
|
+
@enabled = true
|
106
|
+
end
|
107
|
+
|
108
|
+
# Disable Ruby feature set.
|
109
|
+
def disable
|
110
|
+
@enabled = false
|
111
|
+
end
|
112
|
+
|
113
|
+
# Extra libraries to be loaded from `RbConfig::CONFIG["rubyarchdir"]`.
|
114
|
+
#
|
115
|
+
# @note This is only required to be called if extra dependencies are necessary.
|
116
|
+
# For example, psych.so requires libyaml.so.
|
117
|
+
def stdlib= libs
|
118
|
+
# Just a little check to have error earlier.
|
119
|
+
libs.each do |lib|
|
120
|
+
unless File.exist? "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
|
121
|
+
raise "Library “#{lib}” passed to Bwrap::Config::Ruby.stdlib= does not exist."
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
@stdlib = libs
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# @return [Ruby] Instance of feature class for Ruby
|
130
|
+
def ruby
|
131
|
+
@ruby ||= Ruby.new
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
48
135
|
def initialize
|
49
136
|
@binaries_from = []
|
50
137
|
@tmpdir = Dir.tmpdir
|
138
|
+
@audio = []
|
51
139
|
end
|
52
140
|
|
53
141
|
def binaries_from= array
|
@@ -61,6 +149,17 @@ class Bwrap::Config
|
|
61
149
|
end
|
62
150
|
end
|
63
151
|
|
152
|
+
# Enable or disable feature sets to control various aspects of sandboxing.
|
153
|
+
#
|
154
|
+
# @example To enable Ruby feature set
|
155
|
+
# @config.features.ruby = true
|
156
|
+
#
|
157
|
+
# @see {Features} List of available features
|
158
|
+
# @return [Features] Object used to toggle features
|
159
|
+
def features
|
160
|
+
@features ||= ::Bwrap::Config::Features.new
|
161
|
+
end
|
162
|
+
|
64
163
|
def sandbox_directory= directory
|
65
164
|
unless Dir.exist? directory
|
66
165
|
raise "Given sandbox directory #{directory} does not exist. Please create it beforehand and setup to your needs."
|
@@ -69,6 +168,15 @@ class Bwrap::Config
|
|
69
168
|
@sandbox_directory = directory
|
70
169
|
end
|
71
170
|
|
171
|
+
# Directory used as writable root, akin to classic chroot.
|
172
|
+
def root= directory
|
173
|
+
unless Dir.exist? directory
|
174
|
+
raise "Given root directory #{directory} does not exist. Please create it beforehand and set up to your needs."
|
175
|
+
end
|
176
|
+
|
177
|
+
@root = directory
|
178
|
+
end
|
179
|
+
|
72
180
|
# Set given hash of paths to be bound with --ro-bind.
|
73
181
|
#
|
74
182
|
# Key is source path, value is destination path.
|
data/lib/bwrap/version.rb
CHANGED
data/lib/bwrap.rb
CHANGED
@@ -15,8 +15,13 @@ class Bwrap::Bwrap
|
|
15
15
|
|
16
16
|
def initialize config
|
17
17
|
@config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
# Parses command line arguments given to caller script.
|
21
|
+
def parse_command_line_arguments
|
22
|
+
options = optimist_cli_args
|
18
23
|
|
19
|
-
|
24
|
+
Bwrap::Output.handle_output_options options
|
20
25
|
end
|
21
26
|
|
22
27
|
# Runs given command inside bwrap.
|
@@ -24,26 +29,20 @@ class Bwrap::Bwrap
|
|
24
29
|
# @param command [String, Array] Command, with necessary arguments, to be executed inside bwrap
|
25
30
|
def run command
|
26
31
|
construct = Bwrap::Args::Construct.new
|
32
|
+
construct.command = command
|
27
33
|
construct.config = @config
|
28
34
|
bwrap_args = construct.construct_bwrap_args
|
29
35
|
|
30
36
|
exec_command = [ "bwrap" ]
|
31
37
|
exec_command += bwrap_args
|
32
|
-
exec_command
|
33
|
-
exec_command +=
|
38
|
+
exec_command.append command
|
39
|
+
exec_command += @cli_args if @cli_args
|
34
40
|
|
35
41
|
execute exec_command
|
36
42
|
|
37
43
|
construct.cleanup
|
38
44
|
end
|
39
45
|
|
40
|
-
# Parses command line arguments given to caller script.
|
41
|
-
private def parse_command_line_arguments
|
42
|
-
options = optimist_cli_args
|
43
|
-
|
44
|
-
Bwrap::Output.handle_output_options options
|
45
|
-
end
|
46
|
-
|
47
46
|
# Parses global bwrap flags using Optimist.
|
48
47
|
private def optimist_cli_args
|
49
48
|
Optimist.options do
|
@@ -70,5 +69,7 @@ class Bwrap::Bwrap
|
|
70
69
|
|
71
70
|
educate_on_error
|
72
71
|
end
|
72
|
+
|
73
|
+
@cli_args = ARGV.dup
|
73
74
|
end
|
74
75
|
end
|
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.0.0.pre.
|
4
|
+
version: 1.0.0.pre.alpha4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samu Voutilainen
|
@@ -34,7 +34,7 @@ cert_chain:
|
|
34
34
|
X4ioQwEn1/9tHs19VO1CLF58451HgEo1BXd7eWLmV1V5cqw0YWok1ly4L/Su/Phf
|
35
35
|
MRxVMHiVAqY=
|
36
36
|
-----END CERTIFICATE-----
|
37
|
-
date: 2021-11-
|
37
|
+
date: 2021-11-22 00:00:00.000000000 Z
|
38
38
|
dependencies:
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: optimist
|
@@ -120,7 +120,8 @@ dependencies:
|
|
120
120
|
- - "~>"
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '3.7'
|
123
|
-
description: For now this
|
123
|
+
description: For now this is tailored to my needs, so this may or may not be of any
|
124
|
+
use.
|
124
125
|
email:
|
125
126
|
- smar@smar.fi
|
126
127
|
executables: []
|
@@ -135,6 +136,8 @@ files:
|
|
135
136
|
- lib/bwrap/args/bind.rb
|
136
137
|
- lib/bwrap/args/construct.rb
|
137
138
|
- lib/bwrap/args/environment.rb
|
139
|
+
- lib/bwrap/args/features.rb
|
140
|
+
- lib/bwrap/args/library.rb
|
138
141
|
- lib/bwrap/args/machine_id.rb
|
139
142
|
- lib/bwrap/args/mount.rb
|
140
143
|
- lib/bwrap/config.rb
|
@@ -174,5 +177,5 @@ rubyforge_project:
|
|
174
177
|
rubygems_version: 2.7.6.3
|
175
178
|
signing_key:
|
176
179
|
specification_version: 4
|
177
|
-
summary:
|
180
|
+
summary: Framework to create commands for bwrap
|
178
181
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|