core: add new option 'tmpfs' to ProtectHome=
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 21 Feb 2018 00:13:11 +0000 (09:13 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 21 Feb 2018 00:18:17 +0000 (09:18 +0900)
This make ProtectHome= setting can take 'tmpfs'. This is mostly
equivalent to `TemporaryFileSystem=/home /run/user /root`.

man/systemd.exec.xml
src/core/namespace.c
src/core/namespace.h

index 169a449..3e4a7f3 100644 (file)
@@ -788,14 +788,24 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
       <varlistentry>
         <term><varname>ProtectHome=</varname></term>
 
-        <listitem><para>Takes a boolean argument or <literal>read-only</literal>. If true, the directories
-        <filename>/home</filename>, <filename>/root</filename> and <filename>/run/user</filename> are made inaccessible
-        and empty for processes invoked by this unit. If set to <literal>read-only</literal>, the three directories are
-        made read-only instead. 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>
+        <listitem><para>Takes a boolean argument or the special values <literal>read-only</literal> or
+        <literal>tmpfs</literal>. If true, the directories <filename>/home</filename>, <filename>/root</filename> and
+        <filename>/run/user</filename> are made inaccessible and empty for processes invoked by this unit. If set to
+        <literal>read-only</literal>, the three directories are made read-only instead. If set to <literal>tmpfs</literal>,
+        temporary file systems are mounted on the three directories in read-only mode. The value <literal>tmpfs</literal>
+        is useful to hide home directories not relevant to the processes invoked by the unit, while necessary directories
+        are still visible by combining with <varname>BindPaths=</varname> or <varname>BindReadOnlyPaths=</varname>.</para>
+
+        <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>
index 2d82a07..f605d23 100644 (file)
@@ -128,6 +128,13 @@ static const MountEntry protect_home_read_only_table[] = {
         { "/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 */
 static const MountEntry protect_home_yes_table[] = {
         { "/home",               INACCESSIBLE, true  },
@@ -354,6 +361,9 @@ static int append_protect_home(MountEntry **p, ProtectHome protect_home, bool ig
         case PROTECT_HOME_READ_ONLY:
                 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:
                 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 ?
                  ELEMENTSOF(protect_home_yes_table) :
                  ((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 +
                 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_YES] = "yes",
         [PROTECT_HOME_READ_ONLY] = "read-only",
+        [PROTECT_HOME_TMPFS] = "tmpfs",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
index df7be7d..3d56a73 100644 (file)
@@ -34,6 +34,7 @@ typedef enum ProtectHome {
         PROTECT_HOME_NO,
         PROTECT_HOME_YES,
         PROTECT_HOME_READ_ONLY,
+        PROTECT_HOME_TMPFS,
         _PROTECT_HOME_MAX,
         _PROTECT_HOME_INVALID = -1
 } ProtectHome;