diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 169a449632..3e4a7f3359 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -788,14 +788,24 @@ CapabilityBoundingSet=~CAP_B CAP_C
ProtectHome=
- Takes a boolean argument or read-only. If true, the directories
- /home, /root and /run/user are made inaccessible
- and empty for processes invoked by this unit. If set to read-only, 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 DynamicUser= is
- set. For this setting the same restrictions regarding mount propagation and privileges apply as for
- ReadOnlyPaths= and related calls, see below.
+ Takes a boolean argument or the special values read-only or
+ tmpfs. If true, the directories /home, /root and
+ /run/user are made inaccessible and empty for processes invoked by this unit. If set to
+ read-only, the three directories are made read-only instead. If set to tmpfs,
+ temporary file systems are mounted on the three directories in read-only mode. The value tmpfs
+ is useful to hide home directories not relevant to the processes invoked by the unit, while necessary directories
+ are still visible by combining with BindPaths= or BindReadOnlyPaths=.
+
+ Setting this to yes is mostly equivalent to set the three directories in
+ InaccessiblePaths=. Similary, read-only is mostly equivalent to
+ ReadOnlyPaths=, and tmpfs is mostly equivalent to
+ TemporaryFileSystem=.
+
+ 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 DynamicUser= is set. For this setting the same
+ restrictions regarding mount propagation and privileges apply as for ReadOnlyPaths= and related
+ calls, see below.
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 2d82a0778c..f605d239bc 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -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);
diff --git a/src/core/namespace.h b/src/core/namespace.h
index df7be7d1f2..3d56a7302d 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -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;