exec_sandbox 0.1.3 → 0.2.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.
- data/VERSION +1 -1
- data/exec_sandbox.gemspec +3 -2
- data/lib/exec_sandbox.rb +1 -0
- data/lib/exec_sandbox/sandbox.rb +12 -2
- data/lib/exec_sandbox/spawn.rb +25 -13
- data/spec/exec_sandbox/sandbox_spec.rb +47 -10
- data/spec/exec_sandbox/spawn_spec.rb +29 -0
- data/spec/fixtures/count.rb +12 -0
- metadata +20 -19
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/exec_sandbox.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "exec_sandbox"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Victor Costan"]
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
"spec/exec_sandbox/wait4_spec.rb",
|
39
39
|
"spec/fixtures/buffer.rb",
|
40
40
|
"spec/fixtures/churn.rb",
|
41
|
+
"spec/fixtures/count.rb",
|
41
42
|
"spec/fixtures/duplicate.rb",
|
42
43
|
"spec/fixtures/exit_arg.rb",
|
43
44
|
"spec/fixtures/fork.rb",
|
@@ -49,7 +50,7 @@ Gem::Specification.new do |s|
|
|
49
50
|
s.homepage = "http://github.com/pwnall/exec_sandbox"
|
50
51
|
s.licenses = ["MIT"]
|
51
52
|
s.require_paths = ["lib"]
|
52
|
-
s.rubygems_version = "1.8.
|
53
|
+
s.rubygems_version = "1.8.12"
|
53
54
|
s.summary = "Run foreign binaries using POSIX sandboxing features"
|
54
55
|
|
55
56
|
if s.respond_to? :specification_version then
|
data/lib/exec_sandbox.rb
CHANGED
data/lib/exec_sandbox/sandbox.rb
CHANGED
@@ -92,8 +92,11 @@ class Sandbox
|
|
92
92
|
# @option options [String] :out path to a file that is set as the child's
|
93
93
|
# stdout; if not set, the child will receive the write end of a pipe whose
|
94
94
|
# contents is returned in :out_data
|
95
|
+
# @option options [Symbol] :err :none closes the child's stderr, :out
|
96
|
+
# redirects the child's stderr to stdout; by default, the child's stderr
|
97
|
+
# is the same as the parent's
|
95
98
|
# @return [Hash] the result of {Wait4#wait4}, plus an :out_data key if no :out
|
96
|
-
# option is given
|
99
|
+
# option is given
|
97
100
|
def run(command, options = {})
|
98
101
|
limits = options[:limits] || {}
|
99
102
|
|
@@ -113,7 +116,14 @@ class Sandbox
|
|
113
116
|
out_rd, out_wr = IO.pipe
|
114
117
|
io[:out] = out_wr
|
115
118
|
end
|
116
|
-
|
119
|
+
case options[:err]
|
120
|
+
when :out
|
121
|
+
io[:err] = STDOUT
|
122
|
+
when :none
|
123
|
+
# Don't set io[:err], so the child's stderr will be closed.
|
124
|
+
else
|
125
|
+
io[:err] = STDERR
|
126
|
+
end
|
117
127
|
|
118
128
|
pid = ExecSandbox::Spawn.spawn command, io, @principal, limits
|
119
129
|
# Close the pipe ends that are meant to be used in the child.
|
data/lib/exec_sandbox/spawn.rb
CHANGED
@@ -28,32 +28,44 @@ module Spawn
|
|
28
28
|
# @param [Hash] io associates file descriptors with IO objects or file paths;
|
29
29
|
# all file descriptors not covered by io will be closed
|
30
30
|
def self.limit_io(io)
|
31
|
+
# Sort the list of redirections by file descriptor number.
|
32
|
+
redirects = []
|
31
33
|
[:in, :out, :err].each_with_index do |sym, fd_num|
|
32
|
-
if target = io
|
33
|
-
|
34
|
+
if target = io[sym]
|
35
|
+
redirects << [fd_num, redirects.length, target]
|
34
36
|
end
|
35
37
|
end
|
36
38
|
io.each do |k, v|
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
if k.kind_of? Integer
|
40
|
+
redirects << [k, redirects.length, v]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Perform the redirections.
|
45
|
+
redirects.sort!
|
46
|
+
redirects.each do |fd_num, _, target|
|
47
|
+
if target.respond_to?(:fileno)
|
48
|
+
# IO stream.
|
49
|
+
if target.fileno != fd_num
|
50
|
+
LibC.close fd_num
|
51
|
+
LibC.dup2 target.fileno, fd_num
|
41
52
|
end
|
42
53
|
else
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
54
|
+
# Filename string.
|
55
|
+
LibC.close fd_num
|
56
|
+
open_fd = IO.sysopen(target, 'r+')
|
57
|
+
if open_fd != fd_num
|
58
|
+
LibC.dup2 open_fd, fd_num
|
47
59
|
LibC.close open_fd
|
48
60
|
end
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
52
|
-
# Close all file descriptors.
|
64
|
+
# Close all file descriptors not in the redirection table.
|
65
|
+
redirected_fds = Set.new redirects.map(&:first)
|
53
66
|
max_fd = LibC.getdtablesize
|
54
67
|
0.upto(max_fd) do |fd|
|
55
|
-
|
56
|
-
LibC.close fd
|
68
|
+
LibC.close fd unless redirected_fds.include?(fd)
|
57
69
|
end
|
58
70
|
end
|
59
71
|
|
@@ -8,23 +8,44 @@ describe ExecSandbox::Sandbox do
|
|
8
8
|
@temp_in.close
|
9
9
|
@temp_out = Tempfile.new 'exec_sandbox_rspec'
|
10
10
|
@temp_out.close
|
11
|
-
|
12
|
-
ExecSandbox.use do |s|
|
13
|
-
@result = s.run bin_fixture(:duplicate), :in => @temp_in.path,
|
14
|
-
:out => @temp_out.path
|
15
|
-
end
|
16
11
|
end
|
17
12
|
after do
|
18
13
|
@temp_in.unlink
|
19
14
|
@temp_out.unlink
|
20
15
|
end
|
21
16
|
|
22
|
-
|
23
|
-
|
17
|
+
describe 'duplicate.rb' do
|
18
|
+
before do
|
19
|
+
ExecSandbox.use do |s|
|
20
|
+
@result = s.run bin_fixture(:duplicate), :in => @temp_in.path,
|
21
|
+
:out => @temp_out.path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should not crash' do
|
26
|
+
@result[:exit_code].should == 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should produce the correct result' do
|
30
|
+
File.read(@temp_out.path).should == "I/O test\nI/O test\n"
|
31
|
+
end
|
24
32
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
33
|
+
|
34
|
+
describe 'count.rb' do
|
35
|
+
before do
|
36
|
+
ExecSandbox.use do |s|
|
37
|
+
@result = s.run [bin_fixture(:count), '9'], :in => @temp_in.path,
|
38
|
+
:out => @temp_out.path, :err => :out
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not crash' do
|
43
|
+
@result[:exit_code].should == 0
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should produce the correct result' do
|
47
|
+
File.read(@temp_out.path).should == (1..9).map { |i| "#{i}\n" }.join('')
|
48
|
+
end
|
28
49
|
end
|
29
50
|
end
|
30
51
|
|
@@ -61,6 +82,22 @@ describe ExecSandbox::Sandbox do
|
|
61
82
|
@result[:out_data].should == "S" * buffer_size
|
62
83
|
end
|
63
84
|
end
|
85
|
+
|
86
|
+
describe 'count.rb' do
|
87
|
+
before do
|
88
|
+
ExecSandbox.use do |s|
|
89
|
+
@result = s.run [bin_fixture(:count), '9'], :err => :out
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should not crash' do
|
94
|
+
@result[:exit_code].should == 0
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should produce the correct result' do
|
98
|
+
@result[:out_data].should == (1..9).map { |i| "#{i}\n" }.join('')
|
99
|
+
end
|
100
|
+
end
|
64
101
|
end
|
65
102
|
|
66
103
|
|
@@ -69,6 +69,35 @@ describe ExecSandbox::Spawn do
|
|
69
69
|
@status[:exit_code].should_not == 0
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
shared_examples_for 'count.rb' do
|
74
|
+
it 'should not crash' do
|
75
|
+
@status[:exit_code].should == 0
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should write successfully' do
|
79
|
+
@temp_out.open
|
80
|
+
begin
|
81
|
+
@temp_out.read.should == (1..9).map { |i| "#{i}\n" }.join('')
|
82
|
+
ensure
|
83
|
+
@temp_out.close
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'with file descriptor and stderr redirected to stdout' do
|
89
|
+
before do
|
90
|
+
File.open(@temp_in.path, 'r') do |in_io|
|
91
|
+
File.open(@temp_out.path, 'w') do |out_io|
|
92
|
+
pid = ExecSandbox::Spawn.spawn [bin_fixture(:count), '9'],
|
93
|
+
{:in => in_io, :out => out_io, :err => STDOUT}
|
94
|
+
@status = ExecSandbox::Wait4.wait4 pid
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it_behaves_like 'count.rb'
|
100
|
+
end
|
72
101
|
end
|
73
102
|
|
74
103
|
describe '#spawn principal' do
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Counts from 1 to the first argument, and writes each number on a separate
|
4
|
+
# line. Odd numbers go to STDOUT, even numbers go to STDERR.
|
5
|
+
# on both STDOUT and STDERR.
|
6
|
+
|
7
|
+
limit = ARGV[0].to_i
|
8
|
+
1.upto(limit) do |i|
|
9
|
+
file = (i % 2 == 0) ? STDERR : STDOUT
|
10
|
+
file.write "#{i}\n"
|
11
|
+
file.flush
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exec_sandbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-12-20 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
16
|
-
requirement: &
|
16
|
+
requirement: &26627980 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.0.11
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *26627980
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rdoc
|
27
|
-
requirement: &
|
27
|
+
requirement: &26627380 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '3.10'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *26627380
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &26626760 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 2.6.0
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *26626760
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: yard
|
49
|
-
requirement: &
|
49
|
+
requirement: &26626260 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.7.2
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *26626260
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: yard-rspec
|
60
|
-
requirement: &
|
60
|
+
requirement: &26625740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0.1'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *26625740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: bundler
|
71
|
-
requirement: &
|
71
|
+
requirement: &26625220 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 1.0.21
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *26625220
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: jeweler
|
82
|
-
requirement: &
|
82
|
+
requirement: &26624740 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 1.6.4
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *26624740
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rcov
|
93
|
-
requirement: &
|
93
|
+
requirement: &26624240 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *26624240
|
102
102
|
description: Temporary users and groups, rlimits
|
103
103
|
email: costan@gmail.com
|
104
104
|
executables: []
|
@@ -128,6 +128,7 @@ files:
|
|
128
128
|
- spec/exec_sandbox/wait4_spec.rb
|
129
129
|
- spec/fixtures/buffer.rb
|
130
130
|
- spec/fixtures/churn.rb
|
131
|
+
- spec/fixtures/count.rb
|
131
132
|
- spec/fixtures/duplicate.rb
|
132
133
|
- spec/fixtures/exit_arg.rb
|
133
134
|
- spec/fixtures/fork.rb
|
@@ -150,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
151
|
version: '0'
|
151
152
|
segments:
|
152
153
|
- 0
|
153
|
-
hash: -
|
154
|
+
hash: -1397950588643828772
|
154
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
156
|
none: false
|
156
157
|
requirements:
|
@@ -159,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
160
|
version: '0'
|
160
161
|
requirements: []
|
161
162
|
rubyforge_project:
|
162
|
-
rubygems_version: 1.8.
|
163
|
+
rubygems_version: 1.8.12
|
163
164
|
signing_key:
|
164
165
|
specification_version: 3
|
165
166
|
summary: Run foreign binaries using POSIX sandboxing features
|