exec_sandbox 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source :rubygems
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  # gem 'activesupport', '>= 2.3.5'
5
- gem 'ffi', '>= 1.0.9'
5
+ gem 'ffi', '>= 1.0.11'
6
6
 
7
7
  # Add dependencies to develop your gem here.
8
8
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -2,26 +2,26 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  diff-lcs (1.1.3)
5
- ffi (1.0.9)
5
+ ffi (1.0.11)
6
6
  git (1.2.5)
7
7
  jeweler (1.6.4)
8
8
  bundler (~> 1.0)
9
9
  git (>= 1.2.5)
10
10
  rake
11
- json (1.6.1)
12
- rake (0.9.2)
11
+ json (1.6.3)
12
+ rake (0.9.2.2)
13
13
  rcov (0.9.11)
14
- rdoc (3.10)
14
+ rdoc (3.12)
15
15
  json (~> 1.4)
16
- rspec (2.6.0)
17
- rspec-core (~> 2.6.0)
18
- rspec-expectations (~> 2.6.0)
19
- rspec-mocks (~> 2.6.0)
20
- rspec-core (2.6.4)
21
- rspec-expectations (2.6.0)
16
+ rspec (2.7.0)
17
+ rspec-core (~> 2.7.0)
18
+ rspec-expectations (~> 2.7.0)
19
+ rspec-mocks (~> 2.7.0)
20
+ rspec-core (2.7.1)
21
+ rspec-expectations (2.7.0)
22
22
  diff-lcs (~> 1.1.2)
23
- rspec-mocks (2.6.0)
24
- yard (0.7.2)
23
+ rspec-mocks (2.7.0)
24
+ yard (0.7.4)
25
25
  yard-rspec (0.1)
26
26
  yard
27
27
 
@@ -30,7 +30,7 @@ PLATFORMS
30
30
 
31
31
  DEPENDENCIES
32
32
  bundler (>= 1.0.21)
33
- ffi (>= 1.0.9)
33
+ ffi (>= 1.0.11)
34
34
  jeweler (>= 1.6.4)
35
35
  rcov
36
36
  rdoc (>= 3.10)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
data/exec_sandbox.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "exec_sandbox"
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
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"]
12
- s.date = "2011-10-13"
12
+ s.date = "2011-12-20"
13
13
  s.description = "Temporary users and groups, rlimits"
14
14
  s.email = "costan@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -56,7 +56,7 @@ Gem::Specification.new do |s|
56
56
  s.specification_version = 3
57
57
 
58
58
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
59
- s.add_runtime_dependency(%q<ffi>, [">= 1.0.9"])
59
+ s.add_runtime_dependency(%q<ffi>, [">= 1.0.11"])
60
60
  s.add_development_dependency(%q<rdoc>, [">= 3.10"])
61
61
  s.add_development_dependency(%q<rspec>, [">= 2.6.0"])
62
62
  s.add_development_dependency(%q<yard>, [">= 0.7.2"])
@@ -65,7 +65,7 @@ Gem::Specification.new do |s|
65
65
  s.add_development_dependency(%q<jeweler>, [">= 1.6.4"])
66
66
  s.add_development_dependency(%q<rcov>, [">= 0"])
67
67
  else
68
- s.add_dependency(%q<ffi>, [">= 1.0.9"])
68
+ s.add_dependency(%q<ffi>, [">= 1.0.11"])
69
69
  s.add_dependency(%q<rdoc>, [">= 3.10"])
70
70
  s.add_dependency(%q<rspec>, [">= 2.6.0"])
71
71
  s.add_dependency(%q<yard>, [">= 0.7.2"])
@@ -75,7 +75,7 @@ Gem::Specification.new do |s|
75
75
  s.add_dependency(%q<rcov>, [">= 0"])
76
76
  end
77
77
  else
78
- s.add_dependency(%q<ffi>, [">= 1.0.9"])
78
+ s.add_dependency(%q<ffi>, [">= 1.0.11"])
79
79
  s.add_dependency(%q<rdoc>, [">= 3.10"])
80
80
  s.add_dependency(%q<rspec>, [">= 2.6.0"])
81
81
  s.add_dependency(%q<yard>, [">= 0.7.2"])
@@ -6,6 +6,9 @@ class Sandbox
6
6
  # The path to the sandbox's working directory.
7
7
  attr_reader :path
8
8
 
9
+ # The un-privileged user that execs sandboxed binaries.
10
+ attr_reader :user_name
11
+
9
12
  # Empty sandbox.
10
13
  #
11
14
  # @param [String] admin the name of a user who will be able to peek into the
@@ -142,6 +145,17 @@ class Sandbox
142
145
  def finalize
143
146
  close
144
147
  end
148
+
149
+ # Removes temporary users created by old sandboxes.
150
+ #
151
+ # Sandboxes usually clean up after themselves. For the rare circumstances
152
+ # where that doesn't happen (VM crash, Ctrl+C, SIGKILL), this method finds and
153
+ # cleans up the temporary users created for sandboxing.
154
+ #
155
+ # @return [Array<String>] the names of the deleted users
156
+ def self.cleanup
157
+ Users.destroy_temps
158
+ end
145
159
  end # module ExecSandbox::Sandbox
146
160
 
147
161
  # Creates a sandbox, yields it, and destroys it.
@@ -8,6 +8,8 @@ module ExecSandbox
8
8
  module Users
9
9
  # Creates an unprivileged user.
10
10
  #
11
+ # @param [String] prefix used at the beginning of temporary user names to
12
+ # help identify the application that created the users
11
13
  # @return [String] the user's name
12
14
  def self.temp(prefix = 'xsbx.rb')
13
15
  loop do
@@ -81,10 +83,12 @@ module Users
81
83
 
82
84
  else # Linux
83
85
  if group_id
84
- command = ['useradd', '--gid', group_id.to_s,
85
- '--no-create-home', '--no-user-group', user_name]
86
+ command = ['useradd', '--gid', group_id.to_s, '--no-user-group',
87
+ '--no-create-home', '--system',
88
+ '--comment', 'exec_sandbox.rb temporary user', user_name]
86
89
  else
87
- command = ['useradd', '--no-create-home', user_name]
90
+ command = ['useradd', '--user-group', '--no-create-home', '--system',
91
+ '--comment', 'exec_sandbox.rb temporary user', user_name]
88
92
  end
89
93
  unless Kernel.system(*command)
90
94
  raise RuntimeError, "User creation failed at #{command.inspect}!"
@@ -151,6 +155,29 @@ module Users
151
155
  end
152
156
  end # RUBY_PLATFORM
153
157
  end
158
+
159
+ # Finds users whose names match a String or Regexp pattern.
160
+ #
161
+ # @param [String] pattern matched against user names using ===
162
+ # @return [Array<String>] names of users
163
+ def self.named(pattern)
164
+ users = []
165
+ Etc.passwd do |user|
166
+ users << user.name if pattern === user.name
167
+ end
168
+ users
169
+ end
170
+
171
+ # Destroys users created by temp.
172
+ #
173
+ # @param [String] prefix match the prefix given to temp
174
+ # @return [Array<String>] names of users that were deleted
175
+ def self.destroy_temps(prefix = 'xsbx.rb')
176
+ # Matches the names created by temp.
177
+ pattern = /^#{prefix}\-[0-9a-f]+\.[0-9a-f]+\.[0-9a-f]+$/
178
+ # Each returns the collection that it iterates over.
179
+ self.named(pattern).each { |name| destroy name }
180
+ end
154
181
  end # module ExecSandbox::Users
155
182
 
156
183
  end # namespace ExecSandbox
@@ -154,4 +154,24 @@ describe ExecSandbox::Sandbox do
154
154
  end
155
155
  end
156
156
  end
157
+
158
+ describe '#cleanup' do
159
+ describe 'in a system with an open sandbox' do
160
+ before do
161
+ @all_users = ExecSandbox::Users.named(/.*/).sort
162
+
163
+ @sandbox = ExecSandbox.open
164
+ @removed = ExecSandbox::Sandbox.cleanup
165
+ end
166
+
167
+ it 'should not remove the sandbox user' do
168
+ ExecSandbox::Users.named(/.*/).sort.should == @all_users
169
+ end
170
+
171
+ it 'should return an array with the sandbox user' do
172
+ @removed.should == [@sandbox.user_name]
173
+ end
174
+ end
175
+
176
+ end
157
177
  end
@@ -3,6 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
3
  describe ExecSandbox::Users do
4
4
  let(:test_user) { 'exec_sandbox_rspec' }
5
5
  let(:test_group) { Etc.getgrgid(Etc.getpwnam(Etc.getlogin).gid).name }
6
+ let(:current_user) { Etc.getlogin }
6
7
 
7
8
  describe '#temp' do
8
9
  before { @user_name = ExecSandbox::Users.temp 'exsbx.rspec' }
@@ -122,4 +123,76 @@ describe ExecSandbox::Users do
122
123
  end
123
124
  end
124
125
  end
126
+
127
+ describe '#named' do
128
+ describe 'with non-matching RegExp' do
129
+ it 'should not return any user' do
130
+ ExecSandbox::Users.named(/exec_sandbox_rspec/).should be_empty
131
+ end
132
+ end
133
+
134
+ describe 'with non-matching String' do
135
+ it 'should not return any user' do
136
+ ExecSandbox::Users.named(/exec_sandbox_rspec/).should be_empty
137
+ end
138
+ end
139
+
140
+ describe 'with the name of the current user' do
141
+ it 'should return the current user' do
142
+ ExecSandbox::Users.named(current_user).should == [current_user]
143
+ end
144
+ end
145
+
146
+ describe 'with RegExp matching one user' do
147
+ before do
148
+ ExecSandbox::Users.create test_user, test_group
149
+ end
150
+ after do
151
+ ExecSandbox::Users.destroy test_user
152
+ end
153
+ it 'should return that one user' do
154
+ ExecSandbox::Users.named(/exec.sandbox.rspe/).should ==
155
+ ['exec_sandbox_rspec']
156
+ end
157
+ end
158
+ end
159
+
160
+ describe '#destroy_temps' do
161
+ let(:temp_prefix) { 'exsbx.rspec' }
162
+
163
+ before do
164
+ @all_users = ExecSandbox::Users.named(/.*/).sort
165
+ end
166
+
167
+ describe 'in a system with no temps' do
168
+ before do
169
+ @removed = ExecSandbox::Users.destroy_temps temp_prefix
170
+ end
171
+
172
+ it 'should not remove any users' do
173
+ ExecSandbox::Users.named(/.*/).sort.should == @all_users
174
+ end
175
+
176
+ it 'should return an empty array' do
177
+ @removed.should be_empty
178
+ end
179
+ end
180
+
181
+ describe 'in a system with two temps' do
182
+ before do
183
+ @temp1 = ExecSandbox::Users.temp temp_prefix
184
+ @temp2 = ExecSandbox::Users.temp temp_prefix
185
+
186
+ @removed = ExecSandbox::Users.destroy_temps temp_prefix
187
+ end
188
+
189
+ it 'should only remove the two temps' do
190
+ ExecSandbox::Users.named(/.*/).sort.should == @all_users
191
+ end
192
+
193
+ it 'should return the two temps' do
194
+ @removed.sort.should == [@temp1, @temp2].sort
195
+ end
196
+ end
197
+ end
125
198
  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.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-13 00:00:00.000000000Z
12
+ date: 2011-12-20 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
16
- requirement: &24549880 !ruby/object:Gem::Requirement
16
+ requirement: &15824600 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.9
21
+ version: 1.0.11
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *24549880
24
+ version_requirements: *15824600
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rdoc
27
- requirement: &24549360 !ruby/object:Gem::Requirement
27
+ requirement: &15824120 !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: *24549360
35
+ version_requirements: *15824120
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &24548820 !ruby/object:Gem::Requirement
38
+ requirement: &15823640 !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: *24548820
46
+ version_requirements: *15823640
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: yard
49
- requirement: &24548320 !ruby/object:Gem::Requirement
49
+ requirement: &15823160 !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: *24548320
57
+ version_requirements: *15823160
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: yard-rspec
60
- requirement: &24547800 !ruby/object:Gem::Requirement
60
+ requirement: &15822680 !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: *24547800
68
+ version_requirements: *15822680
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
- requirement: &24547220 !ruby/object:Gem::Requirement
71
+ requirement: &15822200 !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: *24547220
79
+ version_requirements: *15822200
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: jeweler
82
- requirement: &24546700 !ruby/object:Gem::Requirement
82
+ requirement: &15821720 !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: *24546700
90
+ version_requirements: *15821720
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rcov
93
- requirement: &24546160 !ruby/object:Gem::Requirement
93
+ requirement: &15821240 !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: *24546160
101
+ version_requirements: *15821240
102
102
  description: Temporary users and groups, rlimits
103
103
  email: costan@gmail.com
104
104
  executables: []
@@ -150,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
150
150
  version: '0'
151
151
  segments:
152
152
  - 0
153
- hash: -4313873554503945480
153
+ hash: -3240483873242314683
154
154
  required_rubygems_version: !ruby/object:Gem::Requirement
155
155
  none: false
156
156
  requirements: