@@ -192,6 +192,7 @@ All execution-related settings are available for transient units.
|
||||
✓ PrivateUsers=
|
||||
✓ ProtectSystem=
|
||||
✓ ProtectHome=
|
||||
✓ ProtectClock=
|
||||
✓ MountFlags=
|
||||
✓ MountAPIVFS=
|
||||
✓ Personality=
|
||||
|
||||
+21
-6
@@ -405,11 +405,11 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
|
||||
<varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
|
||||
<varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
|
||||
<varname>ProtectKernelModules=</varname>, <varname>ProtectKernelLogs=</varname>,
|
||||
<varname>MemoryDenyWriteExecute=</varname>, <varname>RestrictRealtime=</varname>,
|
||||
<varname>RestrictSUIDSGID=</varname>, <varname>DynamicUser=</varname> or <varname>LockPersonality=</varname>
|
||||
are specified. Note that even if this setting is overridden by them, <command>systemctl show</command> shows the
|
||||
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
|
||||
<varname>ProtectClock=</varname>, <varname>MemoryDenyWriteExecute=</varname>,
|
||||
<varname>RestrictRealtime=</varname>, <varname>RestrictSUIDSGID=</varname>, <varname>DynamicUser=</varname>
|
||||
or <varname>LockPersonality=</varname> are specified. Note that even if this setting is overridden by them,
|
||||
<command>systemctl show</command> shows the 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
|
||||
Flag</ulink>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -1296,6 +1296,21 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ProtectClock=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If set, writes to the hardware clock or system clock will be denied.
|
||||
It is recommended to turn this on for most services that do not need modify the clock. Defaults to off. Enabling
|
||||
this option removes <constant>CAP_SYS_TIME</constant> and <constant>CAP_WAKE_ALARM</constant> from the
|
||||
capability bounding set for this unit, installs a system call filter to block calls that can set the
|
||||
clock, and <varname>DeviceAllow=char-rtc r</varname> is implied. This ensures <filename>/dev/rtc0</filename>,
|
||||
<filename>/dev/rtc1</filename>, etc are made read only to the service. See
|
||||
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for the details about <varname>DeviceAllow=</varname>.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ProtectKernelTunables=</varname></term>
|
||||
|
||||
@@ -1807,7 +1822,7 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||
mappings. Specifically these are the options <varname>PrivateTmp=</varname>,
|
||||
<varname>PrivateDevices=</varname>, <varname>ProtectSystem=</varname>, <varname>ProtectHome=</varname>,
|
||||
<varname>ProtectKernelTunables=</varname>, <varname>ProtectControlGroups=</varname>,
|
||||
<varname>ProtectKernelLogs=</varname>, <varname>ReadOnlyPaths=</varname>,
|
||||
<varname>ProtectKernelLogs=</varname>, <varname>ProtectClock=</varname>, <varname>ReadOnlyPaths=</varname>,
|
||||
<varname>InaccessiblePaths=</varname> and <varname>ReadWritePaths=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ struct security_info {
|
||||
bool protect_kernel_modules;
|
||||
bool protect_kernel_tunables;
|
||||
bool protect_kernel_logs;
|
||||
bool protect_clock;
|
||||
|
||||
char *protect_home;
|
||||
char *protect_system;
|
||||
@@ -783,6 +784,16 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.assess = assess_bool,
|
||||
.offset = offsetof(struct security_info, protect_kernel_logs),
|
||||
},
|
||||
{
|
||||
.id = "ProtectClock=",
|
||||
.description_good = "Service cannot write to the hardware clock or system clock",
|
||||
.description_bad = "Service may write to the hardware clock or system clock",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectClock=",
|
||||
.weight = 1000,
|
||||
.range = 1,
|
||||
.assess = assess_bool,
|
||||
.offset = offsetof(struct security_info, protect_clock),
|
||||
},
|
||||
{
|
||||
.id = "ProtectHome=",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHome=",
|
||||
@@ -1907,6 +1918,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
|
||||
{ "ProtectKernelModules", "b", NULL, offsetof(struct security_info, protect_kernel_modules) },
|
||||
{ "ProtectKernelTunables", "b", NULL, offsetof(struct security_info, protect_kernel_tunables) },
|
||||
{ "ProtectKernelLogs", "b", NULL, offsetof(struct security_info, protect_kernel_logs) },
|
||||
{ "ProtectClock", "b", NULL, offsetof(struct security_info, protect_clock) },
|
||||
{ "ProtectSystem", "s", NULL, offsetof(struct security_info, protect_system) },
|
||||
{ "RemoveIPC", "b", NULL, offsetof(struct security_info, remove_ipc) },
|
||||
{ "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 },
|
||||
@@ -1984,6 +1996,10 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
|
||||
if (info->protect_kernel_logs)
|
||||
info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYSLOG);
|
||||
|
||||
if (info->protect_clock)
|
||||
info->capability_bounding_set &= ~((UINT64_C(1) << CAP_SYS_TIME) |
|
||||
(UINT64_C(1) << CAP_WAKE_ALARM));
|
||||
|
||||
if (info->private_devices)
|
||||
info->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) |
|
||||
(UINT64_C(1) << CAP_SYS_RAWIO));
|
||||
|
||||
@@ -1284,6 +1284,9 @@ int bus_exec_context_set_transient_property(
|
||||
if (streq(name, "ProtectKernelLogs"))
|
||||
return bus_set_transient_bool(u, name, &c->protect_kernel_logs, message, flags, error);
|
||||
|
||||
if (streq(name, "ProtectClock"))
|
||||
return bus_set_transient_bool(u, name, &c->protect_clock, message, flags, error);
|
||||
|
||||
if (streq(name, "ProtectControlGroups"))
|
||||
return bus_set_transient_bool(u, name, &c->protect_control_groups, message, flags, error);
|
||||
|
||||
|
||||
@@ -1402,6 +1402,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
|
||||
c->restrict_realtime ||
|
||||
c->restrict_suid_sgid ||
|
||||
exec_context_restrict_namespaces_set(c) ||
|
||||
c->protect_clock ||
|
||||
c->protect_kernel_tunables ||
|
||||
c->protect_kernel_modules ||
|
||||
c->protect_kernel_logs ||
|
||||
@@ -1564,6 +1565,19 @@ static int apply_protect_kernel_logs(const Unit *u, const ExecContext *c) {
|
||||
return seccomp_protect_syslog();
|
||||
}
|
||||
|
||||
static int apply_protect_clock(const Unit *u, const ExecContext *c) {
|
||||
assert(u);
|
||||
assert(c);
|
||||
|
||||
if (!c->protect_clock)
|
||||
return 0;
|
||||
|
||||
if (skip_seccomp_unavailable(u, "ProtectClock="))
|
||||
return 0;
|
||||
|
||||
return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_CLOCK, SCMP_ACT_ERRNO(EPERM), false);
|
||||
}
|
||||
|
||||
static int apply_private_devices(const Unit *u, const ExecContext *c) {
|
||||
assert(u);
|
||||
assert(c);
|
||||
@@ -3797,6 +3811,12 @@ static int exec_child(
|
||||
return log_unit_error_errno(unit, r, "Failed to apply kernel log restrictions: %m");
|
||||
}
|
||||
|
||||
r = apply_protect_clock(unit, context);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_SECCOMP;
|
||||
return log_unit_error_errno(unit, r, "Failed to apply clock restrictions: %m");
|
||||
}
|
||||
|
||||
r = apply_private_devices(unit, context);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_SECCOMP;
|
||||
@@ -4437,6 +4457,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||
"%sProtectKernelTunables: %s\n"
|
||||
"%sProtectKernelModules: %s\n"
|
||||
"%sProtectKernelLogs: %s\n"
|
||||
"%sProtectClock: %s\n"
|
||||
"%sProtectControlGroups: %s\n"
|
||||
"%sPrivateNetwork: %s\n"
|
||||
"%sPrivateUsers: %s\n"
|
||||
@@ -4458,6 +4479,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||
prefix, yes_no(c->protect_kernel_tunables),
|
||||
prefix, yes_no(c->protect_kernel_modules),
|
||||
prefix, yes_no(c->protect_kernel_logs),
|
||||
prefix, yes_no(c->protect_clock),
|
||||
prefix, yes_no(c->protect_control_groups),
|
||||
prefix, yes_no(c->private_network),
|
||||
prefix, yes_no(c->private_users),
|
||||
|
||||
@@ -258,6 +258,7 @@ struct ExecContext {
|
||||
bool protect_kernel_tunables;
|
||||
bool protect_kernel_modules;
|
||||
bool protect_kernel_logs;
|
||||
bool protect_clock;
|
||||
bool protect_control_groups;
|
||||
ProtectSystem protect_system;
|
||||
ProtectHome protect_home;
|
||||
|
||||
@@ -116,6 +116,7 @@ $1.PrivateDevices, config_parse_bool, 0,
|
||||
$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.ProtectKernelLogs, config_parse_bool, 0, offsetof($1, exec_context.protect_kernel_logs)
|
||||
$1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock)
|
||||
$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.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
|
||||
|
||||
@@ -4287,6 +4287,9 @@ int unit_patch_contexts(Unit *u) {
|
||||
if (ec->protect_kernel_logs)
|
||||
ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYSLOG);
|
||||
|
||||
if (ec->protect_clock)
|
||||
ec->capability_bounding_set &= ~((UINT64_C(1) << CAP_SYS_TIME) | (UINT64_C(1) << CAP_WAKE_ALARM));
|
||||
|
||||
if (ec->dynamic_user) {
|
||||
if (!ec->user) {
|
||||
r = user_from_unit_name(u, &ec->user);
|
||||
@@ -4345,6 +4348,12 @@ int unit_patch_contexts(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ec->protect_clock) {
|
||||
r = cgroup_add_device_allow(cc, "char-rtc", "r");
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -854,6 +854,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
"ProtectKernelTunables",
|
||||
"ProtectKernelModules",
|
||||
"ProtectKernelLogs",
|
||||
"ProtectClock",
|
||||
"ProtectControlGroups",
|
||||
"MountAPIVFS",
|
||||
"CPUSchedulingResetOnFork",
|
||||
|
||||
Reference in New Issue
Block a user