Skip to content

Commit 70d7aea

Browse files
committed
tests: test ambient capabilities.
The ambient capability tests are only run if the kernel has support for ambient capabilities.
1 parent 755d4b6 commit 70d7aea

File tree

4 files changed

+99
-2
lines changed

4 files changed

+99
-2
lines changed

src/test/test-capability.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <netinet/in.h>
2121
#include <pwd.h>
2222
#include <sys/capability.h>
23+
#include <sys/prctl.h>
2324
#include <sys/socket.h>
2425
#include <sys/wait.h>
2526
#include <unistd.h>
@@ -66,8 +67,9 @@ static void show_capabilities(void) {
6667
cap_free(text);
6768
}
6869

69-
static int setup_tests(void) {
70+
static int setup_tests(bool *run_ambient) {
7071
struct passwd *nobody;
72+
int r;
7173

7274
nobody = getpwnam("nobody");
7375
if (!nobody) {
@@ -77,6 +79,18 @@ static int setup_tests(void) {
7779
test_uid = nobody->pw_uid;
7880
test_gid = nobody->pw_gid;
7981

82+
*run_ambient = false;
83+
84+
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
85+
86+
/* There's support for PR_CAP_AMBIENT if the prctl() call
87+
* succeeded or error code was something else than EINVAL. The
88+
* EINVAL check should be good enough to rule out false
89+
* positives. */
90+
91+
if (r >= 0 || errno != EINVAL)
92+
*run_ambient = true;
93+
8094
return 0;
8195
}
8296

@@ -140,23 +154,73 @@ static void test_have_effective_cap(void) {
140154
assert_se(!have_effective_cap(CAP_CHOWN));
141155
}
142156

157+
static void test_update_inherited_set(void) {
158+
cap_t caps;
159+
uint64_t set = 0;
160+
cap_flag_value_t fv;
161+
162+
caps = cap_get_proc();
163+
assert_se(caps);
164+
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
165+
assert(fv == CAP_CLEAR);
166+
167+
set = (UINT64_C(1) << CAP_CHOWN);
168+
169+
assert_se(!capability_update_inherited_set(caps, set));
170+
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
171+
assert(fv == CAP_SET);
172+
173+
cap_free(caps);
174+
}
175+
176+
static void test_set_ambient_caps(void) {
177+
cap_t caps;
178+
uint64_t set = 0;
179+
cap_flag_value_t fv;
180+
181+
caps = cap_get_proc();
182+
assert_se(caps);
183+
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
184+
assert(fv == CAP_CLEAR);
185+
cap_free(caps);
186+
187+
assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0);
188+
189+
set = (UINT64_C(1) << CAP_CHOWN);
190+
191+
assert_se(!capability_ambient_set_apply(set, true));
192+
193+
caps = cap_get_proc();
194+
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
195+
assert(fv == CAP_SET);
196+
cap_free(caps);
197+
198+
assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1);
199+
}
200+
143201
int main(int argc, char *argv[]) {
144202
int r;
203+
bool run_ambient;
145204

146205
log_parse_environment();
147206
log_open();
148207

149208
if (getuid() != 0)
150209
return EXIT_TEST_SKIP;
151210

152-
r = setup_tests();
211+
r = setup_tests(&run_ambient);
153212
if (r < 0)
154213
return -r;
155214

156215
show_capabilities();
157216

158217
test_drop_privileges();
218+
test_update_inherited_set();
219+
159220
fork_test(test_have_effective_cap);
160221

222+
if (run_ambient)
223+
fork_test(test_set_ambient_caps);
224+
161225
return 0;
162226
}

src/test/test-execute.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <grp.h>
2121
#include <pwd.h>
2222
#include <stdio.h>
23+
#include <sys/prctl.h>
2324
#include <sys/types.h>
2425

2526
#include "fileio.h"
@@ -224,6 +225,20 @@ static void test_exec_capabilityboundingset(Manager *m) {
224225
test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
225226
}
226227

228+
static void test_exec_capabilityambientset(Manager *m) {
229+
int r;
230+
231+
/* Check if the kernel has support for ambient capabilities. Run
232+
* the tests only if that's the case. Clearing all ambient
233+
* capabilities is fine, since we are expecting them to be unset
234+
* in the first place for the tests. */
235+
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
236+
if (r >= 0 || errno != EINVAL) {
237+
test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
238+
test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
239+
}
240+
}
241+
227242
static void test_exec_privatenetwork(Manager *m) {
228243
int r;
229244

@@ -266,6 +281,7 @@ int main(int argc, char *argv[]) {
266281
test_exec_umask,
267282
test_exec_runtimedirectory,
268283
test_exec_capabilityboundingset,
284+
test_exec_capabilityambientset,
269285
test_exec_oomscoreadjust,
270286
test_exec_ioschedulingclass,
271287
NULL,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Unit]
2+
Description=Test for AmbientCapabilities
3+
4+
[Service]
5+
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
6+
Type=oneshot
7+
User=nobody
8+
AmbientCapabilities=CAP_NET_ADMIN
9+
AmbientCapabilities=CAP_NET_RAW
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Unit]
2+
Description=Test for AmbientCapabilities
3+
4+
[Service]
5+
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
6+
Type=oneshot
7+
User=nobody
8+
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW

0 commit comments

Comments
 (0)