<listitem><para>Units with <varname>PrivateTmp=yes</varname> automatically gain dependencies of type
<varname>Wants=</varname> and <varname>After=</varname> on all mounts required to access
- <filename>/tmp/</filename> and <filename>/var/tmp/</filename>. They will also gain an automatic
+ <filename>/tmp/</filename> and <filename>/var/tmp/</filename> and an automatic
<varname>After=</varname> dependency on
- <citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- </para></listitem>
+ <citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ unless <varname>DefaultDependencies=no</varname> is specified. If
+ <varname>DefaultDependencies=no</varname> is specified, and a
+ <varname>RequiresMountsFor=/tmp/</varname>, <varname>WantsMountsFor=/tmp/</varname>,
+ <varname>After=tmp.mount</varname>, or <varname>RootDirectory=</varname>/<varname>RootImage=</varname>
+ are not specified, <varname>PrivateTmp=yes</varname> is converted to
+ <varname>PrivateTmp=disconnected</varname>.</para></listitem>
<listitem><para>Units with <varname>PrivateTmp=disconnected</varname> automatically gain dependencies
of type <varname>Wants=</varname> and <varname>After=</varname> on the mount required to access
}
assert(c->private_var_tmp >= 0 && c->private_var_tmp < _PRIVATE_TMP_MAX);
- if (needs_sandboxing && c->private_tmp != c->private_var_tmp) {
- assert(c->private_tmp == PRIVATE_TMP_DISCONNECTED);
- assert(c->private_var_tmp == PRIVATE_TMP_NO);
-
+ if (needs_sandboxing &&
+ c->private_var_tmp == PRIVATE_TMP_NO && c->private_tmp != PRIVATE_TMP_NO) {
/* When private tmpfs is enabled only on /tmp/, then explicitly set $TMPDIR to suggest the
* service to use /tmp/. */
if (needs_sandboxing) {
/* The runtime struct only contains the parent of the private /tmp, which is non-accessible
* to world users. Inside of it there's a /tmp that is sticky, and that's the one we want to
- * use here. This does not apply when we are using /run/systemd/empty as fallback. */
+ * use here. This does not apply when we are using /run/systemd/empty as fallback. */
if (context->private_tmp == PRIVATE_TMP_CONNECTED && runtime->shared) {
if (streq_ptr(runtime->shared->tmp_dir, RUN_SYSTEMD_EMPTY))
tmp_dir = runtime->shared->tmp_dir;
else if (runtime->shared->tmp_dir)
tmp_dir = strjoina(runtime->shared->tmp_dir, "/tmp");
+ }
+ if (context->private_var_tmp == PRIVATE_TMP_CONNECTED && runtime->shared) {
if (streq_ptr(runtime->shared->var_tmp_dir, RUN_SYSTEMD_EMPTY))
var_tmp_dir = runtime->shared->var_tmp_dir;
else if (runtime->shared->var_tmp_dir)
return false;
return context->private_users != PRIVATE_USERS_NO ||
- context->private_tmp != PRIVATE_TMP_NO ||
+ context->private_tmp != PRIVATE_TMP_NO || /* no need to check for private_var_tmp here, private_tmp is never demoted to "no" */
context->private_devices ||
context->private_network ||
context->user_namespace_path ||
assert(c->private_var_tmp >= 0 && c->private_var_tmp < _PRIVATE_TMP_MAX);
if (c->private_tmp == PRIVATE_TMP_CONNECTED) {
- assert(c->private_var_tmp == PRIVATE_TMP_CONNECTED);
-
r = unit_add_mounts_for(u, "/tmp/", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_WANTS);
if (r < 0)
return r;
+ }
+ if (c->private_var_tmp == PRIVATE_TMP_CONNECTED) {
r = unit_add_mounts_for(u, "/var/tmp/", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_WANTS);
if (r < 0)
return r;
-
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, true, UNIT_DEPENDENCY_FILE);
- if (r < 0)
- return r;
-
} else if (c->private_var_tmp == PRIVATE_TMP_DISCONNECTED && !exec_context_with_rootfs(c)) {
/* Even if PrivateTmp=disconnected, we still require /var/tmp/ mountpoint to be present,
* i.e. /var/ needs to be mounted. See comments in unit_patch_contexts(). */
return r;
}
+ if (c->private_tmp == PRIVATE_TMP_CONNECTED || c->private_var_tmp == PRIVATE_TMP_CONNECTED) {
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, true, UNIT_DEPENDENCY_FILE);
+ if (r < 0)
+ return r;
+ }
+
if (c->root_image || c->root_mstack) {
/* We need to wait for /dev/loopX to appear when doing RootImage=, hence let's add an
* implicit dependency on udev. (And for RootMStack= we might need it) */
assert(c->private_tmp >= 0 && c->private_tmp < _PRIVATE_TMP_MAX);
/* Disable disconnected private tmpfs on /var/tmp/ when DefaultDependencies=no and
- * RootImage=/RootDirectory= are not set, as /var/ may be a separated partition.
- * See issue #37258. */
+ * RootImage=/RootDirectory= are not set, as /var/ may be a separate partition.
+ * See https://github.com/systemd/systemd/issues/37258. */
/* PrivateTmp=yes/no also enables/disables private tmpfs on /var/tmp/. */
if (c->private_tmp != PRIVATE_TMP_DISCONNECTED)
return PRIVATE_TMP_NO;
}
+static PrivateTmp unit_get_private_tmp(const Unit *u, const ExecContext *c) {
+ assert(u);
+ assert(c);
+ assert(c->private_tmp >= 0 && c->private_tmp < _PRIVATE_TMP_MAX);
+
+ /* Upgrade "PrivateTmp=yes" (a.k.a. 'connected') to 'disconnected' when
+ * DefaultDependencies=no and RootImage=/RootDirectory= are not set, as /tmp/ may be a
+ * separate partition. See https://github.com/systemd/systemd/issues/28515.
+ *
+ * Note that the change goes in the opposite direction than unit_get_private_var_tmp()
+ * above. For /var/tmp/, we need to disable the setting, because we don't want to create
+ * the /var/tmp/ directory if /var/ is a mount point. We don't have this problem with
+ * /tmp/ because there is no nesting. */
+
+ if (c->private_tmp != PRIVATE_TMP_CONNECTED ||
+ u->default_dependencies ||
+ exec_context_with_rootfs(c))
+ return c->private_tmp;
+
+ /* Even if DefaultDependencies=no, honour tmpfs setting when
+ * RequiresMountsFor=/WantsMountsFor=/tmp/ is explicitly set. */
+ for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; t++)
+ if (hashmap_contains(u->mounts_for[t], "/tmp/"))
+ return c->private_tmp;
+
+ /* Check the same but for After=. */
+ Unit *m = manager_get_unit(u->manager, "tmp.mount");
+ if (!m)
+ return c->private_tmp;
+
+ if (unit_has_dependency(u, UNIT_ATOM_AFTER, m))
+ return c->private_tmp;
+
+ return PRIVATE_TMP_DISCONNECTED;
+}
+
int unit_patch_contexts(Unit *u) {
CGroupContext *cc;
ExecContext *ec;
ec->restrict_suid_sgid = true;
}
+ /* Table of possible combinations:
+ * /var/tmp /tmp
+ * PrivateTmp=no no no
+ * PrivateTmp=connected connected connected,disconnected
+ * PrivateTmp=disconnected disconnected,no disconnected
+ */
ec->private_var_tmp = unit_get_private_var_tmp(u, ec);
+ ec->private_tmp = unit_get_private_tmp(u, ec);
FOREACH_ARRAY(d, ec->directories, _EXEC_DIRECTORY_TYPE_MAX)
exec_directory_sort(d);