mirror of
https://github.com/systemd/systemd.git
synced 2025-01-23 02:04:32 +03:00
Merge pull request #2760 from ronnychevalier/rc/core_no_new_privileges_seccompv3
core: set NoNewPrivileges for seccomp if we don't have CAP_SYS_ADMIN
This commit is contained in:
commit
68de79d6a4
@ -1563,6 +1563,7 @@ EXTRA_DIST += \
|
||||
test/test-execute/exec-passenvironment-repeated.service \
|
||||
test/test-execute/exec-passenvironment.service \
|
||||
test/test-execute/exec-group.service \
|
||||
test/test-execute/exec-group-nfsnobody.service \
|
||||
test/test-execute/exec-ignoresigpipe-no.service \
|
||||
test/test-execute/exec-ignoresigpipe-yes.service \
|
||||
test/test-execute/exec-personality-x86-64.service \
|
||||
@ -1578,7 +1579,10 @@ EXTRA_DIST += \
|
||||
test/test-execute/exec-systemcallfilter-failing.service \
|
||||
test/test-execute/exec-systemcallfilter-not-failing2.service \
|
||||
test/test-execute/exec-systemcallfilter-not-failing.service \
|
||||
test/test-execute/exec-systemcallfilter-system-user.service \
|
||||
test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service \
|
||||
test/test-execute/exec-user.service \
|
||||
test/test-execute/exec-user-nfsnobody.service \
|
||||
test/test-execute/exec-workingdirectory.service \
|
||||
test/test-execute/exec-umask-0177.service \
|
||||
test/test-execute/exec-umask-default.service \
|
||||
@ -1595,10 +1599,13 @@ EXTRA_DIST += \
|
||||
test/test-execute/exec-capabilityboundingset-reset.service \
|
||||
test/test-execute/exec-capabilityboundingset-simple.service \
|
||||
test/test-execute/exec-capabilityambientset.service \
|
||||
test/test-execute/exec-capabilityambientset-nfsnobody.service \
|
||||
test/test-execute/exec-capabilityambientset-merge.service \
|
||||
test/test-execute/exec-capabilityambientset-merge-nfsnobody.service \
|
||||
test/test-execute/exec-runtimedirectory.service \
|
||||
test/test-execute/exec-runtimedirectory-mode.service \
|
||||
test/test-execute/exec-runtimedirectory-owner.service \
|
||||
test/test-execute/exec-runtimedirectory-owner-nfsnobody.service \
|
||||
test/bus-policy/hello.conf \
|
||||
test/bus-policy/methods.conf \
|
||||
test/bus-policy/ownerships.conf \
|
||||
|
@ -1155,7 +1155,9 @@
|
||||
first character of the list is <literal>~</literal>, the
|
||||
effect is inverted: only the listed system calls will result
|
||||
in immediate process termination (blacklisting). If running in
|
||||
user mode and this option is used,
|
||||
user mode, or in system mode, but without the
|
||||
<constant>CAP_SYS_ADMIN</constant> capabiblity (e.g. setting
|
||||
<varname>User=nobody</varname>),
|
||||
<varname>NoNewPrivileges=yes</varname> is implied. This
|
||||
feature makes use of the Secure Computing Mode 2 interfaces of
|
||||
the kernel ('seccomp filtering') and is useful for enforcing a
|
||||
@ -1214,8 +1216,10 @@
|
||||
systems. The special <constant>native</constant> identifier
|
||||
implicitly maps to the native architecture of the system (or
|
||||
more strictly: to the architecture the system manager is
|
||||
compiled for). If running in user mode and this option is
|
||||
used, <varname>NoNewPrivileges=yes</varname> is implied. Note
|
||||
compiled for). If running in user mode, or in system mode,
|
||||
but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capabiblity (e.g. setting <varname>User=nobody</varname>),
|
||||
<varname>NoNewPrivileges=yes</varname> is implied. Note
|
||||
that setting this option to a non-empty list implies that
|
||||
<constant>native</constant> is included too. By default, this
|
||||
option is set to the empty list, i.e. no architecture system
|
||||
@ -1244,8 +1248,10 @@
|
||||
<function>socketpair()</function> (which creates connected
|
||||
AF_UNIX sockets only) are unaffected. Note that this option
|
||||
has no effect on 32-bit x86 and is ignored (but works
|
||||
correctly on x86-64). If running in user mode and this option
|
||||
is used, <varname>NoNewPrivileges=yes</varname> is implied. By
|
||||
correctly on x86-64). If running in user mode, or in system
|
||||
mode, but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capabiblity (e.g. setting <varname>User=nobody</varname>),
|
||||
<varname>NoNewPrivileges=yes</varname> is implied. By
|
||||
default, no restriction applies, all address families are
|
||||
accessible to processes. If assigned the empty string, any
|
||||
previous list changes are undone.</para>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
@ -1824,6 +1825,11 @@ static int exec_child(
|
||||
|
||||
if (params->apply_permissions) {
|
||||
|
||||
bool use_address_families = context->address_families_whitelist ||
|
||||
!set_isempty(context->address_families);
|
||||
bool use_syscall_filter = context->syscall_whitelist ||
|
||||
!set_isempty(context->syscall_filter) ||
|
||||
!set_isempty(context->syscall_archs);
|
||||
int secure_bits = context->secure_bits;
|
||||
|
||||
for (i = 0; i < _RLIMIT_MAX; i++) {
|
||||
@ -1890,15 +1896,15 @@ static int exec_child(
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (context->no_new_privileges)
|
||||
if (context->no_new_privileges ||
|
||||
(!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || use_syscall_filter)))
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
|
||||
*exit_status = EXIT_NO_NEW_PRIVILEGES;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SECCOMP
|
||||
if (context->address_families_whitelist ||
|
||||
!set_isempty(context->address_families)) {
|
||||
if (use_address_families) {
|
||||
r = apply_address_families(context);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_ADDRESS_FAMILIES;
|
||||
@ -1906,9 +1912,7 @@ static int exec_child(
|
||||
}
|
||||
}
|
||||
|
||||
if (context->syscall_whitelist ||
|
||||
!set_isempty(context->syscall_filter) ||
|
||||
!set_isempty(context->syscall_archs)) {
|
||||
if (use_syscall_filter) {
|
||||
r = apply_seccomp(context);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_SECCOMP;
|
||||
|
@ -130,18 +130,33 @@ static void test_exec_systemcallerrornumber(Manager *m) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_exec_systemcall_system_mode_with_user(Manager *m) {
|
||||
#ifdef HAVE_SECCOMP
|
||||
if (getpwnam("nobody"))
|
||||
test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
|
||||
else if (getpwnam("nfsnobody"))
|
||||
test(m, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED);
|
||||
else
|
||||
log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody/nfsnobody user: %m");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_exec_user(Manager *m) {
|
||||
if (getpwnam("nobody"))
|
||||
test(m, "exec-user.service", 0, CLD_EXITED);
|
||||
else if (getpwnam("nfsnobody"))
|
||||
test(m, "exec-user-nfsnobody.service", 0, CLD_EXITED);
|
||||
else
|
||||
log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m");
|
||||
log_error_errno(errno, "Skipping test_exec_user, could not find nobody/nfsnobody user: %m");
|
||||
}
|
||||
|
||||
static void test_exec_group(Manager *m) {
|
||||
if (getgrnam("nobody"))
|
||||
test(m, "exec-group.service", 0, CLD_EXITED);
|
||||
else if (getgrnam("nfsnobody"))
|
||||
test(m, "exec-group-nfsnobody.service", 0, CLD_EXITED);
|
||||
else
|
||||
log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m");
|
||||
log_error_errno(errno, "Skipping test_exec_group, could not find nobody/nfsnobody group: %m");
|
||||
}
|
||||
|
||||
static void test_exec_environment(Manager *m) {
|
||||
@ -204,8 +219,10 @@ static void test_exec_runtimedirectory(Manager *m) {
|
||||
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
|
||||
if (getgrnam("nobody"))
|
||||
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
|
||||
else if (getgrnam("nfsnobody"))
|
||||
test(m, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED);
|
||||
else
|
||||
log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m");
|
||||
log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody/nfsnobody group: %m");
|
||||
}
|
||||
|
||||
static void test_exec_capabilityboundingset(Manager *m) {
|
||||
@ -234,9 +251,15 @@ static void test_exec_capabilityambientset(Manager *m) {
|
||||
* 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);
|
||||
}
|
||||
if (getpwnam("nobody")) {
|
||||
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
|
||||
} else if (getpwnam("nfsnobody")) {
|
||||
test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
|
||||
test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
|
||||
} else
|
||||
log_error_errno(errno, "Skipping test_exec_capabilityambientset, could not find nobody/nfsnobody user: %m");
|
||||
} else
|
||||
log_error_errno(errno, "Skipping test_exec_capabilityambientset, the kernel does not support ambient capabilities: %m");
|
||||
}
|
||||
|
||||
static void test_exec_privatenetwork(Manager *m) {
|
||||
@ -267,8 +290,31 @@ static void test_exec_spec_interpolation(Manager *m) {
|
||||
test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
static int run_tests(ManagerRunningAs running_as, test_function_t *tests) {
|
||||
test_function_t *test = NULL;
|
||||
Manager *m = NULL;
|
||||
int r;
|
||||
|
||||
assert_se(tests);
|
||||
|
||||
r = manager_new(running_as, true, &m);
|
||||
if (MANAGER_SKIP_TEST(r)) {
|
||||
printf("Skipping test: manager_new: %s\n", strerror(-r));
|
||||
return EXIT_TEST_SKIP;
|
||||
}
|
||||
assert_se(r >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL) >= 0);
|
||||
|
||||
for (test = tests; test && *test; test++)
|
||||
(*test)(m);
|
||||
|
||||
manager_free(m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_function_t tests[] = {
|
||||
test_function_t user_tests[] = {
|
||||
test_exec_workingdirectory,
|
||||
test_exec_personality,
|
||||
test_exec_ignoresigpipe,
|
||||
@ -291,8 +337,10 @@ int main(int argc, char *argv[]) {
|
||||
test_exec_spec_interpolation,
|
||||
NULL,
|
||||
};
|
||||
test_function_t *test = NULL;
|
||||
Manager *m = NULL;
|
||||
test_function_t system_tests[] = {
|
||||
test_exec_systemcall_system_mode_with_user,
|
||||
NULL,
|
||||
};
|
||||
int r;
|
||||
|
||||
log_parse_environment();
|
||||
@ -317,18 +365,9 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(unsetenv("VAR2") == 0);
|
||||
assert_se(unsetenv("VAR3") == 0);
|
||||
|
||||
r = manager_new(MANAGER_USER, true, &m);
|
||||
if (MANAGER_SKIP_TEST(r)) {
|
||||
printf("Skipping test: manager_new: %s\n", strerror(-r));
|
||||
return EXIT_TEST_SKIP;
|
||||
}
|
||||
assert_se(r >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL) >= 0);
|
||||
r = run_tests(MANAGER_USER, user_tests);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
for (test = tests; test && *test; test++)
|
||||
(*test)(m);
|
||||
|
||||
manager_free(m);
|
||||
|
||||
return 0;
|
||||
return run_tests(MANAGER_SYSTEM, system_tests);
|
||||
}
|
||||
|
@ -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=nfsnobody
|
||||
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=nfsnobody
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
7
test/test-execute/exec-group-nfsnobody.service
Normal file
7
test/test-execute/exec-group-nfsnobody.service
Normal file
@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test for Group
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nfsnobody"'
|
||||
Type=oneshot
|
||||
Group=nfsnobody
|
@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nfsnobody"'
|
||||
Type=oneshot
|
||||
Group=nfsnobody
|
||||
User=root
|
||||
RuntimeDirectory=test-exec_runtimedirectory-owner
|
@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Test for SystemCallFilter in system mode with User set
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/echo "Foo bar"
|
||||
Type=oneshot
|
||||
User=nfsnobody
|
||||
SystemCallFilter=~read write open execve ioperm
|
||||
SystemCallFilter=ioctl
|
||||
SystemCallFilter=read write open execve
|
||||
SystemCallFilter=~ioperm
|
11
test/test-execute/exec-systemcallfilter-system-user.service
Normal file
11
test/test-execute/exec-systemcallfilter-system-user.service
Normal file
@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Test for SystemCallFilter in system mode with User set
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/echo "Foo bar"
|
||||
Type=oneshot
|
||||
User=nobody
|
||||
SystemCallFilter=~read write open execve ioperm
|
||||
SystemCallFilter=ioctl
|
||||
SystemCallFilter=read write open execve
|
||||
SystemCallFilter=~ioperm
|
7
test/test-execute/exec-user-nfsnobody.service
Normal file
7
test/test-execute/exec-user-nfsnobody.service
Normal file
@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test for User
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$USER" = "nfsnobody"'
|
||||
Type=oneshot
|
||||
User=nfsnobody
|
Loading…
x
Reference in New Issue
Block a user