machined: add new OpenRootDirectory() call to Machine objects

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
This commit is contained in:
Lennart Poettering 2016-04-25 11:13:16 +02:00
parent 5d1ce25728
commit ae20320785
3 changed files with 114 additions and 0 deletions

View 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
};

View 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);

View 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),