pledge 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +4 -0
- data/README.rdoc +73 -12
- data/Rakefile +1 -7
- data/ext/pledge/extconf.rb +3 -1
- data/ext/pledge/pledge.c +38 -0
- data/lib/unveil.rb +64 -0
- data/spec/pledge_spec.rb +81 -5
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 949027d706330a2286744e8230a2bf32dcc70eb96bc92d96ea3ecfcc4cc9c79f
|
4
|
+
data.tar.gz: 746d5466733720404a1ed65c53d635f67f90d7c187e8e77b30148bec9fe71e58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75456b41d7c3c77633ce3395cf9c55f5a3d3812ba99cbdeb7ef3a4ff3ef4c9fac4f7e83ecf7ab8501e54b07189b3a9aa53d16c589932f14c40b52e5fa0a3a733
|
7
|
+
data.tar.gz: a75f472530864f085cfd0aa427abd18a871708b1916b2d0f1fabed31a5164a73a695769884e10ab045ef6f1d28333a6bb75ed6081b092f0de92e9b7a1fba8af5
|
data/CHANGELOG
CHANGED
data/README.rdoc
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
= pledge
|
2
2
|
|
3
|
-
pledge exposes OpenBSD's pledge(2)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
pledge exposes OpenBSD's pledge(2) and unveil(2) system
|
4
|
+
calls to ruby. pledge(2) allows a program to restrict the
|
5
|
+
types of operations the program can do, and unveil(2)
|
6
|
+
restricts access to the file system.
|
7
|
+
|
8
|
+
Unlike other similar systems, pledge and unveil are
|
9
|
+
designed for programs that need to use a wide variety of
|
10
|
+
operations and file access on initialization, but
|
8
11
|
a fewer number after initialization (when user input will
|
9
12
|
be accepted).
|
10
13
|
|
11
|
-
|
12
|
-
argument for execpromises on OpenBSD 6.3+.
|
13
|
-
|
14
|
-
== Usage
|
14
|
+
== pledge
|
15
15
|
|
16
16
|
First, you need to require the library
|
17
17
|
|
@@ -53,8 +53,6 @@ in other classes:
|
|
53
53
|
Object.send(:include, Pledge)
|
54
54
|
pledge("rpath")
|
55
55
|
|
56
|
-
== Options
|
57
|
-
|
58
56
|
See the pledge(2) man page for a description of the allowed
|
59
57
|
promises in the strings passed to +Pledge.pledge+.
|
60
58
|
|
@@ -63,6 +61,69 @@ promise is added automatically to the current process's promises,
|
|
63
61
|
as ruby does not function without it, but it is not added to
|
64
62
|
the execpromises (as you can execute non-ruby programs).
|
65
63
|
|
64
|
+
== unveil
|
65
|
+
|
66
|
+
First, you need to require the library
|
67
|
+
|
68
|
+
require 'unveil'
|
69
|
+
|
70
|
+
Then you can use +Pledge.unveil+ as the interface to the unveil(2)
|
71
|
+
system call. You pass +Pledge.unveil+ a hash of paths and permissions,
|
72
|
+
for those paths, and it calls unveil(2) with the path and permissions
|
73
|
+
for each entry.
|
74
|
+
|
75
|
+
The permissions should be a string with the following characters:
|
76
|
+
|
77
|
+
r :: Allow read access to existing files and directories
|
78
|
+
w :: Allow write access to existing files and directories
|
79
|
+
x :: Allow execute access to programs
|
80
|
+
c :: Allow create access for new files and directories
|
81
|
+
|
82
|
+
You can use the empty string as permissions if you want to allow no access
|
83
|
+
to the given path, even if you have granted some access to a folder above
|
84
|
+
the given folder. You can use a value of +:gem+ to allow read access to
|
85
|
+
the directory for the gem specified by the key.
|
86
|
+
|
87
|
+
+Pledge.unveil+ locks the file system access to the specified paths. If
|
88
|
+
you want to specify which paths to allow in multiple places in your
|
89
|
+
program, use +Pledge.unveil_without_lock+ for the initial calls and
|
90
|
+
+Pledge.unveil+ for the final call.
|
91
|
+
|
92
|
+
If +Pledge.unveil+ is called with an empty hash, it adds an unveil of +/+
|
93
|
+
with no permissions, which denies all access to the file system if
|
94
|
+
+unveil_without_lock+ was not called previously with paths.
|
95
|
+
|
96
|
+
Example:
|
97
|
+
|
98
|
+
Pledge.unveil(
|
99
|
+
'/home/foo/bar' => 'r',
|
100
|
+
'/home/foo/bar/data' => 'rwc',
|
101
|
+
'/bin' => 'x',
|
102
|
+
'/home/foo/bar/secret' => '',
|
103
|
+
'rack' => :gem
|
104
|
+
)
|
105
|
+
|
106
|
+
The value of :gem is mostly mostly needed if the gem uses autoload or
|
107
|
+
other forms of runtime requires. This allows read access to
|
108
|
+
all files in the gem's folder, not just the gem's require paths,
|
109
|
+
so it works correctly for gems that access data (e.g. templates)
|
110
|
+
outside of the gem's require paths.
|
111
|
+
|
112
|
+
If you plan to use pledge and unveil together, you should
|
113
|
+
unveil before pledging, unless you use the +unveil+
|
114
|
+
promise when pledging.
|
115
|
+
|
116
|
+
=== Issues with unveil and File.realpath
|
117
|
+
|
118
|
+
+Pledge.unveil+ does not work with +File.realpath+ on Ruby <2.7.
|
119
|
+
The Ruby ports officially supported by OpenBSD have had support to
|
120
|
+
allow them to work together backported, as long as you are running
|
121
|
+
OpenBSD 6.6+ (or 6.5-current after July 2019). As +require+ uses
|
122
|
+
+File.realpath+, this means in most cases where you would want to
|
123
|
+
use the +:gem+ support, it will not actually work correctly unless
|
124
|
+
you are using Ruby 2.7+ or an OpenBSD package with the backported
|
125
|
+
support.
|
126
|
+
|
66
127
|
== Reporting issues/bugs
|
67
128
|
|
68
129
|
This library uses GitHub Issues for tracking issues/bugs:
|
@@ -81,7 +142,7 @@ To get a copy:
|
|
81
142
|
|
82
143
|
== Requirements
|
83
144
|
|
84
|
-
* OpenBSD 5.9+
|
145
|
+
* OpenBSD 5.9+ (6.4+ for unveil, but 6.6+ recommended)
|
85
146
|
* ruby 1.8.7+
|
86
147
|
* rake-compiler (if compiling)
|
87
148
|
|
data/Rakefile
CHANGED
@@ -1,13 +1,7 @@
|
|
1
1
|
require "rake"
|
2
2
|
require "rake/clean"
|
3
3
|
|
4
|
-
CLEAN.include %w'**.rbc rdoc'
|
5
|
-
|
6
|
-
desc "Do a full cleaning"
|
7
|
-
task :distclean do
|
8
|
-
CLEAN.include %w'tmp pkg tame*.gem lib/*.so'
|
9
|
-
Rake::Task[:clean].invoke
|
10
|
-
end
|
4
|
+
CLEAN.include %w'**.rbc rdoc lib/*.so tmp'
|
11
5
|
|
12
6
|
desc "Build the gem"
|
13
7
|
task :package do
|
data/ext/pledge/extconf.rb
CHANGED
data/ext/pledge/pledge.c
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
static VALUE ePledgeInvalidPromise;
|
6
6
|
static VALUE ePledgePermissionIncreaseAttempt;
|
7
7
|
static VALUE ePledgeError;
|
8
|
+
static VALUE ePledgeUnveilError;
|
8
9
|
|
9
10
|
static VALUE rb_pledge(int argc, VALUE* argv, VALUE pledge_class) {
|
10
11
|
VALUE promises = Qnil;
|
@@ -44,6 +45,37 @@ static VALUE rb_pledge(int argc, VALUE* argv, VALUE pledge_class) {
|
|
44
45
|
return Qnil;
|
45
46
|
}
|
46
47
|
|
48
|
+
#ifdef HAVE_UNVEIL
|
49
|
+
static VALUE check_unveil(const char * path, const char * perm) {
|
50
|
+
if (unveil(path, perm) != 0) {
|
51
|
+
switch(errno) {
|
52
|
+
case EINVAL:
|
53
|
+
rb_raise(ePledgeUnveilError, "invalid permissions value");
|
54
|
+
case EPERM:
|
55
|
+
rb_raise(ePledgeUnveilError, "attempt to increase permissions, path not accessible, or unveil already locked");
|
56
|
+
case E2BIG:
|
57
|
+
rb_raise(ePledgeUnveilError, "per-process limit for unveiled paths reached");
|
58
|
+
case ENOENT:
|
59
|
+
rb_raise(ePledgeUnveilError, "directory in the path does not exist");
|
60
|
+
default:
|
61
|
+
rb_raise(ePledgeUnveilError, "unveil error");
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
return Qnil;
|
66
|
+
}
|
67
|
+
|
68
|
+
static VALUE rb_unveil(VALUE pledge_class, VALUE path, VALUE perm) {
|
69
|
+
SafeStringValue(path);
|
70
|
+
SafeStringValue(perm);
|
71
|
+
return check_unveil(RSTRING_PTR(path), RSTRING_PTR(perm));
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE rb_finalize_unveil(VALUE pledge_class) {
|
75
|
+
return check_unveil(NULL, NULL);
|
76
|
+
}
|
77
|
+
#endif
|
78
|
+
|
47
79
|
void Init_pledge(void) {
|
48
80
|
VALUE cPledge;
|
49
81
|
cPledge = rb_define_module("Pledge");
|
@@ -52,4 +84,10 @@ void Init_pledge(void) {
|
|
52
84
|
ePledgeError = rb_define_class_under(cPledge, "Error", rb_eStandardError);
|
53
85
|
ePledgeInvalidPromise = rb_define_class_under(cPledge, "InvalidPromise", ePledgeError);
|
54
86
|
ePledgePermissionIncreaseAttempt = rb_define_class_under(cPledge, "PermissionIncreaseAttempt", ePledgeError);
|
87
|
+
|
88
|
+
#ifdef HAVE_UNVEIL
|
89
|
+
rb_define_private_method(cPledge, "_unveil", rb_unveil, 2);
|
90
|
+
rb_define_private_method(cPledge, "_finalize_unveil!", rb_finalize_unveil, 0);
|
91
|
+
ePledgeUnveilError = rb_define_class_under(cPledge, "UnveilError", rb_eStandardError);
|
92
|
+
#endif
|
55
93
|
}
|
data/lib/unveil.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'pledge'
|
4
|
+
raise LoadError, "unveil not supported" unless Pledge.respond_to?(:_unveil, true)
|
5
|
+
|
6
|
+
module Pledge
|
7
|
+
# Limit access to the file system using unveil(2). +paths+ should be a hash
|
8
|
+
# where keys are paths and values are the access permissions for that path. Each
|
9
|
+
# value should be a string with the following characters specifying what
|
10
|
+
# permissions are allowed:
|
11
|
+
#
|
12
|
+
# r :: Allow read access to existing files and directories
|
13
|
+
# w :: Allow write access to existing files and directories
|
14
|
+
# c :: Allow create/delete access for new files and directories
|
15
|
+
# x :: Allow execute access to programs
|
16
|
+
#
|
17
|
+
# You can use the empty string as permissions if you want to allow no access
|
18
|
+
# to the given path, even if you have granted some access to a folder above
|
19
|
+
# the given folder. You can use a value of +:gem+ to allow read access to
|
20
|
+
# the directory for the gem specified by the key.
|
21
|
+
#
|
22
|
+
# If called with an empty hash, adds an unveil of +/+ with no permissions,
|
23
|
+
# which denies all access to the file system if +unveil_without_lock+
|
24
|
+
# was not called previously.
|
25
|
+
def unveil(paths)
|
26
|
+
if paths.empty?
|
27
|
+
paths = {'/'=>''}
|
28
|
+
end
|
29
|
+
|
30
|
+
unveil_without_lock(paths)
|
31
|
+
_finalize_unveil!
|
32
|
+
end
|
33
|
+
|
34
|
+
# Same as unveil, but allows for future calls to unveil or unveil_without_lock.
|
35
|
+
def unveil_without_lock(paths)
|
36
|
+
paths = Hash[paths]
|
37
|
+
|
38
|
+
paths.to_a.each do |path, perm|
|
39
|
+
unless path.is_a?(String)
|
40
|
+
raise UnveilError, "unveil path is not a string: #{path.inspect}"
|
41
|
+
end
|
42
|
+
|
43
|
+
case perm
|
44
|
+
when :gem
|
45
|
+
unless spec = Gem.loaded_specs[path]
|
46
|
+
raise UnveilError, "cannot unveil gem #{path} as it is not loaded"
|
47
|
+
end
|
48
|
+
|
49
|
+
paths.delete(path)
|
50
|
+
paths[spec.full_gem_path] = 'r'
|
51
|
+
when String
|
52
|
+
# nothing to do
|
53
|
+
else
|
54
|
+
raise UnveilError, "unveil permission is not a string: #{perm.inspect}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
paths.each do |path, perm|
|
59
|
+
_unveil(path, perm)
|
60
|
+
end
|
61
|
+
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
data/spec/pledge_spec.rb
CHANGED
@@ -41,7 +41,7 @@ describe "Pledge.pledge" do
|
|
41
41
|
proc{Pledge.pledge("foo")}.must_raise Pledge::InvalidPromise
|
42
42
|
end
|
43
43
|
|
44
|
-
it "should raise a Pledge::PermissionIncreaseAttempt if attempting to increase
|
44
|
+
it "should raise a Pledge::PermissionIncreaseAttempt if attempting to increase permissions" do
|
45
45
|
pledged("begin; Pledge.pledge('rpath'); rescue Pledge::PermissionIncreaseAttempt; exit 0; end; exit 1")
|
46
46
|
end
|
47
47
|
|
@@ -121,9 +121,9 @@ describe "Pledge.pledge" do
|
|
121
121
|
end
|
122
122
|
|
123
123
|
it "should handle both promises and execpromises arguments" do
|
124
|
-
execpledged("proc exec rpath", "stdio rpath", "exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE')
|
125
|
-
execpledged("proc exec", "stdio rpath", "$stderr.reopen('/dev/null', 'w'); exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE')
|
126
|
-
execpledged("proc exec rpath", "stdio", "$stderr.reopen('/dev/null', 'w'); exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE')
|
124
|
+
execpledged("proc exec rpath", "stdio rpath", "exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE'))").must_equal true
|
125
|
+
execpledged("proc exec", "stdio rpath", "$stderr.reopen('/dev/null', 'w'); exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE'))").must_equal false
|
126
|
+
execpledged("proc exec rpath", "stdio", "$stderr.reopen('/dev/null', 'w'); exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE'))").must_equal false
|
127
127
|
end
|
128
128
|
|
129
129
|
it "should handle nil arguments" do
|
@@ -133,6 +133,82 @@ describe "Pledge.pledge" do
|
|
133
133
|
execpledged("", nil, "`cat MIT-LICENSE`").must_equal false
|
134
134
|
execpledged(nil, "stdio rpath", "`cat MIT-LICENSE`").must_equal true
|
135
135
|
execpledged(nil, "stdio", "File.read('MIT-LICENSE')").must_equal true
|
136
|
-
execpledged(nil, "stdio", "$stderr.reopen('/dev/null', 'w'); exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE')
|
136
|
+
execpledged(nil, "stdio", "$stderr.reopen('/dev/null', 'w'); exit(`cat MIT-LICENSE` == File.read('MIT-LICENSE'))").must_equal false
|
137
137
|
end
|
138
138
|
end
|
139
|
+
|
140
|
+
describe "Pledge.unveil" do
|
141
|
+
def unveiled(unveils, code)
|
142
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.unveil(#{unveils.inspect}); #{code}")
|
143
|
+
end
|
144
|
+
|
145
|
+
test_file = "spec/#{$$}_test.rb"
|
146
|
+
|
147
|
+
after do
|
148
|
+
File.delete(test_file) if File.file?(test_file)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should handle unveiling paths" do
|
152
|
+
unveiled({}, "exit(Dir['*'].empty?)").must_equal true
|
153
|
+
unveiled({'.'=>'r'}, "exit(!Dir['*'].empty?)").must_equal true
|
154
|
+
|
155
|
+
test_read = "exit(((File.read('MIT-LICENSE'); true) rescue false))"
|
156
|
+
unveiled({'.'=>'w'}, test_read).must_equal false
|
157
|
+
unveiled({'.'=>'r'}, test_read).must_equal true
|
158
|
+
unveiled({'.'=>'r'}, "exit(((File.open('MIT-LICENSE', 'w'){}; true) rescue false))").must_equal false
|
159
|
+
|
160
|
+
%w'rwxc rwx rwc rxc rx rw rc'.each do |perm|
|
161
|
+
unveiled({'.'=>perm}, test_read).must_equal true
|
162
|
+
end
|
163
|
+
|
164
|
+
%w'wxc wx wc xc x w c'.each do |perm|
|
165
|
+
unveiled({'.'=>perm}, test_read).must_equal false
|
166
|
+
end
|
167
|
+
|
168
|
+
unveiled({'MIT-LICENSE'=>'r'}, test_read).must_equal true
|
169
|
+
unveiled({'Rakefile'=>'r'}, test_read).must_equal false
|
170
|
+
unveiled({'.'=>'r', 'MIT-LICENSE'=>''}, test_read).must_equal false
|
171
|
+
unveiled({}, "Pledge.unveil{} rescue exit(1)").must_equal false
|
172
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.unveil_without_lock({'.'=>'r'}); Pledge.unveil({}); #{test_read}").must_equal true
|
173
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.unveil('foo/bar'=>'r') rescue exit(1)").must_equal false
|
174
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.send(:_unveil, '.', 'f') rescue exit(1)").must_equal false
|
175
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.unveil({1=>'s'}) rescue exit(1)").must_equal false
|
176
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.unveil({'s'=>1}) rescue exit(1)").must_equal false
|
177
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.send(:_unveil, 1, 'r') rescue exit(1)").must_equal false
|
178
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.send(:_unveil, '.', 1) rescue exit(1)").must_equal false
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should handle require after unveil with read access after removing from $LOADED_FEATURES" do
|
182
|
+
[File.join('.', test_file), File.join(Dir.pwd, test_file)].each do |f|
|
183
|
+
f = f.inspect
|
184
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', <<-END).must_equal true
|
185
|
+
File.open(#{f}, 'w'){|f| f.write '1'}
|
186
|
+
require #{f}
|
187
|
+
Pledge.unveil('spec'=>'r')
|
188
|
+
$LOADED_FEATURES.delete #{f}
|
189
|
+
require #{f}
|
190
|
+
END
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should handle :gem value to unveil gems" do
|
195
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "$stderr.reopen('/dev/null', 'w'); require 'rubygems'; gem 'minitest'; require 'minitest'; Pledge.unveil({}); require 'minitest/benchmark' rescue exit(1)").must_equal false
|
196
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "require 'rubygems'; gem 'minitest'; require 'minitest'; Pledge.unveil('minitest'=>:gem); require 'minitest/benchmark' rescue (p $!; puts $!.backtrace; exit(1))").must_equal true
|
197
|
+
|
198
|
+
system(RUBY, '-I', 'lib', '-r', 'unveil', '-e', "Pledge.unveil('gadzooks!!!'=>:gem) rescue exit(1)").must_equal false
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should need create and write access for writing new files, and create access for removing files" do
|
202
|
+
unveiled({'.'=>'w'}, "File.open(#{test_file.inspect}, 'w'){|f| f.write '1'} rescue exit(1)").must_equal false
|
203
|
+
File.file?(test_file).must_equal false
|
204
|
+
unveiled({'.'=>'c'}, "File.open(#{test_file.inspect}, 'w'){|f| f.write '1'} rescue exit(1)").must_equal false
|
205
|
+
File.file?(test_file).must_equal false
|
206
|
+
unveiled({'.'=>'cw'}, "File.open(#{test_file.inspect}, 'w'){|f| f.write '1'}").must_equal true
|
207
|
+
File.read(test_file).must_equal '1'
|
208
|
+
|
209
|
+
unveiled({'.'=>'w'}, "File.delete(#{test_file.inspect}) rescue exit(1)").must_equal false
|
210
|
+
File.read(test_file).must_equal '1'
|
211
|
+
unveiled({'.'=>'c'}, "File.delete(#{test_file.inspect})").must_equal true
|
212
|
+
File.file?(test_file).must_equal false
|
213
|
+
end
|
214
|
+
end if Pledge.respond_to?(:_unveil, true)
|
metadata
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pledge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
|
-
pledge exposes OpenBSD's pledge(2) system
|
15
|
-
program to restrict the types of operations the program
|
16
|
-
|
17
|
-
pledge
|
18
|
-
use a wide variety of operations on initialization, but
|
19
|
-
|
20
|
-
be accepted).
|
14
|
+
pledge exposes OpenBSD's pledge(2) and unveil(2) system calls to Ruby, allowing
|
15
|
+
a program to restrict the types of operations the program can do, and the file
|
16
|
+
system access the program has, after the point of call. Unlike other similar
|
17
|
+
systems, pledge and unveil are specifically designed for programs that need to
|
18
|
+
use a wide variety of operations on initialization, but a fewer number after
|
19
|
+
initialization (when user input will be accepted).
|
21
20
|
email: code@jeremyevans.net
|
22
21
|
executables: []
|
23
22
|
extensions:
|
@@ -33,6 +32,7 @@ files:
|
|
33
32
|
- Rakefile
|
34
33
|
- ext/pledge/extconf.rb
|
35
34
|
- ext/pledge/pledge.c
|
35
|
+
- lib/unveil.rb
|
36
36
|
- spec/pledge_spec.rb
|
37
37
|
homepage: https://github.com/jeremyevans/ruby-pledge
|
38
38
|
licenses:
|
@@ -44,7 +44,7 @@ rdoc_options:
|
|
44
44
|
- "--line-numbers"
|
45
45
|
- "--inline-source"
|
46
46
|
- "--title"
|
47
|
-
- 'pledge: restrict system operations on OpenBSD'
|
47
|
+
- 'pledge: restrict system operations and file system access on OpenBSD'
|
48
48
|
- "--main"
|
49
49
|
- README.rdoc
|
50
50
|
require_paths:
|
@@ -63,5 +63,5 @@ requirements: []
|
|
63
63
|
rubygems_version: 3.0.3
|
64
64
|
signing_key:
|
65
65
|
specification_version: 4
|
66
|
-
summary: Restrict system operations on OpenBSD
|
66
|
+
summary: Restrict system operations and file system access on OpenBSD
|
67
67
|
test_files: []
|