cap2 0.2.0 → 0.2.1
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/README.md +40 -15
- data/lib/cap2/file.rb +20 -14
- data/lib/cap2/process.rb +10 -10
- data/lib/cap2/version.rb +1 -1
- data/spec/file_spec.rb +39 -13
- data/spec/process_spec.rb +8 -8
- metadata +2 -2
data/README.md
CHANGED
@@ -49,25 +49,26 @@ Capabilities are referenced using lower cased symbols, and without the CAP_ pref
|
|
49
49
|
|
50
50
|
### Querying Capabilities
|
51
51
|
|
52
|
-
There are three methods - `permitted?`, `enabled?` and `inheritable?` - defined on both `Cap2::Process` and `Cap2::File` for querying capabilities. Each of these methods, Cap2::File#enabled? being the exception, take a capability
|
52
|
+
There are three methods - `permitted?`, `enabled?` and `inheritable?` - defined on both `Cap2::Process` and `Cap2::File` for querying capabilities. Each of these methods, Cap2::File#enabled? being the exception, take a list of capability symbols and return true / false if the capabilities are in / not in the relevant set:
|
53
53
|
|
54
54
|
```
|
55
55
|
# the init daemon - all caps permitted & enabled but not inheritable
|
56
|
-
init = Cap2.process(1)
|
56
|
+
init = Cap2.process(1) # => #<Cap2::Process @pid=1>
|
57
57
|
|
58
|
-
init.permitted?(:kill)
|
59
|
-
init.permitted?(:chown)
|
58
|
+
init.permitted?(:kill) # => true
|
59
|
+
init.permitted?(:chown, :fowner) # => true
|
60
60
|
|
61
|
-
init.enabled?(:fowner)
|
61
|
+
init.enabled?(:fowner) # => true
|
62
|
+
init.enabled?(:kill, :chown) # => true
|
62
63
|
|
63
|
-
init.inheritable?(:
|
64
|
-
init.inheritable?(:fowner)
|
64
|
+
init.inheritable?(:chown) # => false
|
65
|
+
init.inheritable?(:fowner, :kill) # => false
|
65
66
|
|
66
67
|
# assume /bin/ping is using file capabilities to enable CAP_NET_RAW on exec
|
67
68
|
ping = Cap2.file('/bin/ping') # => #<Cap2::File @filename="/bin/ping">
|
68
69
|
|
69
70
|
ping.permitted?(:net_raw) # => true
|
70
|
-
ping.permitted?(:mknod)
|
71
|
+
ping.permitted?(:mknod, :chown) # => false
|
71
72
|
|
72
73
|
ping.enabled? # => true
|
73
74
|
|
@@ -87,17 +88,19 @@ Cap2 provides different levels of control over process and file capabilities.
|
|
87
88
|
To modify the permitted capabilities of a file (i.e. the capabilities which will be permitted in any process that exec's the file), use `Cap2::File#permit` and `Cap2::File#unpermit`:
|
88
89
|
|
89
90
|
```
|
90
|
-
Cap2.process.enabled?(:setfcap)
|
91
|
+
Cap2.process.enabled?(:setfcap) # => true - needed to set file capabilities
|
91
92
|
|
92
|
-
file = Cap2.file('/tmp/file')
|
93
|
+
file = Cap2.file('/tmp/file') # => #<Cap2::File @filename="/tmp/file">
|
93
94
|
|
94
|
-
file.permitted?(:mknod)
|
95
|
+
file.permitted?(:mknod, :chown, :fowner) # => false
|
95
96
|
|
96
|
-
file.permit(:mknod)
|
97
|
-
file.
|
97
|
+
file.permit(:mknod) # => true
|
98
|
+
file.permit(:chown, :fowner) # => true
|
99
|
+
file.permitted?(:mknod, :chown, :fowner) # => true
|
98
100
|
|
99
|
-
file.unpermit(:mknod)
|
100
|
-
file.
|
101
|
+
file.unpermit(:mknod) # => true
|
102
|
+
file.unpermit(:chown, :fowner) # => true
|
103
|
+
file.permitted?(:mknod, :chown, :fowner) # => false
|
101
104
|
```
|
102
105
|
|
103
106
|
To modify the effective bit of a file (i.e. whether the resulting permitted capabilities of any process that exec's the file will also be enabled in it's effective set), use `Cap2::File#enable` and `Cap2::File#disable`:
|
@@ -133,6 +136,28 @@ file.disallow_inherit(:fowner) # => true
|
|
133
136
|
file.inheritable?(:fowner) # => false
|
134
137
|
```
|
135
138
|
|
139
|
+
To clear all capabilities for a file, use Cap2::File#clear:
|
140
|
+
|
141
|
+
```
|
142
|
+
Cap2.process.enabled?(:setfcap) # => true - needed to set file capabilities
|
143
|
+
|
144
|
+
file = Cap2.file('/tmp/file') # => #<Cap2::File @filename="/tmp/file">
|
145
|
+
|
146
|
+
file.permit(:kill, :mknod) # => true
|
147
|
+
file.allow_inherit(:kill, :mknod) # => true
|
148
|
+
file.enable # => true
|
149
|
+
|
150
|
+
file.permitted?(:kill, :mknod) # => true
|
151
|
+
file.inheritable?(:kill, :mknod) # => true
|
152
|
+
file.enabled? # => true
|
153
|
+
|
154
|
+
file.clear # => true
|
155
|
+
|
156
|
+
file.permitted?(:kill, :mknod) # => false
|
157
|
+
file.inheritable?(:kill, :mknod) # => false
|
158
|
+
file.enabled? # => false
|
159
|
+
```
|
160
|
+
|
136
161
|
#### Processes
|
137
162
|
|
138
163
|
Cap2 can be used to enable / disable capabilities of the current Ruby process.
|
data/lib/cap2/file.rb
CHANGED
@@ -8,16 +8,16 @@ module Cap2
|
|
8
8
|
@caps = getcaps
|
9
9
|
end
|
10
10
|
|
11
|
-
# Returns whether the given
|
12
|
-
def permitted?(
|
11
|
+
# Returns whether the given capabilities are permitted
|
12
|
+
def permitted?(*capabilities)
|
13
13
|
reload
|
14
|
-
@caps[:permitted].
|
14
|
+
@caps[:permitted].superset? Set[*capabilities]
|
15
15
|
end
|
16
16
|
|
17
|
-
# Returns whether the given
|
18
|
-
def inheritable?(
|
17
|
+
# Returns whether the given capabilities are inheritable
|
18
|
+
def inheritable?(*capabilities)
|
19
19
|
reload
|
20
|
-
@caps[:inheritable].
|
20
|
+
@caps[:inheritable].superset? Set[*capabilities]
|
21
21
|
end
|
22
22
|
|
23
23
|
# Returns whether or not the file has any effective
|
@@ -28,26 +28,26 @@ module Cap2
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Permit processes executing this file to enable the given capability.
|
31
|
-
def permit(
|
32
|
-
@caps[:permitted].
|
31
|
+
def permit(*capabilities)
|
32
|
+
@caps[:permitted].merge(capabilities)
|
33
33
|
save
|
34
34
|
end
|
35
35
|
|
36
36
|
# Dont permit processes executing this file to enable the given capability.
|
37
|
-
def unpermit(
|
38
|
-
@caps[:permitted].
|
37
|
+
def unpermit(*capabilities)
|
38
|
+
@caps[:permitted].subtract(capabilities)
|
39
39
|
save
|
40
40
|
end
|
41
41
|
|
42
42
|
# Allow processes executing this file to inherit the given capability.
|
43
|
-
def allow_inherit(
|
44
|
-
@caps[:inheritable].
|
43
|
+
def allow_inherit(*capabilities)
|
44
|
+
@caps[:inheritable].merge(capabilities)
|
45
45
|
save
|
46
46
|
end
|
47
47
|
|
48
48
|
# Dont allow processes executing this file to inherit the given capability.
|
49
|
-
def disallow_inherit(
|
50
|
-
@caps[:inheritable].
|
49
|
+
def disallow_inherit(*capabilities)
|
50
|
+
@caps[:inheritable].subtract(capabilities)
|
51
51
|
save
|
52
52
|
end
|
53
53
|
|
@@ -63,6 +63,12 @@ module Cap2
|
|
63
63
|
save
|
64
64
|
end
|
65
65
|
|
66
|
+
# Clear all capabilites
|
67
|
+
def clear
|
68
|
+
@caps.each_pair { |_, s| s.clear }
|
69
|
+
save
|
70
|
+
end
|
71
|
+
|
66
72
|
private
|
67
73
|
def reload
|
68
74
|
@caps = getcaps
|
data/lib/cap2/process.rb
CHANGED
@@ -8,22 +8,22 @@ module Cap2
|
|
8
8
|
@caps = getcaps
|
9
9
|
end
|
10
10
|
|
11
|
-
# Returns whether the given
|
12
|
-
def permitted?(
|
11
|
+
# Returns whether the given capabilities are permitted
|
12
|
+
def permitted?(*capabilities)
|
13
13
|
reload
|
14
|
-
@caps[:permitted].
|
14
|
+
@caps[:permitted].superset? Set[*capabilities]
|
15
15
|
end
|
16
16
|
|
17
|
-
# Returns whether the given
|
18
|
-
def enabled?(
|
17
|
+
# Returns whether the given capabilities are enabled
|
18
|
+
def enabled?(*capabilities)
|
19
19
|
reload
|
20
|
-
@caps[:effective].
|
20
|
+
@caps[:effective].superset? Set[*capabilities]
|
21
21
|
end
|
22
22
|
|
23
|
-
# Returns whether the given
|
24
|
-
def inheritable?(
|
23
|
+
# Returns whether the given capabilities are inheritable
|
24
|
+
def inheritable?(capabilities)
|
25
25
|
reload
|
26
|
-
@caps[:inheritable].
|
26
|
+
@caps[:inheritable].superset? Set[*capabilities]
|
27
27
|
end
|
28
28
|
|
29
29
|
# Enable the given capability for this process.
|
@@ -44,7 +44,7 @@ module Cap2
|
|
44
44
|
# Raises a RuntimeError if the process's pid is not the same as the current
|
45
45
|
# pid (you cannot enable capabilities for other processes, that's their job).
|
46
46
|
def check_pid
|
47
|
-
unless @pid == Process.pid
|
47
|
+
unless @pid == ::Process.pid
|
48
48
|
raise 'Cannot modify capabilities of other processes'
|
49
49
|
end
|
50
50
|
end
|
data/lib/cap2/version.rb
CHANGED
data/spec/file_spec.rb
CHANGED
@@ -5,17 +5,21 @@ describe Cap2::File do
|
|
5
5
|
|
6
6
|
subject { Cap2::File.new(file.path) }
|
7
7
|
|
8
|
+
before(:each) do
|
9
|
+
run_as_root('clear')
|
10
|
+
end
|
11
|
+
|
8
12
|
describe '#permitted?' do
|
9
|
-
context "when the file doesn't have the given
|
10
|
-
it { should_not be_permitted(:dac_override) }
|
13
|
+
context "when the file doesn't have the given capabilities" do
|
14
|
+
it { should_not be_permitted(:dac_override, :chown) }
|
11
15
|
end
|
12
16
|
|
13
|
-
context 'when the file does have the given
|
17
|
+
context 'when the file does have the given capabilities' do
|
14
18
|
before(:each) do
|
15
|
-
run_as_root('permit(:dac_override)')
|
19
|
+
run_as_root('permit(:dac_override, :chown)')
|
16
20
|
end
|
17
21
|
|
18
|
-
it { should be_permitted(:dac_override) }
|
22
|
+
it { should be_permitted(:dac_override, :chown) }
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
@@ -34,35 +38,45 @@ describe Cap2::File do
|
|
34
38
|
end
|
35
39
|
|
36
40
|
describe '#inheritable?' do
|
37
|
-
context "when the file doesn't have the given
|
38
|
-
it { should_not be_inheritable(:dac_override) }
|
41
|
+
context "when the file doesn't have the given capabilities" do
|
42
|
+
it { should_not be_inheritable(:dac_override, :chown) }
|
39
43
|
end
|
40
44
|
|
41
|
-
context 'when the file does have the given
|
45
|
+
context 'when the file does have the given capabilities' do
|
42
46
|
before(:each) do
|
43
|
-
run_as_root('allow_inherit(:dac_override)')
|
47
|
+
run_as_root('allow_inherit(:dac_override, :chown)')
|
44
48
|
end
|
45
49
|
|
46
|
-
it { should be_inheritable(:dac_override) }
|
50
|
+
it { should be_inheritable(:dac_override, :chown) }
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
50
54
|
describe '#permit' do
|
51
55
|
specify do
|
52
|
-
expect { running_as_root('permit(:fowner)') }.to \
|
56
|
+
expect { running_as_root('permit(:fowner, :kill)') }.to \
|
53
57
|
change { subject.permitted?(:fowner) }.from(false).to(true)
|
54
58
|
end
|
59
|
+
|
60
|
+
specify do
|
61
|
+
expect { running_as_root('permit(:fowner, :kill)') }.to \
|
62
|
+
change { subject.permitted?(:kill) }.from(false).to(true)
|
63
|
+
end
|
55
64
|
end
|
56
65
|
|
57
66
|
describe '#unpermit' do
|
58
67
|
before(:each) do
|
59
|
-
run_as_root('permit(:fowner)')
|
68
|
+
run_as_root('permit(:fowner, :kill)')
|
60
69
|
end
|
61
70
|
|
62
71
|
specify do
|
63
|
-
expect { running_as_root('unpermit(:fowner)') }.to \
|
72
|
+
expect { running_as_root('unpermit(:fowner, :kill)') }.to \
|
64
73
|
change { subject.permitted?(:fowner) }.from(true).to(false)
|
65
74
|
end
|
75
|
+
|
76
|
+
specify do
|
77
|
+
expect { running_as_root('unpermit(:fowner, :kill)') }.to \
|
78
|
+
change { subject.permitted?(:kill) }.from(true).to(false)
|
79
|
+
end
|
66
80
|
end
|
67
81
|
|
68
82
|
describe '#allow_inherit' do
|
@@ -129,6 +143,18 @@ describe Cap2::File do
|
|
129
143
|
end
|
130
144
|
end
|
131
145
|
|
146
|
+
describe '#clear' do
|
147
|
+
it 'should clear all capabilities' do
|
148
|
+
run_as_root('permit(:kill)', 'allow_inherit(:kill)', 'enable')
|
149
|
+
|
150
|
+
run_as_root('clear')
|
151
|
+
|
152
|
+
subject.should_not be_permitted(:kill)
|
153
|
+
subject.should_not be_inheritable(:kill)
|
154
|
+
subject.should_not be_enabled
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
132
158
|
# FIXME: Would like to call the given code on subject directly (e.g.
|
133
159
|
# `subject.permit(:fowner)`) but this would require the test
|
134
160
|
# suite to be run as root?
|
data/spec/process_spec.rb
CHANGED
@@ -2,30 +2,30 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Cap2::Process do
|
4
4
|
describe '#permitted?' do
|
5
|
-
context "when the process doesn't have the given
|
5
|
+
context "when the process doesn't have the given capabilities" do
|
6
6
|
subject { Cap2::Process.new(Process.pid) }
|
7
7
|
|
8
|
-
it { should_not be_permitted(:dac_override) }
|
8
|
+
it { should_not be_permitted(:dac_override, :chown) }
|
9
9
|
end
|
10
10
|
|
11
|
-
context 'when the process does have the given
|
11
|
+
context 'when the process does have the given capabilities' do
|
12
12
|
subject { Cap2::Process.new(1) }
|
13
13
|
|
14
|
-
it { should be_permitted(:dac_override) }
|
14
|
+
it { should be_permitted(:dac_override, :chown) }
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
describe '#enabled?' do
|
19
|
-
context "when the process doesn't have the given
|
19
|
+
context "when the process doesn't have the given capabilities" do
|
20
20
|
subject { Cap2::Process.new(Process.pid) }
|
21
21
|
|
22
|
-
it { should_not be_enabled(:dac_override) }
|
22
|
+
it { should_not be_enabled(:dac_override, :chown) }
|
23
23
|
end
|
24
24
|
|
25
|
-
context 'when the process does have the given
|
25
|
+
context 'when the process does have the given capabilities' do
|
26
26
|
subject { Cap2::Process.new(1) }
|
27
27
|
|
28
|
-
it { should be_enabled(:dac_override) }
|
28
|
+
it { should be_enabled(:dac_override, :chown) }
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cap2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-08 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! " Cap2 is a Ruby library for managing the POSIX 1003.1e capabilities\n
|
15
15
|
\ available in Linux kernels.\n\n These capabilities are a partitioning of
|