@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b ProtectHostname = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b MemoryKSM = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
<!--property ProtectHostname is not documented!-->
+ <!--property MemoryKSM is not documented!-->
+
<!--property NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHostname"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b ProtectHostname = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b MemoryKSM = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
<!--property ProtectHostname is not documented!-->
+ <!--property MemoryKSM is not documented!-->
+
<!--property NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHostname"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b ProtectHostname = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b MemoryKSM = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
<!--property ProtectHostname is not documented!-->
+ <!--property MemoryKSM is not documented!-->
+
<!--property NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHostname"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b ProtectHostname = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b MemoryKSM = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
<!--property ProtectHostname is not documented!-->
+ <!--property MemoryKSM is not documented!-->
+
<!--property NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHostname"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>MemoryKSM=</varname></term>
+
+ <listitem><para>Takes a boolean argument. When set, it enables KSM (kernel samepage merging) for
+ the processes. KSM is a memory-saving de-duplication feature. Anonymous memory pages with identical
+ content can be replaced by a single write-protected page. This feature should only be enabled for
+ jobs that share the same security domain. For details, see
+ <ulink url="https://docs.kernel.org/admin-guide/mm/ksm.html">Kernel Samepage Merging</ulink> in the
+ kernel documentation.</para>
+
+ <para>Note that this functionality might not be available, for example if KSM is disabled in the
+ kernel, or the kernel doesn't support controlling KSM at the process level through
+ <function>prctl()</function>.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>PrivateUsers=</varname></term>
CONFIG_XFRM_USER=y
CONFIG_XFS_FS=y
CONFIG_XFS_POSIX_ACL=y
+CONFIG_KSM=y
# CONFIG_WIRELESS is not set
# CONFIG_WLAN is not set
#ifndef PR_MDWE_REFUSE_EXEC_GAIN
#define PR_MDWE_REFUSE_EXEC_GAIN 1
#endif
+
+#ifndef PR_SET_MEMORY_MERGE
+#define PR_SET_MEMORY_MERGE 67
+#endif
SD_BUS_PROPERTY("ProtectProc", "s", property_get_protect_proc, offsetof(ExecContext, protect_proc), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("MemoryKSM", "b", bus_property_get_tristate, offsetof(ExecContext, memory_ksm), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootImagePolicy", "s", property_get_image_policy, offsetof(ExecContext, root_image_policy), SD_BUS_VTABLE_PROPERTY_CONST),
if (streq(name, "ProtectHostname"))
return bus_set_transient_bool(u, name, &c->protect_hostname, message, flags, error);
+ if (streq(name, "MemoryKSM"))
+ return bus_set_transient_tristate(u, name, &c->memory_ksm, message, flags, error);
+
if (streq(name, "UtmpIdentifier"))
return bus_set_transient_string(u, name, &c->utmp_id, message, flags, error);
return r;
}
+ if (context->memory_ksm >= 0)
+ if (prctl(PR_SET_MEMORY_MERGE, context->memory_ksm) < 0) {
+ if (ERRNO_IS_NOT_SUPPORTED(errno))
+ log_unit_debug_errno(unit, errno, "KSM support not available, ignoring.");
+ else {
+ *exit_status = EXIT_KSM;
+ return log_unit_error_errno(unit, errno, "Failed to set KSM: %m");
+ }
+ }
+
/* Drop groups as early as possible.
* This needs to be done after PrivateDevices=y setup as device nodes should be owned by the host's root.
* For non-root in a userns, devices will be owned by the user/group before the group change, and nobody. */
c->tty_cols = UINT_MAX;
numa_policy_reset(&c->numa_policy);
c->private_mounts = -1;
+ c->memory_ksm = -1;
}
void exec_context_done(ExecContext *c) {
ProcSubset proc_subset; /* subset= */
int private_mounts;
+ int memory_ksm;
bool private_tmp;
bool private_network;
bool private_devices;
{{type}}.SmackProcessLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
{% endif %}
{{type}}.ProtectHostname, config_parse_bool, 0, offsetof({{type}}, exec_context.protect_hostname)
+{{type}}.MemoryKSM, config_parse_tristate, 0, offsetof({{type}}, exec_context.memory_ksm)
{%- endmacro -%}
{%- macro KILL_CONTEXT_CONFIG_ITEMS(type) -%}
"CPUSchedulingResetOnFork",
"LockPersonality",
"ProtectHostname",
+ "MemoryKSM",
"RestrictSUIDSGID"))
return bus_append_parse_boolean(m, field, eq);
[EXIT_NUMA_POLICY] = { "NUMA_POLICY", EXIT_STATUS_SYSTEMD },
[EXIT_CREDENTIALS] = { "CREDENTIALS", EXIT_STATUS_SYSTEMD },
[EXIT_BPF] = { "BPF", EXIT_STATUS_SYSTEMD },
+ [EXIT_KSM] = { "KSM", EXIT_STATUS_SYSTEMD },
[EXIT_EXCEPTION] = { "EXCEPTION", EXIT_STATUS_SYSTEMD },
EXIT_NUMA_POLICY,
EXIT_CREDENTIALS,
EXIT_BPF,
+ EXIT_KSM,
EXIT_EXCEPTION = 255, /* Whenever we want to propagate an abnormal/signal exit, in line with bash */
};