]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined: add new OpenRootDirectory() call to Machine objects
authorLennart Poettering <lennart@poettering.net>
Mon, 25 Apr 2016 09:13:16 +0000 (11:13 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 25 Apr 2016 13:24:46 +0000 (15:24 +0200)
This new call returns a file descriptor for the root directory of a container.
This file descriptor may then be used to access the rest of the container's
file system, via openat() and similar calls. Since the file descriptor returned
is for the file system namespace inside of the container it may be used to
access all files of the container exactly the way the container itself would
see them. This is particularly useful for containers run directly from
loopback media, for example via systemd-nspawn's --image= switch. It also
provides access to directories such as /run of a container that are normally
not accessible to the outside of a container.

This replaces PR #2870.

Fixes: #2870
src/machine/machine-dbus.c
src/machine/machine-dbus.h
src/machine/machined-dbus.c

index ab54d9e93427b4c02344b109c9940cb4e059216c..5121bfdd18fabd296aa80be5dc6e94af8a088499 100644 (file)
@@ -1274,6 +1274,97 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
         return 1;
 }
 
+int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_close_ int fd = -1;
+        Machine *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = bus_verify_polkit_async(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.machine1.manage-machines",
+                        NULL,
+                        false,
+                        UID_INVALID,
+                        &m->manager->polkit_registry,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Will call us back */
+
+        switch (m->class) {
+
+        case MACHINE_HOST:
+                fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                if (fd < 0)
+                        return -errno;
+
+                break;
+
+        case MACHINE_CONTAINER: {
+                _cleanup_close_ int mntns_fd = -1, root_fd = -1;
+                _cleanup_close_pair_ int pair[2] = { -1, -1 };
+                siginfo_t si;
+                pid_t child;
+
+                r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
+                if (r < 0)
+                        return r;
+
+                if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+                        return -errno;
+
+                child = fork();
+                if (child < 0)
+                        return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+
+                if (child == 0) {
+                        _cleanup_close_ int dfd = -1;
+
+                        pair[0] = safe_close(pair[0]);
+
+                        r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
+                        if (r < 0)
+                                _exit(EXIT_FAILURE);
+
+                        dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                        if (dfd < 0)
+                                _exit(EXIT_FAILURE);
+
+                        r = send_one_fd(pair[1], dfd, 0);
+                        dfd = safe_close(dfd);
+                        if (r < 0)
+                                _exit(EXIT_FAILURE);
+
+                        _exit(EXIT_SUCCESS);
+                }
+
+                pair[1] = safe_close(pair[1]);
+
+                r = wait_for_terminate(child, &si);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
+                if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+
+                fd = receive_one_fd(pair[0], MSG_DONTWAIT);
+                if (fd < 0)
+                        return fd;
+
+                break;
+        }
+
+        default:
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
+        }
+
+        return sd_bus_reply_method_return(message, "h", fd);
+}
+
 const sd_bus_vtable machine_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1297,6 +1388,7 @@ const sd_bus_vtable machine_vtable[] = {
         SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_VTABLE_END
 };
 
index 3a8162b1712d53b647819947ab9538efb0a47323..241b23c7ecc55de3f7e586246fa6eefce7093f7d 100644 (file)
@@ -38,6 +38,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
 int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
 int machine_send_signal(Machine *m, bool new_machine);
 int machine_send_create_reply(Machine *m, sd_bus_error *error);
index c9639c3cf26eead2404c443b71ed402ec389acea..31efa3695bba9cb60129fdcb9f33924d9d9f5d86 100644 (file)
@@ -706,6 +706,26 @@ static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_e
         return bus_machine_method_copy(message, machine, error);
 }
 
+static int method_open_machine_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        Machine *machine;
+        const char *name;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return r;
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        return bus_machine_method_open_root_directory(message, machine, error);
+}
+
 static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image* i = NULL;
         const char *name;
@@ -1225,6 +1245,7 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),