[systemd-devel] [PATCH] [PATCH v2] PrivateDevices: fix /dev mount when a service is chrooted

Alban Crequy alban.crequy at gmail.com
Fri Feb 20 04:59:23 PST 2015


From: Alban Crequy <alban at endocode.com>

When a service is chrooted with the option RootDirectory=/opt/..., then
the option PrivateDevices=true must mount the private /dev in
$RootDirectory/dev instead of /dev.

v2:
 - create the $RootDirectory/dev directory if missing. This is
   consistent with mount unit creating the mount points if missing.
 - avoid arbitrary limitation on 512 characters
---
 src/core/execute.c   |  9 ++++++++-
 src/core/namespace.c | 16 +++++++++++-----
 src/core/namespace.h |  2 +-
 src/test/test-ns.c   |  2 +-
 4 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/core/execute.c b/src/core/execute.c
index 1815e3d..1ced8b1 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1571,6 +1571,7 @@ static int exec_child(
             context->protect_home != PROTECT_HOME_NO) {
 
                 char *tmp = NULL, *var = NULL;
+                char *private_dev_dir = NULL;
 
                 /* The runtime struct only contains the parent
                  * of the private /tmp, which is
@@ -1585,6 +1586,12 @@ static int exec_child(
                                 var = strjoina(runtime->var_tmp_dir, "/tmp");
                 }
 
+                if (params->apply_chroot && context->root_directory) {
+                        size_t sz = strlen("/dev") + strlen(context->root_directory) + 1;
+                        private_dev_dir = alloca0(sz);
+                        snprintf(private_dev_dir, sz, "%s/dev", context->root_directory);
+                }
+
                 r = setup_namespace(
                                 context->read_write_dirs,
                                 context->read_only_dirs,
@@ -1592,7 +1599,7 @@ static int exec_child(
                                 tmp,
                                 var,
                                 params->bus_endpoint_path,
-                                context->private_devices,
+                                private_dev_dir,
                                 context->protect_home,
                                 context->protect_system,
                                 context->mount_flags);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 4fecd32..4967cf4 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -234,7 +234,13 @@ static int mount_dev(BindMount *m) {
 
         dev_setup(temporary_mount);
 
-        if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) {
+        /* Create the /dev directory if missing. It is more likely to be
+         * missing when the service is started with RootDirectory. This is
+         * consistent with mount units creating the mount points when missing.
+         */
+        mkdir_p_label (m->path, 0755);
+
+        if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
                 r = -errno;
                 goto fail;
         }
@@ -419,7 +425,7 @@ int setup_namespace(
                 const char* tmp_dir,
                 const char* var_tmp_dir,
                 const char* bus_endpoint_path,
-                bool private_dev,
+                const char* private_dev_dir,
                 ProtectHome protect_home,
                 ProtectSystem protect_system,
                 unsigned long mount_flags) {
@@ -438,7 +444,7 @@ int setup_namespace(
                 strv_length(read_write_dirs) +
                 strv_length(read_only_dirs) +
                 strv_length(inaccessible_dirs) +
-                private_dev +
+                !!private_dev_dir +
                 (protect_home != PROTECT_HOME_NO ? 3 : 0) +
                 (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) +
                 (protect_system == PROTECT_SYSTEM_FULL ? 1 : 0);
@@ -469,8 +475,8 @@ int setup_namespace(
                         m++;
                 }
 
-                if (private_dev) {
-                        m->path = "/dev";
+                if (private_dev_dir) {
+                        m->path = private_dev_dir;
                         m->mode = PRIVATE_DEV;
                         m++;
                 }
diff --git a/src/core/namespace.h b/src/core/namespace.h
index 42b92e7..4b06802 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -47,7 +47,7 @@ int setup_namespace(char **read_write_dirs,
                     const char *tmp_dir,
                     const char *var_tmp_dir,
                     const char *endpoint_path,
-                    bool private_dev,
+                    const char *private_dev_dir,
                     ProtectHome protect_home,
                     ProtectSystem protect_system,
                     unsigned long mount_flags);
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index 7cd7b77..d973d0d 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -60,7 +60,7 @@ int main(int argc, char *argv[]) {
                             tmp_dir,
                             var_tmp_dir,
                             NULL,
-                            true,
+                            "/dev",
                             PROTECT_HOME_NO,
                             PROTECT_SYSTEM_NO,
                             0);
-- 
2.1.4



More information about the systemd-devel mailing list