From ecf63c91025b1692d48886b57dae3896ab12c54c Mon Sep 17 00:00:00 2001
From: Nate Jones <jonesnl@umich.edu>
Date: Fri, 28 Feb 2020 20:31:23 -0500
Subject: [PATCH 1732/1760] execute: Make '+' exec prefix ignore
PrivateTmp=yes

The man pages state that the '+' prefix in Exec* directives should
ignore filesystem namespacing options such as PrivateTmp. Now it does.

This is very similar to #8842, just with PrivateTmp instead of
PrivateDevices.
Reference: https://github.com/systemd/systemd/commit/ecf63c91025b1692d48886b57dae3896ab12c54c
Conflict: NA
---
 src/core/execute.c                            | 26 +++++++++----------
 src/test/test-execute.c                       |  1 +
 test/meson.build                              |  1 +
 test/test-execute/exec-basic.service          |  1 -
 ...exec-privatetmp-disabled-by-prefix.service |  8 ++++++
 5 files changed, 23 insertions(+), 14 deletions(-)
 create mode 100644 test/test-execute/exec-privatetmp-disabled-by-prefix.service

diff --git a/src/core/execute.c b/src/core/execute.c
index 4c90007..7e28870 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2468,17 +2468,6 @@ static int apply_mount_namespace(
 
         assert(context);
 
-        /* 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. */
-
-        if (context->private_tmp && runtime) {
-                if (runtime->tmp_dir)
-                        tmp = strjoina(runtime->tmp_dir, "/tmp");
-                if (runtime->var_tmp_dir)
-                        var = strjoina(runtime->var_tmp_dir, "/tmp");
-        }
-
         if (params->flags & EXEC_APPLY_CHROOT) {
                 root_image = context->root_image;
 
@@ -2491,7 +2480,18 @@ static int apply_mount_namespace(
                 return r;
 
         needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
-        if (needs_sandboxing)
+        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. */
+
+                if (context->private_tmp && runtime) {
+                        if (runtime->tmp_dir)
+                                tmp = strjoina(runtime->tmp_dir, "/tmp");
+                        if (runtime->var_tmp_dir)
+                                var = strjoina(runtime->var_tmp_dir, "/tmp");
+                }
+
                 ns_info = (NamespaceInfo) {
                         .ignore_protect_paths = false,
                         .private_dev = context->private_devices,
@@ -2502,7 +2502,7 @@ static int apply_mount_namespace(
                         .mount_apivfs = context->mount_apivfs,
                         .private_mounts = context->private_mounts,
                 };
-        else if (!context->dynamic_user && root_dir)
+        } else if (!context->dynamic_user && root_dir)
                 /*
                  * If DynamicUser=no and RootDirectory= is set then lets pass a relaxed
                  * sandbox info, otherwise enforce it, don't ignore protected paths and
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 435ab39..91729f5 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -292,6 +292,7 @@ static void test_exec_privatetmp(Manager *m) {
 
         test(__func__, m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
         test(__func__, m, "exec-privatetmp-no.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatetmp-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 
         unlink("/tmp/test-exec_privatetmp");
 }
diff --git a/test/meson.build b/test/meson.build
index 36d9df7..0c1db57 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -108,6 +108,7 @@ test_data_files = '''
         test-execute/exec-privatenetwork-yes.service
         test-execute/exec-privatetmp-no.service
         test-execute/exec-privatetmp-yes.service
+        test-execute/exec-privatetmp-disabled-by-prefix.service
         test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service
         test-execute/exec-protectkernelmodules-no-capabilities.service
         test-execute/exec-protectkernelmodules-yes-capabilities.service
diff --git a/test/test-execute/exec-basic.service b/test/test-execute/exec-basic.service
index ae4618c..60c5be6 100644
--- a/test/test-execute/exec-basic.service
+++ b/test/test-execute/exec-basic.service
@@ -10,7 +10,6 @@ ExecStart=touch /tmp/a ; /bin/sh -c 'touch /tmp/b' ; touch /tmp/c
 ExecStart=test -f /tmp/a
 ExecStart=!test -f /tmp/b
 ExecStart=!!test -f /tmp/c
-ExecStart=+test -f /tmp/c
 ExecStartPost=rm /tmp/a /tmp/b /tmp/c
 
 PrivateTmp=true
diff --git a/test/test-execute/exec-privatetmp-disabled-by-prefix.service b/test/test-execute/exec-privatetmp-disabled-by-prefix.service
new file mode 100644
index 0000000..009e6be
--- /dev/null
+++ b/test/test-execute/exec-privatetmp-disabled-by-prefix.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for PrivateTmp=yes with prefix
+
+[Service]
+ExecStart=/bin/sh -x -c 'test ! -f /tmp/test-exec_privatetmp'
+ExecStart=+/bin/sh -x -c 'test -f /tmp/test-exec_privatetmp'
+Type=oneshot
+PrivateTmp=yes
-- 
2.19.1

