Compare commits

..

14 Commits

Author SHA1 Message Date
Lennart Poettering f0bfae7265
Merge pull request #14037 from poettering/machinectl-pw-agent
spawn ask pw tty agent from "machinectl start"
2019-11-15 16:59:49 +01:00
Lennart Poettering 8af381679d
Merge pull request #13940 from keur/protect_kernel_logs
Add ProtectKernelLogs to systemd.exec
2019-11-15 16:26:10 +01:00
Lennart Poettering e41e9ba8bf machinectl: spawn ask password agent on "start"
We start units in the background, hence it is wise to also have the
ask pasword agent around.

Fixes: #13587
2019-11-15 11:12:34 +01:00
Lennart Poettering c59e2ec696 ask-password-agent: introduce ask_password_agent_open_if_enabled()
This makes the ask-password agent handling more alike the polkit agent
handling again, and introduces ask_password_agent_open_if_enabled() that
works just like the already existing polkit_agent_open_if_enabled().
2019-11-15 11:11:52 +01:00
Lennart Poettering 385d581b74 polkit-agent: don't use an inline function
This is long enough to just be a regular function, and is never called
in inner loops, let's hence just make this a plain function.
2019-11-15 11:11:14 +01:00
Kevin Kuehler 82dce83b19 systemd-analyze: Add ProtectKernelLogs to security 2019-11-15 00:59:54 -08:00
Kevin Kuehler 6168ae5840 units: set ProtectKernelLogs=yes on relevant units
We set ProtectKernelLogs=yes on all long running services except for
udevd, since it accesses /dev/kmsg, and journald, since it calls syslog
and accesses /dev/kmsg.
2019-11-15 00:59:54 -08:00
Kevin Kuehler 806aea3879 test-namespace: Add test for ProtectKernelLogs= 2019-11-15 00:59:51 -08:00
Kevin Kuehler d916e35b9f man: Add description for ProtectKernelLogs= 2019-11-14 13:31:06 -08:00
Kevin Kuehler 97d05f3b70 test/test-seccomp: add test_protect_syslog 2019-11-14 13:31:03 -08:00
Kevin Kuehler 94a7b2759d core: ProtectKernelLogs= mask kmsg in proc and sys
Block access to /dev/kmsg and /proc/kmsg when ProtectKernelLogs is set.
2019-11-14 12:58:43 -08:00
Kevin Kuehler 07cab0f72b tests: Add capability tests for ProtectKernelLogs 2019-11-11 12:12:02 -08:00
Kevin Kuehler 8470304018 core: Add ProtectKernelLogs
If seccomp is enabled, load the SYSCALL_FILTER_SET_SYSLOG into the
seccomp filter set. Drop the CAP_SYSLOG capability.
2019-11-11 12:12:02 -08:00
Kevin Kuehler 620dbdd248 shared: Add ProtectKernelLogs property
Add seccomp_protect_syslog, which adds a filter rule for the syslog
system call.
2019-11-11 12:11:56 -08:00
36 changed files with 301 additions and 38 deletions

View File

@ -402,11 +402,11 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>, <varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>,
<varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>, <varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
<varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>, <varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
<varname>ProtectKernelModules=</varname>, <varname>MemoryDenyWriteExecute=</varname>, <varname>ProtectKernelModules=</varname>, <varname>ProtectKernelLogs=</varname>,
<varname>RestrictRealtime=</varname>, <varname>RestrictSUIDSGID=</varname>, <varname>MemoryDenyWriteExecute=</varname>, <varname>RestrictRealtime=</varname>,
<varname>DynamicUser=</varname> or <varname>LockPersonality=</varname> are specified. Note that even <varname>RestrictSUIDSGID=</varname>, <varname>DynamicUser=</varname> or <varname>LockPersonality=</varname>
if this setting is overridden by them, <command>systemctl show</command> shows the original value of are specified. Note that even if this setting is overridden by them, <command>systemctl show</command> shows the
this setting. Also see <ulink original value of this setting. Also see <ulink
url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges
Flag</ulink>.</para></listitem> Flag</ulink>.</para></listitem>
</varlistentry> </varlistentry>
@ -1321,6 +1321,22 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
<xi:include href="system-only.xml" xpointer="singular"/></listitem> <xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ProtectKernelLogs=</varname></term>
<listitem><para>Takes a boolean argument. If true, access to the kernel log ring buffer will be denied. It is
recommended to turn this on for most services that do not need to read from or write to the kernel log ring
buffer. Enabling this option removes <constant>CAP_SYSLOG</constant> from the capability bounding set for this
unit, and installs a system call filter to block the
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call (not to be confused with the libc API
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for userspace logging). The kernel exposes its log buffer to userspace via <filename>/dev/kmsg</filename> and
<filename>/proc/kmsg</filename>. If enabled, these are made inaccessible to all the processes in the unit.</para>
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>ProtectControlGroups=</varname></term> <term><varname>ProtectControlGroups=</varname></term>
@ -1772,8 +1788,8 @@ SystemCallErrorNumber=EPERM</programlisting>
mappings. Specifically these are the options <varname>PrivateTmp=</varname>, mappings. Specifically these are the options <varname>PrivateTmp=</varname>,
<varname>PrivateDevices=</varname>, <varname>ProtectSystem=</varname>, <varname>ProtectHome=</varname>, <varname>PrivateDevices=</varname>, <varname>ProtectSystem=</varname>, <varname>ProtectHome=</varname>,
<varname>ProtectKernelTunables=</varname>, <varname>ProtectControlGroups=</varname>, <varname>ProtectKernelTunables=</varname>, <varname>ProtectControlGroups=</varname>,
<varname>ReadOnlyPaths=</varname>, <varname>InaccessiblePaths=</varname> and <varname>ProtectKernelLogs=</varname>, <varname>ReadOnlyPaths=</varname>,
<varname>ReadWritePaths=</varname>.</para></listitem> <varname>InaccessiblePaths=</varname> and <varname>ReadWritePaths=</varname>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -64,6 +64,7 @@ struct security_info {
bool protect_control_groups; bool protect_control_groups;
bool protect_kernel_modules; bool protect_kernel_modules;
bool protect_kernel_tunables; bool protect_kernel_tunables;
bool protect_kernel_logs;
char *protect_home; char *protect_home;
char *protect_system; char *protect_system;
@ -772,6 +773,16 @@ static const struct security_assessor security_assessor_table[] = {
.assess = assess_bool, .assess = assess_bool,
.offset = offsetof(struct security_info, protect_kernel_tunables), .offset = offsetof(struct security_info, protect_kernel_tunables),
}, },
{
.id = "ProtectKernelLogs=",
.description_good = "Service cannot read from or write to the kernel log ring buffer",
.description_bad = "Service may read from or write to the kernel log ring buffer",
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelLogs=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
.offset = offsetof(struct security_info, protect_kernel_logs),
},
{ {
.id = "ProtectHome=", .id = "ProtectHome=",
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHome=", .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHome=",
@ -1906,6 +1917,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
{ "ProtectHostname", "b", NULL, offsetof(struct security_info, protect_hostname) }, { "ProtectHostname", "b", NULL, offsetof(struct security_info, protect_hostname) },
{ "ProtectKernelModules", "b", NULL, offsetof(struct security_info, protect_kernel_modules) }, { "ProtectKernelModules", "b", NULL, offsetof(struct security_info, protect_kernel_modules) },
{ "ProtectKernelTunables", "b", NULL, offsetof(struct security_info, protect_kernel_tunables) }, { "ProtectKernelTunables", "b", NULL, offsetof(struct security_info, protect_kernel_tunables) },
{ "ProtectKernelLogs", "b", NULL, offsetof(struct security_info, protect_kernel_logs) },
{ "ProtectSystem", "s", NULL, offsetof(struct security_info, protect_system) }, { "ProtectSystem", "s", NULL, offsetof(struct security_info, protect_system) },
{ "RemoveIPC", "b", NULL, offsetof(struct security_info, remove_ipc) }, { "RemoveIPC", "b", NULL, offsetof(struct security_info, remove_ipc) },
{ "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 }, { "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 },
@ -1980,6 +1992,9 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
if (info->protect_kernel_modules) if (info->protect_kernel_modules)
info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE); info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE);
if (info->protect_kernel_logs)
info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYSLOG);
if (info->private_devices) if (info->private_devices)
info->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) | info->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) |
(UINT64_C(1) << CAP_SYS_RAWIO)); (UINT64_C(1) << CAP_SYS_RAWIO));

View File

@ -783,6 +783,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectKernelTunables", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_tunables), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ProtectKernelTunables", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_tunables), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectKernelModules", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_modules), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ProtectKernelModules", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_modules), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectKernelLogs", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_logs), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectControlGroups", "b", bus_property_get_bool, offsetof(ExecContext, protect_control_groups), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ProtectControlGroups", "b", bus_property_get_bool, offsetof(ExecContext, protect_control_groups), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
@ -1274,6 +1275,9 @@ int bus_exec_context_set_transient_property(
if (streq(name, "ProtectKernelModules")) if (streq(name, "ProtectKernelModules"))
return bus_set_transient_bool(u, name, &c->protect_kernel_modules, message, flags, error); return bus_set_transient_bool(u, name, &c->protect_kernel_modules, message, flags, error);
if (streq(name, "ProtectKernelLogs"))
return bus_set_transient_bool(u, name, &c->protect_kernel_logs, message, flags, error);
if (streq(name, "ProtectControlGroups")) if (streq(name, "ProtectControlGroups"))
return bus_set_transient_bool(u, name, &c->protect_control_groups, message, flags, error); return bus_set_transient_bool(u, name, &c->protect_control_groups, message, flags, error);

View File

@ -1396,6 +1396,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
exec_context_restrict_namespaces_set(c) || exec_context_restrict_namespaces_set(c) ||
c->protect_kernel_tunables || c->protect_kernel_tunables ||
c->protect_kernel_modules || c->protect_kernel_modules ||
c->protect_kernel_logs ||
c->private_devices || c->private_devices ||
context_has_syscall_filters(c) || context_has_syscall_filters(c) ||
!set_isempty(c->syscall_archs) || !set_isempty(c->syscall_archs) ||
@ -1542,6 +1543,19 @@ static int apply_protect_kernel_modules(const Unit *u, const ExecContext *c) {
return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM), false); return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM), false);
} }
static int apply_protect_kernel_logs(const Unit *u, const ExecContext *c) {
assert(u);
assert(c);
if (!c->protect_kernel_logs)
return 0;
if (skip_seccomp_unavailable(u, "ProtectKernelLogs="))
return 0;
return seccomp_protect_syslog();
}
static int apply_private_devices(const Unit *u, const ExecContext *c) { static int apply_private_devices(const Unit *u, const ExecContext *c) {
assert(u); assert(u);
assert(c); assert(c);
@ -1858,6 +1872,7 @@ static bool exec_needs_mount_namespace(
context->protect_home != PROTECT_HOME_NO || context->protect_home != PROTECT_HOME_NO ||
context->protect_kernel_tunables || context->protect_kernel_tunables ||
context->protect_kernel_modules || context->protect_kernel_modules ||
context->protect_kernel_logs ||
context->protect_control_groups) context->protect_control_groups)
return true; return true;
@ -2493,6 +2508,7 @@ static int apply_mount_namespace(
.protect_control_groups = context->protect_control_groups, .protect_control_groups = context->protect_control_groups,
.protect_kernel_tunables = context->protect_kernel_tunables, .protect_kernel_tunables = context->protect_kernel_tunables,
.protect_kernel_modules = context->protect_kernel_modules, .protect_kernel_modules = context->protect_kernel_modules,
.protect_kernel_logs = context->protect_kernel_logs,
.protect_hostname = context->protect_hostname, .protect_hostname = context->protect_hostname,
.mount_apivfs = context->mount_apivfs, .mount_apivfs = context->mount_apivfs,
.private_mounts = context->private_mounts, .private_mounts = context->private_mounts,
@ -3679,6 +3695,12 @@ static int exec_child(
return log_unit_error_errno(unit, r, "Failed to apply module loading restrictions: %m"); return log_unit_error_errno(unit, r, "Failed to apply module loading restrictions: %m");
} }
r = apply_protect_kernel_logs(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
return log_unit_error_errno(unit, r, "Failed to apply kernel log restrictions: %m");
}
r = apply_private_devices(unit, context); r = apply_private_devices(unit, context);
if (r < 0) { if (r < 0) {
*exit_status = EXIT_SECCOMP; *exit_status = EXIT_SECCOMP;
@ -4318,6 +4340,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
"%sPrivateDevices: %s\n" "%sPrivateDevices: %s\n"
"%sProtectKernelTunables: %s\n" "%sProtectKernelTunables: %s\n"
"%sProtectKernelModules: %s\n" "%sProtectKernelModules: %s\n"
"%sProtectKernelLogs: %s\n"
"%sProtectControlGroups: %s\n" "%sProtectControlGroups: %s\n"
"%sPrivateNetwork: %s\n" "%sPrivateNetwork: %s\n"
"%sPrivateUsers: %s\n" "%sPrivateUsers: %s\n"
@ -4338,6 +4361,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->private_devices), prefix, yes_no(c->private_devices),
prefix, yes_no(c->protect_kernel_tunables), prefix, yes_no(c->protect_kernel_tunables),
prefix, yes_no(c->protect_kernel_modules), prefix, yes_no(c->protect_kernel_modules),
prefix, yes_no(c->protect_kernel_logs),
prefix, yes_no(c->protect_control_groups), prefix, yes_no(c->protect_control_groups),
prefix, yes_no(c->private_network), prefix, yes_no(c->private_network),
prefix, yes_no(c->private_users), prefix, yes_no(c->private_users),

View File

@ -257,6 +257,7 @@ struct ExecContext {
bool private_mounts; bool private_mounts;
bool protect_kernel_tunables; bool protect_kernel_tunables;
bool protect_kernel_modules; bool protect_kernel_modules;
bool protect_kernel_logs;
bool protect_control_groups; bool protect_control_groups;
ProtectSystem protect_system; ProtectSystem protect_system;
ProtectHome protect_home; ProtectHome protect_home;

View File

@ -115,6 +115,7 @@ $1.PrivateTmp, config_parse_bool, 0,
$1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices) $1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices)
$1.ProtectKernelTunables, config_parse_bool, 0, offsetof($1, exec_context.protect_kernel_tunables) $1.ProtectKernelTunables, config_parse_bool, 0, offsetof($1, exec_context.protect_kernel_tunables)
$1.ProtectKernelModules, config_parse_bool, 0, offsetof($1, exec_context.protect_kernel_modules) $1.ProtectKernelModules, config_parse_bool, 0, offsetof($1, exec_context.protect_kernel_modules)
$1.ProtectKernelLogs, config_parse_bool, 0, offsetof($1, exec_context.protect_kernel_logs)
$1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups) $1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups)
$1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path) $1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path)
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)

View File

@ -109,6 +109,12 @@ static const MountEntry protect_kernel_modules_table[] = {
{ "/usr/lib/modules", INACCESSIBLE, true }, { "/usr/lib/modules", INACCESSIBLE, true },
}; };
/* ProtectKernelLogs= option */
static const MountEntry protect_kernel_logs_table[] = {
{ "/proc/kmsg", INACCESSIBLE, true },
{ "/dev/kmsg", INACCESSIBLE, true },
};
/* /*
* ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of * ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
* system should be protected by ProtectSystem= * system should be protected by ProtectSystem=
@ -1147,8 +1153,9 @@ static size_t namespace_calculate_mounts(
n_temporary_filesystems + n_temporary_filesystems +
ns_info->private_dev + ns_info->private_dev +
(ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) + (ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
(ns_info->protect_control_groups ? 1 : 0) +
(ns_info->protect_kernel_modules ? ELEMENTSOF(protect_kernel_modules_table) : 0) + (ns_info->protect_kernel_modules ? ELEMENTSOF(protect_kernel_modules_table) : 0) +
(ns_info->protect_kernel_logs ? ELEMENTSOF(protect_kernel_logs_table) : 0) +
(ns_info->protect_control_groups ? 1 : 0) +
protect_home_cnt + protect_system_cnt + protect_home_cnt + protect_system_cnt +
(ns_info->protect_hostname ? 2 : 0) + (ns_info->protect_hostname ? 2 : 0) +
(namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0); (namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0);
@ -1319,6 +1326,12 @@ int setup_namespace(
goto finish; goto finish;
} }
if (ns_info->protect_kernel_logs) {
r = append_static_mounts(&m, protect_kernel_logs_table, ELEMENTSOF(protect_kernel_logs_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
}
if (ns_info->protect_control_groups) { if (ns_info->protect_control_groups) {
*(m++) = (MountEntry) { *(m++) = (MountEntry) {
.path_const = "/sys/fs/cgroup", .path_const = "/sys/fs/cgroup",

View File

@ -51,6 +51,7 @@ struct NamespaceInfo {
bool protect_control_groups:1; bool protect_control_groups:1;
bool protect_kernel_tunables:1; bool protect_kernel_tunables:1;
bool protect_kernel_modules:1; bool protect_kernel_modules:1;
bool protect_kernel_logs:1;
bool mount_apivfs:1; bool mount_apivfs:1;
bool protect_hostname:1; bool protect_hostname:1;
}; };

View File

@ -4269,6 +4269,9 @@ int unit_patch_contexts(Unit *u) {
if (ec->protect_kernel_modules) if (ec->protect_kernel_modules)
ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE); ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE);
if (ec->protect_kernel_logs)
ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYSLOG);
if (ec->dynamic_user) { if (ec->dynamic_user) {
if (!ec->user) { if (!ec->user) {
r = user_from_unit_name(u, &ec->user); r = user_from_unit_name(u, &ec->user);

View File

@ -46,6 +46,7 @@
#include "sigbus.h" #include "sigbus.h"
#include "signal-util.h" #include "signal-util.h"
#include "sort-util.h" #include "sort-util.h"
#include "spawn-ask-password-agent.h"
#include "spawn-polkit-agent.h" #include "spawn-polkit-agent.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "string-table.h" #include "string-table.h"
@ -1722,6 +1723,7 @@ static int start_machine(int argc, char *argv[], void *userdata) {
assert(bus); assert(bus);
polkit_agent_open_if_enabled(arg_transport, arg_ask_password); polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
r = bus_wait_for_jobs_new(bus, &w); r = bus_wait_for_jobs_new(bus, &w);
if (r < 0) if (r < 0)

View File

@ -818,8 +818,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts", "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
"NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime", "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
"DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules", "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
"ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality", "ProtectKernelLogs", "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork",
"ProtectHostname", "RestrictSUIDSGID")) "LockPersonality", "ProtectHostname", "RestrictSUIDSGID"))
return bus_append_parse_boolean(m, field, eq); return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, if (STR_IN_SET(field,

View File

@ -1281,6 +1281,38 @@ int seccomp_protect_sysctl(void) {
return 0; return 0;
} }
int seccomp_protect_syslog(void) {
uint32_t arch;
int r;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
if (r < 0)
return r;
r = seccomp_rule_add_exact(
seccomp,
SCMP_ACT_ERRNO(EPERM),
SCMP_SYS(syslog),
0);
if (r < 0) {
log_debug_errno(r, "Failed to add syslog() rule for architecture %s, skipping %m", seccomp_arch_to_string(arch));
continue;
}
r = seccomp_load(seccomp);
if (ERRNO_IS_SECCOMP_FATAL(r))
return r;
if (r < 0)
log_debug_errno(r, "Failed to install syslog protection rules for architecture %s, skipping %m", seccomp_arch_to_string(arch));
}
return 0;
}
int seccomp_restrict_address_families(Set *address_families, bool whitelist) { int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
uint32_t arch; uint32_t arch;
int r; int r;

View File

@ -82,6 +82,7 @@ int seccomp_parse_syscall_filter(
int seccomp_restrict_archs(Set *archs); int seccomp_restrict_archs(Set *archs);
int seccomp_restrict_namespaces(unsigned long retain); int seccomp_restrict_namespaces(unsigned long retain);
int seccomp_protect_sysctl(void); int seccomp_protect_sysctl(void);
int seccomp_protect_syslog(void);
int seccomp_restrict_address_families(Set *address_families, bool whitelist); int seccomp_restrict_address_families(Set *address_families, bool whitelist);
int seccomp_restrict_realtime(void); int seccomp_restrict_realtime(void);
int seccomp_memory_deny_write_execute(void); int seccomp_memory_deny_write_execute(void);

View File

@ -46,3 +46,16 @@ void ask_password_agent_close(void) {
(void) wait_for_terminate(agent_pid, NULL); (void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0; agent_pid = 0;
} }
int ask_password_agent_open_if_enabled(BusTransport transport, bool ask_password) {
/* Open the ask password agent as a child process if necessary */
if (transport != BUS_TRANSPORT_LOCAL)
return 0;
if (!ask_password)
return 0;
return ask_password_agent_open();
}

View File

@ -1,5 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once #pragma once
#include <stdbool.h>
#include "bus-util.h"
int ask_password_agent_open(void); int ask_password_agent_open(void);
void ask_password_agent_close(void); void ask_password_agent_close(void);
int ask_password_agent_open_if_enabled(BusTransport transport, bool ask_password);

View File

@ -83,3 +83,16 @@ void polkit_agent_close(void) {
} }
#endif #endif
int polkit_agent_open_if_enabled(BusTransport transport, bool ask_password) {
/* Open the polkit agent as a child process if necessary */
if (transport != BUS_TRANSPORT_LOCAL)
return 0;
if (!ask_password)
return 0;
return polkit_agent_open();
}

View File

@ -1,22 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once #pragma once
#include <stdbool.h>
#include "bus-util.h" #include "bus-util.h"
int polkit_agent_open(void); int polkit_agent_open(void);
void polkit_agent_close(void); void polkit_agent_close(void);
static inline int polkit_agent_open_if_enabled( int polkit_agent_open_if_enabled(BusTransport transport, bool ask_password);
BusTransport transport,
bool ask_password) {
/* Open the polkit agent as a child process if necessary */
if (transport != BUS_TRANSPORT_LOCAL)
return 0;
if (!ask_password)
return 0;
return polkit_agent_open();
}

View File

@ -236,22 +236,16 @@ static void release_busses(void) {
buses[w] = sd_bus_flush_close_unref(buses[w]); buses[w] = sd_bus_flush_close_unref(buses[w]);
} }
static void ask_password_agent_open_if_enabled(void) { static void ask_password_agent_open_maybe(void) {
/* Open the password agent as a child process if necessary */ /* Open the password agent as a child process if necessary */
if (arg_dry_run) if (arg_dry_run)
return; return;
if (!arg_ask_password)
return;
if (arg_scope != UNIT_FILE_SYSTEM) if (arg_scope != UNIT_FILE_SYSTEM)
return; return;
if (arg_transport != BUS_TRANSPORT_LOCAL) ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
return;
ask_password_agent_open();
} }
static void polkit_agent_open_maybe(void) { static void polkit_agent_open_maybe(void) {
@ -3071,7 +3065,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
ask_password_agent_open_if_enabled(); ask_password_agent_open_maybe();
polkit_agent_open_maybe(); polkit_agent_open_maybe();
if (arg_action == ACTION_SYSTEMCTL) { if (arg_action == ACTION_SYSTEMCTL) {

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include <fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -9,7 +10,9 @@
#include "process-util.h" #include "process-util.h"
#include "string-util.h" #include "string-util.h"
#include "tests.h" #include "tests.h"
#include "user-util.h"
#include "util.h" #include "util.h"
#include "virt.h"
static void test_tmpdir(const char *id, const char *A, const char *B) { static void test_tmpdir(const char *id, const char *A, const char *B) {
_cleanup_free_ char *a, *b; _cleanup_free_ char *a, *b;
@ -48,14 +51,16 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
assert_se(rmdir(b) >= 0); assert_se(rmdir(b) >= 0);
} }
static int test_netns(void) { static void test_netns(void) {
_cleanup_close_pair_ int s[2] = { -1, -1 }; _cleanup_close_pair_ int s[2] = { -1, -1 };
pid_t pid1, pid2, pid3; pid_t pid1, pid2, pid3;
int r, n = 0; int r, n = 0;
siginfo_t si; siginfo_t si;
if (geteuid() > 0) if (geteuid() > 0) {
return log_tests_skipped("not root"); (void) log_tests_skipped("not root");
return;
}
assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0); assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
@ -102,7 +107,62 @@ static int test_netns(void) {
n += si.si_status; n += si.si_status;
assert_se(n == 1); assert_se(n == 1);
return EXIT_SUCCESS; }
static void test_protect_kernel_logs(void) {
int r;
pid_t pid;
static const NamespaceInfo ns_info = {
.protect_kernel_logs = true,
};
if (geteuid() > 0) {
(void) log_tests_skipped("not root");
return;
}
/* In a container we likely don't have access to /dev/kmsg */
if (detect_container() > 0) {
(void) log_tests_skipped("in container");
return;
}
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
_cleanup_close_ int fd = -1;
fd = open("/dev/kmsg", O_RDONLY | O_CLOEXEC);
assert_se(fd > 0);
r = setup_namespace(NULL,
NULL,
&ns_info,
NULL,
NULL,
NULL,
NULL,
NULL, 0,
NULL, 0,
NULL,
NULL,
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
0,
NULL);
assert_se(r == 0);
assert_se(setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) >= 0);
assert_se(open("/dev/kmsg", O_RDONLY | O_CLOEXEC) < 0);
assert_se(errno == EACCES);
_exit(EXIT_SUCCESS);
}
assert_se(wait_for_terminate_and_check("ns-kernellogs", pid, WAIT_LOG) == EXIT_SUCCESS);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -133,5 +193,8 @@ int main(int argc, char *argv[]) {
test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz); test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
return test_netns(); test_netns();
test_protect_kernel_logs();
return EXIT_SUCCESS;
} }

View File

@ -323,6 +323,48 @@ static void test_protect_sysctl(void) {
assert_se(wait_for_terminate_and_check("sysctlseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); assert_se(wait_for_terminate_and_check("sysctlseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
} }
static void test_protect_syslog(void) {
pid_t pid;
log_info("/* %s */", __func__);
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
}
if (geteuid() != 0) {
log_notice("Not root, skipping %s", __func__);
return;
}
/* in containers syslog() is likely missing anyway */
if (detect_container() > 0) {
log_notice("Testing in container, skipping %s", __func__);
return;
}
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
#if defined __NR_syslog && __NR_syslog > 0
assert_se(syscall(__NR_syslog, -1, NULL, 0) < 0);
assert_se(errno == EINVAL);
#endif
assert_se(seccomp_protect_syslog() >= 0);
#if defined __NR_syslog && __NR_syslog > 0
assert_se(syscall(__NR_syslog, 0, 0, 0) < 0);
assert_se(errno == EPERM);
#endif
_exit(EXIT_SUCCESS);
}
assert_se(wait_for_terminate_and_check("syslogseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
static void test_restrict_address_families(void) { static void test_restrict_address_families(void) {
pid_t pid; pid_t pid;
@ -983,6 +1025,7 @@ int main(int argc, char *argv[]) {
test_filter_sets_ordered(); test_filter_sets_ordered();
test_restrict_namespace(); test_restrict_namespace();
test_protect_sysctl(); test_protect_sysctl();
test_protect_syslog();
test_restrict_address_families(); test_restrict_address_families();
test_restrict_realtime(); test_restrict_realtime();
test_memory_deny_write_execute_mmap(); test_memory_deny_write_execute_mmap();

View File

@ -109,6 +109,8 @@ test_data_files = '''
test-execute/exec-privatetmp-no.service test-execute/exec-privatetmp-no.service
test-execute/exec-privatetmp-yes.service test-execute/exec-privatetmp-yes.service
test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service
test-execute/exec-protectkernellogs-yes-capabilities.service
test-execute/exec-protectkernellogs-no-capabilities.service
test-execute/exec-protectkernelmodules-no-capabilities.service test-execute/exec-protectkernelmodules-no-capabilities.service
test-execute/exec-protectkernelmodules-yes-capabilities.service test-execute/exec-protectkernelmodules-yes-capabilities.service
test-execute/exec-protectkernelmodules-yes-mount-propagation.service test-execute/exec-protectkernelmodules-yes-mount-propagation.service

View File

@ -0,0 +1,7 @@
[Unit]
Description=Test CAP_SYSLOG for ProtectKernelLogs=no
[Service]
ProtectKernelLogs=no
ExecStart=/bin/sh -x -c 'capsh --print | grep cap_syslog'
Type=oneshot

View File

@ -0,0 +1,7 @@
[Unit]
Description=Test CAP_SYSLOG for ProtectKernelLogs=yes
[Service]
ProtectKernelLogs=yes
ExecStart=/bin/sh -x -c '! capsh --print | grep cap_syslog'
Type=oneshot

View File

@ -32,6 +32,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes RestrictNamespaces=yes

View File

@ -27,6 +27,7 @@ ProtectControlGroups=yes
ProtectHome=yes ProtectHome=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/etc ReadWritePaths=/etc
RestrictAddressFamilies=AF_UNIX RestrictAddressFamilies=AF_UNIX

View File

@ -24,6 +24,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes RestrictNamespaces=yes
RestrictRealtime=yes RestrictRealtime=yes

View File

@ -26,6 +26,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes RestrictNamespaces=yes

View File

@ -24,6 +24,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes RestrictNamespaces=yes
RestrictRealtime=yes RestrictRealtime=yes

View File

@ -28,6 +28,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/etc ReadWritePaths=/etc
RestrictAddressFamilies=AF_UNIX RestrictAddressFamilies=AF_UNIX

View File

@ -41,6 +41,7 @@ ProtectControlGroups=yes
ProtectHome=yes ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/etc /run ReadWritePaths=/etc /run
Restart=always Restart=always

View File

@ -24,6 +24,7 @@ LockPersonality=yes
MemoryDenyWriteExecute=yes MemoryDenyWriteExecute=yes
NoNewPrivileges=yes NoNewPrivileges=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelLogs=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictRealtime=yes RestrictRealtime=yes
SystemCallArchitectures=native SystemCallArchitectures=native

View File

@ -29,6 +29,7 @@ NoNewPrivileges=yes
ProtectControlGroups=yes ProtectControlGroups=yes
ProtectHome=yes ProtectHome=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
Restart=on-failure Restart=on-failure
RestartSec=0 RestartSec=0

View File

@ -18,6 +18,7 @@ BusName=org.freedesktop.portable1
CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD
MemoryDenyWriteExecute=yes MemoryDenyWriteExecute=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelLogs=yes
RestrictRealtime=yes RestrictRealtime=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
SystemCallFilter=@system-service @mount SystemCallFilter=@system-service @mount

View File

@ -32,6 +32,7 @@ ProtectControlGroups=yes
ProtectHome=yes ProtectHome=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
Restart=always Restart=always
RestartSec=0 RestartSec=0

View File

@ -27,6 +27,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/etc ReadWritePaths=/etc
RestrictAddressFamilies=AF_UNIX RestrictAddressFamilies=AF_UNIX

View File

@ -32,6 +32,7 @@ ProtectHome=yes
ProtectHostname=yes ProtectHostname=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectSystem=strict ProtectSystem=strict
Restart=always Restart=always
RestartSec=0 RestartSec=0