tests: test ambient capabilities.
The ambient capability tests are only run if the kernel has support for ambient capabilities.
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/capability.h>
|
#include <sys/capability.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -66,8 +67,9 @@ static void show_capabilities(void) {
|
|||||||
cap_free(text);
|
cap_free(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_tests(void) {
|
static int setup_tests(bool *run_ambient) {
|
||||||
struct passwd *nobody;
|
struct passwd *nobody;
|
||||||
|
int r;
|
||||||
|
|
||||||
nobody = getpwnam("nobody");
|
nobody = getpwnam("nobody");
|
||||||
if (!nobody) {
|
if (!nobody) {
|
||||||
@@ -77,6 +79,18 @@ static int setup_tests(void) {
|
|||||||
test_uid = nobody->pw_uid;
|
test_uid = nobody->pw_uid;
|
||||||
test_gid = nobody->pw_gid;
|
test_gid = nobody->pw_gid;
|
||||||
|
|
||||||
|
*run_ambient = false;
|
||||||
|
|
||||||
|
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
|
||||||
|
|
||||||
|
/* There's support for PR_CAP_AMBIENT if the prctl() call
|
||||||
|
* succeeded or error code was something else than EINVAL. The
|
||||||
|
* EINVAL check should be good enough to rule out false
|
||||||
|
* positives. */
|
||||||
|
|
||||||
|
if (r >= 0 || errno != EINVAL)
|
||||||
|
*run_ambient = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,8 +154,53 @@ static void test_have_effective_cap(void) {
|
|||||||
assert_se(!have_effective_cap(CAP_CHOWN));
|
assert_se(!have_effective_cap(CAP_CHOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_update_inherited_set(void) {
|
||||||
|
cap_t caps;
|
||||||
|
uint64_t set = 0;
|
||||||
|
cap_flag_value_t fv;
|
||||||
|
|
||||||
|
caps = cap_get_proc();
|
||||||
|
assert_se(caps);
|
||||||
|
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
|
||||||
|
assert(fv == CAP_CLEAR);
|
||||||
|
|
||||||
|
set = (UINT64_C(1) << CAP_CHOWN);
|
||||||
|
|
||||||
|
assert_se(!capability_update_inherited_set(caps, set));
|
||||||
|
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
|
||||||
|
assert(fv == CAP_SET);
|
||||||
|
|
||||||
|
cap_free(caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_set_ambient_caps(void) {
|
||||||
|
cap_t caps;
|
||||||
|
uint64_t set = 0;
|
||||||
|
cap_flag_value_t fv;
|
||||||
|
|
||||||
|
caps = cap_get_proc();
|
||||||
|
assert_se(caps);
|
||||||
|
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
|
||||||
|
assert(fv == CAP_CLEAR);
|
||||||
|
cap_free(caps);
|
||||||
|
|
||||||
|
assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0);
|
||||||
|
|
||||||
|
set = (UINT64_C(1) << CAP_CHOWN);
|
||||||
|
|
||||||
|
assert_se(!capability_ambient_set_apply(set, true));
|
||||||
|
|
||||||
|
caps = cap_get_proc();
|
||||||
|
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
|
||||||
|
assert(fv == CAP_SET);
|
||||||
|
cap_free(caps);
|
||||||
|
|
||||||
|
assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int r;
|
int r;
|
||||||
|
bool run_ambient;
|
||||||
|
|
||||||
log_parse_environment();
|
log_parse_environment();
|
||||||
log_open();
|
log_open();
|
||||||
@@ -149,14 +208,19 @@ int main(int argc, char *argv[]) {
|
|||||||
if (getuid() != 0)
|
if (getuid() != 0)
|
||||||
return EXIT_TEST_SKIP;
|
return EXIT_TEST_SKIP;
|
||||||
|
|
||||||
r = setup_tests();
|
r = setup_tests(&run_ambient);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -r;
|
return -r;
|
||||||
|
|
||||||
show_capabilities();
|
show_capabilities();
|
||||||
|
|
||||||
test_drop_privileges();
|
test_drop_privileges();
|
||||||
|
test_update_inherited_set();
|
||||||
|
|
||||||
fork_test(test_have_effective_cap);
|
fork_test(test_have_effective_cap);
|
||||||
|
|
||||||
|
if (run_ambient)
|
||||||
|
fork_test(test_set_ambient_caps);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
@@ -224,6 +225,20 @@ static void test_exec_capabilityboundingset(Manager *m) {
|
|||||||
test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
|
test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_exec_capabilityambientset(Manager *m) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Check if the kernel has support for ambient capabilities. Run
|
||||||
|
* the tests only if that's the case. Clearing all ambient
|
||||||
|
* capabilities is fine, since we are expecting them to be unset
|
||||||
|
* in the first place for the tests. */
|
||||||
|
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
|
||||||
|
if (r >= 0 || errno != EINVAL) {
|
||||||
|
test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
|
||||||
|
test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void test_exec_privatenetwork(Manager *m) {
|
static void test_exec_privatenetwork(Manager *m) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -266,6 +281,7 @@ int main(int argc, char *argv[]) {
|
|||||||
test_exec_umask,
|
test_exec_umask,
|
||||||
test_exec_runtimedirectory,
|
test_exec_runtimedirectory,
|
||||||
test_exec_capabilityboundingset,
|
test_exec_capabilityboundingset,
|
||||||
|
test_exec_capabilityambientset,
|
||||||
test_exec_oomscoreadjust,
|
test_exec_oomscoreadjust,
|
||||||
test_exec_ioschedulingclass,
|
test_exec_ioschedulingclass,
|
||||||
NULL,
|
NULL,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for AmbientCapabilities
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
||||||
|
Type=oneshot
|
||||||
|
User=nobody
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN
|
||||||
|
AmbientCapabilities=CAP_NET_RAW
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for AmbientCapabilities
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
||||||
|
Type=oneshot
|
||||||
|
User=nobody
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
||||||
Reference in New Issue
Block a user