core: add new option 'tmpfs' to ProtectHome=

This make ProtectHome= setting can take 'tmpfs'. This is mostly
equivalent to `TemporaryFileSystem=/home /run/user /root`.
This commit is contained in:
Yu Watanabe 2018-02-21 09:13:11 +09:00
parent 4cac89bd7c
commit e4da7d8c79
3 changed files with 33 additions and 9 deletions

View file

@ -788,14 +788,24 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<varlistentry> <varlistentry>
<term><varname>ProtectHome=</varname></term> <term><varname>ProtectHome=</varname></term>
<listitem><para>Takes a boolean argument or <literal>read-only</literal>. If true, the directories <listitem><para>Takes a boolean argument or the special values <literal>read-only</literal> or
<filename>/home</filename>, <filename>/root</filename> and <filename>/run/user</filename> are made inaccessible <literal>tmpfs</literal>. If true, the directories <filename>/home</filename>, <filename>/root</filename> and
and empty for processes invoked by this unit. If set to <literal>read-only</literal>, the three directories are <filename>/run/user</filename> are made inaccessible and empty for processes invoked by this unit. If set to
made read-only instead. It is recommended to enable this setting for all long-running services (in particular <literal>read-only</literal>, the three directories are made read-only instead. If set to <literal>tmpfs</literal>,
network-facing ones), to ensure they cannot get access to private user data, unless the services actually temporary file systems are mounted on the three directories in read-only mode. The value <literal>tmpfs</literal>
require access to the user's private data. This setting is implied if <varname>DynamicUser=</varname> is is useful to hide home directories not relevant to the processes invoked by the unit, while necessary directories
set. For this setting the same restrictions regarding mount propagation and privileges apply as for are still visible by combining with <varname>BindPaths=</varname> or <varname>BindReadOnlyPaths=</varname>.</para>
<varname>ReadOnlyPaths=</varname> and related calls, see below.</para></listitem>
<para>Setting this to <literal>yes</literal> is mostly equivalent to set the three directories in
<varname>InaccessiblePaths=</varname>. Similary, <literal>read-only</literal> is mostly equivalent to
<varname>ReadOnlyPaths=</varname>, and <literal>tmpfs</literal> is mostly equivalent to
<varname>TemporaryFileSystem=</varname>.</para>
<para> It is recommended to enable this setting for all long-running services (in particular network-facing ones),
to ensure they cannot get access to private user data, unless the services actually require access to the user's
private data. This setting is implied if <varname>DynamicUser=</varname> is set. For this setting the same
restrictions regarding mount propagation and privileges apply as for <varname>ReadOnlyPaths=</varname> and related
calls, see below.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View file

@ -128,6 +128,13 @@ static const MountEntry protect_home_read_only_table[] = {
{ "/root", READONLY, true }, { "/root", READONLY, true },
}; };
/* ProtectHome=tmpfs table */
static const MountEntry protect_home_tmpfs_table[] = {
{ "/home", TMPFS, true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
{ "/run/user", TMPFS, true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
{ "/root", TMPFS, true, .read_only = true, .options_const = "mode=0700", .flags = MS_NODEV|MS_STRICTATIME },
};
/* ProtectHome=yes table */ /* ProtectHome=yes table */
static const MountEntry protect_home_yes_table[] = { static const MountEntry protect_home_yes_table[] = {
{ "/home", INACCESSIBLE, true }, { "/home", INACCESSIBLE, true },
@ -354,6 +361,9 @@ static int append_protect_home(MountEntry **p, ProtectHome protect_home, bool ig
case PROTECT_HOME_READ_ONLY: case PROTECT_HOME_READ_ONLY:
return append_static_mounts(p, protect_home_read_only_table, ELEMENTSOF(protect_home_read_only_table), ignore_protect); return append_static_mounts(p, protect_home_read_only_table, ELEMENTSOF(protect_home_read_only_table), ignore_protect);
case PROTECT_HOME_TMPFS:
return append_static_mounts(p, protect_home_tmpfs_table, ELEMENTSOF(protect_home_tmpfs_table), ignore_protect);
case PROTECT_HOME_YES: case PROTECT_HOME_YES:
return append_static_mounts(p, protect_home_yes_table, ELEMENTSOF(protect_home_yes_table), ignore_protect); return append_static_mounts(p, protect_home_yes_table, ELEMENTSOF(protect_home_yes_table), ignore_protect);
@ -1011,7 +1021,9 @@ static unsigned namespace_calculate_mounts(
(protect_home == PROTECT_HOME_YES ? (protect_home == PROTECT_HOME_YES ?
ELEMENTSOF(protect_home_yes_table) : ELEMENTSOF(protect_home_yes_table) :
((protect_home == PROTECT_HOME_READ_ONLY) ? ((protect_home == PROTECT_HOME_READ_ONLY) ?
ELEMENTSOF(protect_home_read_only_table) : 0)); ELEMENTSOF(protect_home_read_only_table) :
((protect_home == PROTECT_HOME_TMPFS) ?
ELEMENTSOF(protect_home_tmpfs_table) : 0)));
return !!tmp_dir + !!var_tmp_dir + return !!tmp_dir + !!var_tmp_dir +
strv_length(read_write_paths) + strv_length(read_write_paths) +
@ -1576,6 +1588,7 @@ static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
[PROTECT_HOME_NO] = "no", [PROTECT_HOME_NO] = "no",
[PROTECT_HOME_YES] = "yes", [PROTECT_HOME_YES] = "yes",
[PROTECT_HOME_READ_ONLY] = "read-only", [PROTECT_HOME_READ_ONLY] = "read-only",
[PROTECT_HOME_TMPFS] = "tmpfs",
}; };
DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome); DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);

View file

@ -34,6 +34,7 @@ typedef enum ProtectHome {
PROTECT_HOME_NO, PROTECT_HOME_NO,
PROTECT_HOME_YES, PROTECT_HOME_YES,
PROTECT_HOME_READ_ONLY, PROTECT_HOME_READ_ONLY,
PROTECT_HOME_TMPFS,
_PROTECT_HOME_MAX, _PROTECT_HOME_MAX,
_PROTECT_HOME_INVALID = -1 _PROTECT_HOME_INVALID = -1
} ProtectHome; } ProtectHome;