core: verify WorkingDirectory= is outside of API VFS only under mount namespacing
authorMike Yuan <me@yhndnzj.com>
Sun, 23 Jun 2024 16:12:33 +0000 (18:12 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 5 Jul 2024 18:00:04 +0000 (20:00 +0200)
The purpose of the check is to prevent leaking API VFS fds
from host into a mount namespace/container. When mountns
is not used at all, the check is pointless and causes
inconvenience. E.g. file managers might need to be spawned
under those directories, and they surely won't run in mountns.

Suggested in https://github.com/systemd/systemd/pull/33454#issuecomment-2186351467
Fixes #33361

(cherry picked from commit 276bd392ecdd6febaeac82e7d6f46a035826f98d)

src/core/dbus-execute.c
src/core/load-fragment.c
src/core/unit.c

index 21c260b26b820247509e802ed7b58061a43959d8..b0d9402e53ca7c6ccbb9bbe60ec8357191d87f64 100644 (file)
@@ -2743,10 +2743,6 @@ int bus_exec_context_set_transient_property(
                                 if (!path_is_normalized(simplified))
                                         return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
                                                                 "WorkingDirectory= expects a normalized path or '~'");
-
-                                if (path_below_api_vfs(simplified))
-                                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
-                                                                "WorkingDirectory= may not be below /proc/, /sys/ or /dev/");
                         }
                 }
 
index 5ae68886afe79229d81bb8029481754d69d64b64..b346b48dd1c87435848350ff8f98e65705c9ae2d 100644 (file)
@@ -2634,7 +2634,8 @@ int config_parse_working_directory(
                         return missing_ok ? 0 : -ENOEXEC;
                 }
 
-                r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS|(missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
+                r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE|(missing_ok ? 0 : PATH_CHECK_FATAL),
+                                           unit, filename, line, lvalue);
                 if (r < 0)
                         return missing_ok ? 0 : -ENOEXEC;
 
index 2d40618fcbb7ad201d33f65c6636e0165f58c9c5..aa6e71198b641d271b932114f91383a87b4e3cd9 100644 (file)
@@ -41,6 +41,7 @@
 #include "logarithm.h"
 #include "macro.h"
 #include "mkdir-label.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "rm-rf.h"
@@ -4234,6 +4235,10 @@ static int unit_verify_contexts(const Unit *u, const ExecContext *ec) {
         if (ec->dynamic_user && ec->working_directory_home)
                 return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "WorkingDirectory=~ is not allowed under DynamicUser=yes. Refusing.");
 
+        if (ec->working_directory && path_below_api_vfs(ec->working_directory) &&
+            exec_needs_mount_namespace(ec, /* params = */ NULL, /* runtime = */ NULL))
+                return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "WorkingDirectory= may not be below /proc/, /sys/ or /dev/ when using mount namespacing. Refusing.");
+
         return 0;
 }