pledge 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1ff2e2250fd7b7b8b8edab08f84d75d1140b75ee
4
+ data.tar.gz: 14e9e9cdc750d16d575e014e5e5b29769816f19d
5
+ SHA512:
6
+ metadata.gz: a5e05296eac3da536dbf96189899d810baecef6c791ef9f356628f2f81a04c13f00a892247cf7e9495749f357e9316aefe6b5af324a8361112925861f1786b45
7
+ data.tar.gz: 3f7e3289b7011e2b54eac6b1ce35798667dda2d08b51815517a57b6476255ffd3628bb37fee313d24f4649a1f0bc654af1590bf0617401a5a8381fdebff16c06
@@ -0,0 +1,3 @@
1
+ === 1.0.0 (2016-11-04)
2
+
3
+ * Initial Public Release
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2016 Jeremy Evans
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,99 @@
1
+ = pledge
2
+
3
+ pledge exposes OpenBSD's pledge(2) system call to ruby, allowing a
4
+ program to restrict the types of operations the program
5
+ can do after that point. Unlike other similar systems,
6
+ pledge is specifically designed for programs that need to
7
+ use a wide variety of operations on initialization, but
8
+ a fewer number after initialization (when user input will
9
+ be accepted).
10
+
11
+ plege(2) is supported on OpenBSD 5.9+.
12
+
13
+ == Usage
14
+
15
+ First, you need to require the library
16
+
17
+ require 'pledge'
18
+
19
+ Then you can use +Pledge.pledge+ as the interface to the pledge(2)
20
+ system call. You pass +Pledge.pledge+ a string containing tokens
21
+ for the operations you would like to allow (called promises).
22
+ For example, if you want to give the process the ability to read
23
+ from the the file system, but not read from the file system or
24
+ allow network access:
25
+
26
+ Pledge.pledge("rpath")
27
+
28
+ To allow read/write filesystem access, but not network access:
29
+
30
+ Pledge.pledge("rpath wpath cpath")
31
+
32
+ To allow inet/unix socket access and DNS queries, but not
33
+ filesystem access:
34
+
35
+ Pledge.pledge("inet unix dns")
36
+
37
+ +Pledge+ is a module that extends itself, you can include it
38
+ in other classes:
39
+
40
+ Object.send(:include, Pledge)
41
+ pledge("rpath")
42
+
43
+ == Options
44
+
45
+ See the pledge(2) man page for a description of the allowed
46
+ promises in the string passed to +Pledge.pledge+.
47
+
48
+ Using an unsupported promise will raise an exception. The "stdio"
49
+ promise is added automatically, as ruby does not function without
50
+
51
+ it.
52
+
53
+ == Reporting issues/bugs
54
+
55
+ This library uses GitHub Issues for tracking issues/bugs:
56
+
57
+ https://github.com/jeremyevans/ruby-pledge/issues
58
+
59
+ == Contributing
60
+
61
+ The source code is on GitHub:
62
+
63
+ https://github.com/jeremyevans/ruby-pledge
64
+
65
+ To get a copy:
66
+
67
+ git clone git://github.com/jeremyevans/ruby-pledge.git
68
+
69
+ == Requirements
70
+
71
+ * OpenBSD 5.9+
72
+ * ruby 1.8.7+
73
+ * rake-compiler (if compiling)
74
+
75
+ == Compiling
76
+
77
+ To build the library from a git checkout, use the compile task.
78
+
79
+ rake compile
80
+
81
+ == Running the specs
82
+
83
+ The rake spec task runs the specs. This is also the default rake
84
+ task. This will compile the library if not already compiled.
85
+
86
+ rake
87
+
88
+ == Known Issues
89
+
90
+ * You cannot create new threads after running +Pledge.pledge+, as
91
+ it uses syscalls that are not currently allowed by pledge(2). +fork+
92
+ still works, assuming you are using the +proc+ pledge.
93
+
94
+ * You cannot currently test +Pledge.pledge+ in irb/pry, as they use an
95
+ ioctl that is not currently allowed by pledge(2).
96
+
97
+ == Author
98
+
99
+ Jeremy Evans <code@jeremyevans.net>
@@ -0,0 +1,30 @@
1
+ require "rake"
2
+ require "rake/clean"
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
11
+
12
+ desc "Build the gem"
13
+ task :package do
14
+ sh %{gem build pledge.gemspec}
15
+ end
16
+
17
+ desc "Run specs"
18
+ task :spec => :compile do
19
+ ruby = ENV['RUBY'] ||= FileUtils::RUBY
20
+ sh %{#{ruby} spec/pledge_spec.rb}
21
+ end
22
+
23
+ desc "Run specs"
24
+ task :default => :spec
25
+
26
+ begin
27
+ require 'rake/extensiontask'
28
+ Rake::ExtensionTask.new('pledge')
29
+ rescue LoadError
30
+ end
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+ have_header 'pledge'
3
+ $CFLAGS << " -O0 -g -ggdb" if ENV['DEBUG']
4
+ $CFLAGS << " -Wall"
5
+ create_makefile("pledge")
@@ -0,0 +1,40 @@
1
+ #include <errno.h>
2
+ #include <ruby.h>
3
+ #include <unistd.h>
4
+
5
+ static VALUE ePledgeInvalidPromise;
6
+ static VALUE ePledgePermissionIncreaseAttempt;
7
+ static VALUE ePledgeError;
8
+
9
+ static VALUE rb_pledge(VALUE pledge_class, VALUE promises) {
10
+ SafeStringValue(promises);
11
+ promises = rb_str_dup(promises);
12
+
13
+ /* required for ruby to work */
14
+ rb_str_cat2(promises, " stdio");
15
+ promises = rb_funcall(promises, rb_intern("strip"), 0);
16
+ SafeStringValue(promises);
17
+
18
+ if (pledge(RSTRING_PTR(promises), NULL) != 0) {
19
+ switch(errno) {
20
+ case EINVAL:
21
+ rb_raise(ePledgeInvalidPromise, "invalid promise in promises string");
22
+ case EPERM:
23
+ rb_raise(ePledgePermissionIncreaseAttempt, "attempt to increase permissions");
24
+ default:
25
+ rb_raise(ePledgeError, "pledge error");
26
+ }
27
+ }
28
+
29
+ return Qnil;
30
+ }
31
+
32
+ void Init_pledge(void) {
33
+ VALUE cPledge;
34
+ cPledge = rb_define_module("Pledge");
35
+ rb_define_method(cPledge, "pledge", rb_pledge, 1);
36
+ rb_extend_object(cPledge, cPledge);
37
+ ePledgeError = rb_define_class_under(cPledge, "Error", rb_eStandardError);
38
+ ePledgeInvalidPromise = rb_define_class_under(cPledge, "InvalidPromise", ePledgeError);
39
+ ePledgePermissionIncreaseAttempt = rb_define_class_under(cPledge, "PermissionIncreaseAttempt", ePledgeError);
40
+ }
@@ -0,0 +1,112 @@
1
+ require './lib/pledge'
2
+
3
+ require 'rubygems'
4
+ gem 'minitest'
5
+ require 'minitest/autorun'
6
+
7
+ RUBY = ENV['RUBY'] || 'ruby'
8
+
9
+ describe "Pledge.pledge" do
10
+ def _pledged(status, promises, code)
11
+ system(RUBY, '-I', 'lib', '-r', 'pledge', '-e', "Pledge.pledge(#{promises.inspect}); #{code}").must_equal status
12
+ end
13
+
14
+ def pledged(code, promises="")
15
+ _pledged(true, promises, code)
16
+ end
17
+
18
+ def unpledged(code, promises="")
19
+ _pledged(false, promises, code)
20
+ end
21
+
22
+ def with_lib(lib)
23
+ rubyopt = ENV['RUBYOPT']
24
+ ENV['RUBYOPT'] = "#{rubyopt} -r#{lib}"
25
+ yield
26
+ ensure
27
+ ENV['RUBYOPT'] = rubyopt
28
+ end
29
+
30
+ after do
31
+ Dir['spec/_*'].each{|f| File.delete(f)}
32
+ Dir['*.core'].each{|f| File.delete(f)}
33
+ end
34
+
35
+ it "should raise a Pledge::InvalidPromise for unsupported promises" do
36
+ proc{Pledge.pledge("foo")}.must_raise Pledge::InvalidPromise
37
+ end
38
+
39
+ it "should raise a Pledge::PermissionIncreaseAttempt if attempting to increase permissinos" do
40
+ pledged("begin; Pledge.pledge('rpath'); rescue Pledge::PermissionIncreaseAttempt; exit 0; end; exit 1")
41
+ end
42
+
43
+ it "should produce a core file on failure" do
44
+ unpledged("File.read('#{__FILE__}')")
45
+ Dir['*.core'].wont_equal []
46
+ end
47
+
48
+ it "should allow reading files if rpath is used" do
49
+ unpledged("File.read('#{__FILE__}')")
50
+ pledged("File.read('#{__FILE__}')", "rpath")
51
+ end
52
+
53
+ it "should allow creating files if cpath and wpath are used" do
54
+ unpledged("File.open('spec/_test', 'w'){}")
55
+ unpledged("File.open('spec/_test', 'w'){}", "cpath")
56
+ unpledged("File.open('spec/_test', 'w'){}", "wpath")
57
+ File.file?('spec/_test').must_equal false
58
+ pledged("File.open('#{'spec/_test'}', 'w'){}", "cpath wpath")
59
+ File.file?('spec/_test').must_equal true
60
+ end
61
+
62
+ it "should allow writing to files if wpath and rpath are used" do
63
+ File.open('spec/_test', 'w'){}
64
+ unpledged("File.open('spec/_test', 'r+'){}")
65
+ pledged("File.open('#{'spec/_test'}', 'r+'){|f| f.write '1'}", "wpath rpath")
66
+ File.read('spec/_test').must_equal '1'
67
+ end
68
+
69
+ it "should allow dns lookups if dns is used" do
70
+ with_lib('socket') do
71
+ unpledged("Socket.gethostbyname('google.com')")
72
+ pledged("Socket.gethostbyname('google.com')", "dns")
73
+ end
74
+ end
75
+
76
+ it "should allow internet access if inet is used" do
77
+ with_lib('net/http') do
78
+ unpledged("Net::HTTP.get('127.0.0.1', '/index.html') rescue nil")
79
+ promises = "inet"
80
+ # rpath necessary on ruby < 2.1, as it calls stat
81
+ promises << " rpath" if RUBY_VERSION < '2.1'
82
+ pledged("Net::HTTP.get('127.0.0.1', '/index.html') rescue nil", promises)
83
+ end
84
+ end
85
+
86
+ it "should allow killing programs if proc is used" do
87
+ unpledged("Process.kill(:URG, #{$$})")
88
+ pledged("Process.kill(:URG, #{$$})", "proc")
89
+ end
90
+
91
+ it "should allow creating temp files if tmppath and rpath are used" do
92
+ with_lib('tempfile') do
93
+ unpledged("Tempfile.new('foo')")
94
+ unpledged("Tempfile.new('foo')", "tmppath")
95
+ unpledged("Tempfile.new('foo')", "rpath")
96
+ promises = "tmppath rpath"
97
+ # cpath necessary on ruby < 2.0, as it calls mkdir
98
+ promises << " cpath" if RUBY_VERSION < '2.0'
99
+ pledged("Tempfile.new('foo')", promises)
100
+ end
101
+ end
102
+
103
+ it "should allow unix sockets if unix and rpath is used" do
104
+ require 'socket'
105
+ us = UNIXServer.new('spec/_sock')
106
+ with_lib('socket') do
107
+ unpledged("UNIXSocket.new('spec/_sock').send('u', 0)")
108
+ pledged("UNIXSocket.new('spec/_sock').send('t', 0)", "unix")
109
+ end
110
+ us.accept.read.must_equal 't'
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pledge
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Evans
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ pledge exposes OpenBSD's pledge(2) system call to ruby, allowing a
15
+ program to restrict the types of operations the program
16
+ can do after that point. Unlike other similar systems,
17
+ pledge is specifically designed for programs that need to
18
+ use a wide variety of operations on initialization, but
19
+ a fewer number after initialization (when user input will
20
+ be accepted).
21
+ email: code@jeremyevans.net
22
+ executables: []
23
+ extensions:
24
+ - ext/pledge/extconf.rb
25
+ extra_rdoc_files:
26
+ - README.rdoc
27
+ - CHANGELOG
28
+ - MIT-LICENSE
29
+ files:
30
+ - CHANGELOG
31
+ - MIT-LICENSE
32
+ - README.rdoc
33
+ - Rakefile
34
+ - ext/pledge/extconf.rb
35
+ - ext/pledge/pledge.c
36
+ - spec/pledge_spec.rb
37
+ homepage: https://github.com/jeremyevans/ruby-pledge
38
+ licenses:
39
+ - MIT
40
+ metadata: {}
41
+ post_install_message:
42
+ rdoc_options:
43
+ - "--quiet"
44
+ - "--line-numbers"
45
+ - "--inline-source"
46
+ - "--title"
47
+ - 'pledge: restrict system operations on OpenBSD'
48
+ - "--main"
49
+ - README.rdoc
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 1.8.7
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 2.5.1
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Restrict system operations on OpenBSD
68
+ test_files: []