cap2 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +50 -10
- data/ext/cap2/cap2.c +13 -0
- data/lib/cap2.so +0 -0
- data/lib/cap2/file.rb +32 -8
- data/lib/cap2/version.rb +1 -1
- data/spec/file_spec.rb +42 -6
- metadata +1 -1
data/README.md
CHANGED
@@ -32,8 +32,8 @@ $ sudo make install
|
|
32
32
|
$ gem install cap2
|
33
33
|
```
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
Process and File Objects
|
36
|
+
------------------------
|
37
37
|
|
38
38
|
Cap2 provides methods for querying and modifying capabilities for both processes and files.
|
39
39
|
|
@@ -45,11 +45,18 @@ Cap2.process(1000) # Returns a Cap2::Process for the process with pid 100
|
|
45
45
|
Cap2.file('/sbin/init') # Returns a Cap2::File for the /sbin/init file
|
46
46
|
```
|
47
47
|
|
48
|
+
Querying Capabilities
|
49
|
+
---------------------
|
50
|
+
|
48
51
|
Capabilities are referenced using lower cased symbols, and without the CAP_ prefix (e.g. `:kill` represents CAP_KILL).
|
49
52
|
|
50
|
-
|
53
|
+
There are three methods defined on both `Cap2::Process` and `Cap2::File` for querying capabilities:
|
51
54
|
|
52
|
-
|
55
|
+
* `permitted?`
|
56
|
+
* `enabled?`
|
57
|
+
* `inheritable?`
|
58
|
+
|
59
|
+
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
60
|
|
54
61
|
```
|
55
62
|
# the init daemon - all caps permitted & enabled but not inheritable
|
@@ -63,7 +70,9 @@ init.enabled?(:kill, :chown) # => true
|
|
63
70
|
|
64
71
|
init.inheritable?(:chown) # => false
|
65
72
|
init.inheritable?(:fowner, :kill) # => false
|
73
|
+
```
|
66
74
|
|
75
|
+
```
|
67
76
|
# assume /bin/ping is using file capabilities to enable CAP_NET_RAW on exec
|
68
77
|
ping = Cap2.file('/bin/ping') # => #<Cap2::File @filename="/bin/ping">
|
69
78
|
|
@@ -75,15 +84,39 @@ ping.enabled? # => true
|
|
75
84
|
ping.inheritable?(:net_raw) # => false
|
76
85
|
```
|
77
86
|
|
78
|
-
|
87
|
+
### Why does Cap2::File#enabled? not take an arguement?
|
79
88
|
|
80
89
|
Under the hood, the file effective set is just a single bit. When enabled, any process which exec's the file will have the capabilities from it's resulting permitted set also in it's effective set.
|
81
90
|
|
82
|
-
|
91
|
+
Modifying File Capabilities
|
92
|
+
---------------------------
|
93
|
+
|
94
|
+
The file capability modification methods are:
|
83
95
|
|
84
|
-
|
96
|
+
* `permit(capabilities)`
|
97
|
+
* `unpermit(capabilities)`
|
98
|
+
* `allow_inherit(capabilities)`
|
99
|
+
* `disallow_inherit(capabilities)`
|
100
|
+
* `enable`
|
101
|
+
* `disable`
|
85
102
|
|
86
|
-
|
103
|
+
where `capabilities` can take any of the following forms:
|
104
|
+
|
105
|
+
```
|
106
|
+
# list of one or more symbols
|
107
|
+
(:chown)
|
108
|
+
(:mknod, :kill, :mac_admin)
|
109
|
+
|
110
|
+
# hash with an :only key
|
111
|
+
(:only => :fowner)
|
112
|
+
(:only => [:lease, :net_raw])
|
113
|
+
|
114
|
+
# hash with an :except key
|
115
|
+
(:except => :sys_time)
|
116
|
+
(:except => [:syslog, :fsetid])
|
117
|
+
```
|
118
|
+
|
119
|
+
### Permitting capabilities
|
87
120
|
|
88
121
|
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`:
|
89
122
|
|
@@ -103,6 +136,8 @@ file.unpermit(:chown, :fowner) # => true
|
|
103
136
|
file.permitted?(:mknod, :chown, :fowner) # => false
|
104
137
|
```
|
105
138
|
|
139
|
+
### Enabling capabilities
|
140
|
+
|
106
141
|
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`:
|
107
142
|
|
108
143
|
```
|
@@ -120,6 +155,8 @@ file.disable # => true
|
|
120
155
|
file.enabled? # => false
|
121
156
|
```
|
122
157
|
|
158
|
+
### Inheriting capabilities
|
159
|
+
|
123
160
|
To modify the inheritable capabilities of a file (i.e. the capabilities which will be ANDed with the inheritable set of any process that exec's the file to determine which capabilities are in the permitted set of the process), use `Cap2::File#allow_inherit` and `Cap2::File#disallow_inherit`:
|
124
161
|
|
125
162
|
```
|
@@ -136,7 +173,9 @@ file.disallow_inherit(:fowner) # => true
|
|
136
173
|
file.inheritable?(:fowner) # => false
|
137
174
|
```
|
138
175
|
|
139
|
-
|
176
|
+
### Clearing capabilities
|
177
|
+
|
178
|
+
To clear all capabilities for a file, use `Cap2::File#clear`:
|
140
179
|
|
141
180
|
```
|
142
181
|
Cap2.process.enabled?(:setfcap) # => true - needed to set file capabilities
|
@@ -158,7 +197,8 @@ file.inheritable?(:kill, :mknod) # => false
|
|
158
197
|
file.enabled? # => false
|
159
198
|
```
|
160
199
|
|
161
|
-
|
200
|
+
Modifying Process Capabilities
|
201
|
+
------------------------------
|
162
202
|
|
163
203
|
Cap2 can be used to enable / disable capabilities of the current Ruby process.
|
164
204
|
|
data/ext/cap2/cap2.c
CHANGED
@@ -79,6 +79,18 @@ VALUE cap2_caps_to_hash(cap_t cap_d) {
|
|
79
79
|
return caps;
|
80
80
|
}
|
81
81
|
|
82
|
+
VALUE cap2_allcaps(VALUE self) {
|
83
|
+
int i;
|
84
|
+
VALUE caps;
|
85
|
+
|
86
|
+
caps = rb_ary_new();
|
87
|
+
|
88
|
+
for(i = 0; i < __CAP_COUNT; i++)
|
89
|
+
rb_ary_push(caps, ID2SYM(rb_intern(cap2_caps[i].name)));
|
90
|
+
|
91
|
+
return caps;
|
92
|
+
}
|
93
|
+
|
82
94
|
/*
|
83
95
|
* Convert @pid stored in the given Process object to an int and return it.
|
84
96
|
*/
|
@@ -292,6 +304,7 @@ void Init_cap2(void) {
|
|
292
304
|
VALUE rb_cCap2Process;
|
293
305
|
|
294
306
|
rb_mCap2 = rb_define_module("Cap2");
|
307
|
+
rb_define_module_function(rb_mCap2, "allcaps", cap2_allcaps, 0);
|
295
308
|
|
296
309
|
rb_cCap2Process = rb_define_class_under(rb_mCap2, "Process", rb_cObject);
|
297
310
|
rb_define_method(rb_cCap2Process, "getcaps", cap2_process_getcaps, 0);
|
data/lib/cap2.so
CHANGED
Binary file
|
data/lib/cap2/file.rb
CHANGED
@@ -27,27 +27,27 @@ module Cap2
|
|
27
27
|
!@caps[:effective].empty?
|
28
28
|
end
|
29
29
|
|
30
|
-
# Permit processes executing this file to enable the given
|
30
|
+
# Permit processes executing this file to enable the given capabilities.
|
31
31
|
def permit(*capabilities)
|
32
|
-
@caps[:permitted].merge(capabilities)
|
32
|
+
@caps[:permitted].merge parse(capabilities)
|
33
33
|
save
|
34
34
|
end
|
35
35
|
|
36
|
-
# Dont permit processes executing this file to enable the given
|
36
|
+
# Dont permit processes executing this file to enable the given capabilities.
|
37
37
|
def unpermit(*capabilities)
|
38
|
-
@caps[:permitted].subtract(capabilities)
|
38
|
+
@caps[:permitted].subtract parse(capabilities)
|
39
39
|
save
|
40
40
|
end
|
41
41
|
|
42
|
-
# Allow processes executing this file to inherit the given
|
42
|
+
# Allow processes executing this file to inherit the given capabilities.
|
43
43
|
def allow_inherit(*capabilities)
|
44
|
-
@caps[:inheritable].merge(capabilities)
|
44
|
+
@caps[:inheritable].merge parse(capabilities)
|
45
45
|
save
|
46
46
|
end
|
47
47
|
|
48
|
-
# Dont allow processes executing this file to inherit the given
|
48
|
+
# Dont allow processes executing this file to inherit the given capabilities.
|
49
49
|
def disallow_inherit(*capabilities)
|
50
|
-
@caps[:inheritable].subtract(capabilities)
|
50
|
+
@caps[:inheritable].subtract parse(capabilities)
|
51
51
|
save
|
52
52
|
end
|
53
53
|
|
@@ -73,5 +73,29 @@ module Cap2
|
|
73
73
|
def reload
|
74
74
|
@caps = getcaps
|
75
75
|
end
|
76
|
+
|
77
|
+
def parse(caps)
|
78
|
+
if (options = caps.first).is_a? Hash
|
79
|
+
if caps.size > 1
|
80
|
+
raise(
|
81
|
+
ArgumentError,
|
82
|
+
'cannot pass both a hash and a list of capabilities'
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
if options.has_key?(:only) && !options.has_key?(:except)
|
87
|
+
Array(options[:only])
|
88
|
+
elsif options.has_key?(:except) && !options.has_key?(:only)
|
89
|
+
Cap2.allcaps - Array(options[:except])
|
90
|
+
else
|
91
|
+
raise(
|
92
|
+
ArgumentError,
|
93
|
+
"expected exactly one of [:only, :except], got #{options.keys}"
|
94
|
+
)
|
95
|
+
end
|
96
|
+
else
|
97
|
+
caps
|
98
|
+
end
|
99
|
+
end
|
76
100
|
end
|
77
101
|
end
|
data/lib/cap2/version.rb
CHANGED
data/spec/file_spec.rb
CHANGED
@@ -52,14 +52,50 @@ describe Cap2::File do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
describe '#permit' do
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
context 'with a list of capability symbols' do
|
56
|
+
specify do
|
57
|
+
expect { running_as_root('permit(:fowner, :kill)') }.to \
|
58
|
+
change { subject.permitted?(:fowner) }.from(false).to(true)
|
59
|
+
end
|
60
|
+
|
61
|
+
specify do
|
62
|
+
expect { running_as_root('permit(:fowner, :kill)') }.to \
|
63
|
+
change { subject.permitted?(:kill) }.from(false).to(true)
|
64
|
+
end
|
58
65
|
end
|
59
66
|
|
60
|
-
|
61
|
-
|
62
|
-
|
67
|
+
context 'with an :only option' do
|
68
|
+
specify do
|
69
|
+
expect { running_as_root('permit(:only => :fowner)') }.to \
|
70
|
+
change { subject.permitted?(:fowner) }.from(false).to(true)
|
71
|
+
end
|
72
|
+
|
73
|
+
specify do
|
74
|
+
expect { running_as_root('permit(:only => :fowner)') }.to_not \
|
75
|
+
change { subject.permitted?(:kill) }.from(false)
|
76
|
+
end
|
77
|
+
|
78
|
+
specify do
|
79
|
+
expect { running_as_root('permit(:only => [:fowner, :kill])') }.to \
|
80
|
+
change { subject.permitted?(:fowner, :kill) }.from(false).to(true)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with an :except option' do
|
85
|
+
specify do
|
86
|
+
expect { running_as_root('permit(:except => :fowner)') }.to \
|
87
|
+
change { subject.permitted?(:kill) }.from(false).to(true)
|
88
|
+
end
|
89
|
+
|
90
|
+
specify do
|
91
|
+
expect { running_as_root('permit(:except => :fowner)') }.to_not \
|
92
|
+
change { subject.permitted?(:fowner) }.from(false)
|
93
|
+
end
|
94
|
+
|
95
|
+
specify do
|
96
|
+
expect { running_as_root('permit(:except => [:fowner, :kill])') }.to_not \
|
97
|
+
change { subject.permitted?(:fowner, :kill) }.from(false)
|
98
|
+
end
|
63
99
|
end
|
64
100
|
end
|
65
101
|
|