Blob Blame History Raw
From a610cc4f18c24a007e5a2cac21b2ecbd81e5f3c3 Mon Sep 17 00:00:00 2001
From: Daniel Mack <zonque@gmail.com>
Date: Fri, 22 Aug 2014 18:55:21 +0200
Subject: [PATCH] namespace: add support for custom kdbus endpoint

If a path to a previously created custom kdbus endpoint is passed in,
bind-mount a new devtmpfs that contains a 'bus' node, which in turn in
bind-mounted with the custom endpoint. This tmpfs then mounted over the
kdbus subtree that refers to the current bus.

This way, we can fake the bus node in order to lock down services with
a kdbus custom endpoint policy.
---
 src/core/execute.c   |  1 +
 src/core/namespace.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/core/namespace.h |  1 +
 src/test/test-ns.c   |  1 +
 4 files changed, 93 insertions(+), 1 deletion(-)

diff --git a/src/core/execute.c b/src/core/execute.c
index a88e1b1953..96cabe6d99 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1523,6 +1523,7 @@ static int exec_child(ExecCommand *command,
                                 context->inaccessible_dirs,
                                 tmp,
                                 var,
+                                NULL,
                                 context->private_devices,
                                 context->protect_home,
                                 context->protect_system,
diff --git a/src/core/namespace.c b/src/core/namespace.c
index fe95377871..eaaebdd644 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -51,6 +51,7 @@ typedef enum MountMode {
         PRIVATE_TMP,
         PRIVATE_VAR_TMP,
         PRIVATE_DEV,
+        PRIVATE_BUS_ENDPOINT,
         READWRITE
 } MountMode;
 
@@ -272,6 +273,84 @@ fail:
         return r;
 }
 
+static int mount_kdbus(BindMount *m) {
+
+        char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX";
+        _cleanup_free_ char *basepath = NULL;
+        _cleanup_umask_ mode_t u;
+        char *busnode, *root;
+        struct stat st;
+        int r;
+
+        assert(m);
+
+        u = umask(0000);
+
+        if (!mkdtemp(temporary_mount)) {
+                log_error("Failed create temp dir: %m");
+                return -errno;
+        }
+
+        root = strappenda(temporary_mount, "/kdbus");
+        mkdir(root, 0755);
+        if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* create a new /dev/null dev node copy so we have some fodder to
+         * bind-mount the custom endpoint over. */
+        if (stat("/dev/null", &st) < 0) {
+                log_error("Failed to stat /dev/null: %m");
+                r = -errno;
+                goto fail;
+        }
+
+        busnode = strappenda(root, "/bus");
+        if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
+                log_error("mknod() for %s failed: %m", busnode);
+                r = -errno;
+                goto fail;
+        }
+
+        r = mount(m->path, busnode, "bind", MS_BIND, NULL);
+        if (r < 0) {
+                log_error("bind mount of %s failed: %m", m->path);
+                r = -errno;
+                goto fail;
+        }
+
+        basepath = dirname_malloc(m->path);
+        if (!basepath) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
+                log_error("bind mount of %s failed: %m", basepath);
+                r = -errno;
+                goto fail;
+        }
+
+        rmdir(temporary_mount);
+        return 0;
+
+fail:
+        if (busnode) {
+                umount(busnode);
+                unlink(busnode);
+        }
+
+        if (root) {
+                umount(root);
+                rmdir(root);
+        }
+
+        rmdir(temporary_mount);
+
+        return r;
+}
+
 static int apply_mount(
                 BindMount *m,
                 const char *tmp_dir,
@@ -311,6 +390,9 @@ static int apply_mount(
         case PRIVATE_DEV:
                 return mount_dev(m);
 
+        case PRIVATE_BUS_ENDPOINT:
+                return mount_kdbus(m);
+
         default:
                 assert_not_reached("Unknown mode");
         }
@@ -350,6 +432,7 @@ int setup_namespace(
                 char** inaccessible_dirs,
                 char* tmp_dir,
                 char* var_tmp_dir,
+                char* bus_endpoint_path,
                 bool private_dev,
                 ProtectHome protect_home,
                 ProtectSystem protect_system,
@@ -365,7 +448,7 @@ int setup_namespace(
         if (unshare(CLONE_NEWNS) < 0)
                 return -errno;
 
-        n = !!tmp_dir + !!var_tmp_dir +
+        n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
                 strv_length(read_write_dirs) +
                 strv_length(read_only_dirs) +
                 strv_length(inaccessible_dirs) +
@@ -406,6 +489,12 @@ int setup_namespace(
                         m++;
                 }
 
+                if (bus_endpoint_path) {
+                        m->path = bus_endpoint_path;
+                        m->mode = PRIVATE_BUS_ENDPOINT;
+                        m++;
+                }
+
                 if (protect_home != PROTECT_HOME_NO) {
                         r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
                         if (r < 0)
diff --git a/src/core/namespace.h b/src/core/namespace.h
index 9343fe3264..9cd420e958 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -46,6 +46,7 @@ int setup_namespace(char **read_write_dirs,
                     char **inaccessible_dirs,
                     char *tmp_dir,
                     char *var_tmp_dir,
+                    char *endpoint_path,
                     bool private_dev,
                     ProtectHome protect_home,
                     ProtectSystem protect_system,
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index acad725899..7714e49ad9 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -59,6 +59,7 @@ int main(int argc, char *argv[]) {
                             (char **) inaccessible,
                             tmp_dir,
                             var_tmp_dir,
+                            NULL,
                             true,
                             PROTECT_HOME_NO,
                             PROTECT_SYSTEM_NO,