summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2021-01-22 17:49:11 +0000
committerGitHub <noreply@github.com>2021-01-22 17:49:11 +0000
commit95457dc13cc5fba332c44cbe3aa35e2fa129588f (patch)
tree1833a55106b31291787a9a317cadaa5e5daef982 /src/core
parent42e6f5497963162643f9da06384b0c9f0755d229 (diff)
parent6faecbd353f9eb5aebe65a7159c5e61191e4330f (diff)
downloadsystemd-95457dc13cc5fba332c44cbe3aa35e2fa129588f.tar.gz
Merge pull request #18302 from bluca/mount_image_runtime
systemctl/core: add DBUS method to mount images without service restart
Diffstat (limited to 'src/core')
-rw-r--r--src/core/dbus-execute.c72
-rw-r--r--src/core/dbus-manager.c16
-rw-r--r--src/core/dbus-service.c50
-rw-r--r--src/core/dbus-service.h1
-rw-r--r--src/core/dbus-util.c76
-rw-r--r--src/core/dbus-util.h3
-rw-r--r--src/core/namespace.c66
-rw-r--r--src/core/org.freedesktop.systemd1.conf8
8 files changed, 149 insertions, 143 deletions
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 20403df819..8434ccb48e 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1497,74 +1497,6 @@ static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint6
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
-/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */
-static int read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator) {
- _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
- _cleanup_free_ char *format_str = NULL;
- const char *mount_options, *partition;
- int r;
-
- assert(message);
- assert(ret_options);
- assert(ret_format_str);
- assert(separator);
-
- r = sd_bus_message_enter_container(message, 'a', "(ss)");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
- _cleanup_free_ char *previous = NULL, *escaped = NULL;
- _cleanup_free_ MountOptions *o = NULL;
- PartitionDesignator partition_designator;
-
- if (chars_intersect(mount_options, WHITESPACE))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Invalid mount options string, contains whitespace character(s): %s", mount_options);
-
- partition_designator = partition_designator_from_string(partition);
- if (partition_designator < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
-
- /* Need to store them in the unit with the escapes, so that they can be parsed again */
- escaped = shell_escape(mount_options, ":");
- if (!escaped)
- return -ENOMEM;
-
- previous = TAKE_PTR(format_str);
- format_str = strjoin(previous, previous ? separator : "", partition, ":", escaped);
- if (!format_str)
- return -ENOMEM;
-
- o = new(MountOptions, 1);
- if (!o)
- return -ENOMEM;
- *o = (MountOptions) {
- .partition_designator = partition_designator,
- .options = strdup(mount_options),
- };
- if (!o->options)
- return -ENOMEM;
- LIST_APPEND(mount_options, options, TAKE_PTR(o));
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (!LIST_IS_EMPTY(options)) {
- char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str);
- if (!final)
- return -ENOMEM;
- free_and_replace(*ret_format_str, final);
- LIST_JOIN(mount_options, *ret_options, options);
- }
-
- return 0;
-}
-
int bus_exec_context_set_transient_property(
Unit *u,
ExecContext *c,
@@ -1599,7 +1531,7 @@ int bus_exec_context_set_transient_property(
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
_cleanup_free_ char *format_str = NULL;
- r = read_mount_options(message, error, &options, &format_str, " ");
+ r = bus_read_mount_options(message, error, &options, &format_str, " ");
if (r < 0)
return r;
@@ -3407,7 +3339,7 @@ int bus_exec_context_set_transient_property(
return -ENOMEM;
free_and_replace(format_str, tuple);
- r = read_mount_options(message, error, &options, &format_str, ":");
+ r = bus_read_mount_options(message, error, &options, &format_str, ":");
if (r < 0)
return r;
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 4b88f0d9f0..eeb74353da 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -731,6 +731,11 @@ static int method_bind_mount_unit(sd_bus_message *message, void *userdata, sd_bu
return method_generic_unit_operation(message, userdata, error, bus_service_method_bind_mount, GENERIC_UNIT_VALIDATE_LOADED);
}
+static int method_mount_image_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ /* Only add mounts on fully loaded units */
+ return method_generic_unit_operation(message, userdata, error, bus_service_method_mount_image, GENERIC_UNIT_VALIDATE_LOADED);
+}
+
static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
/* Only allow reffing of fully loaded units, and make sure reffing a unit loads it. */
return method_generic_unit_operation(message, userdata, error, bus_unit_method_ref, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED);
@@ -2776,6 +2781,17 @@ const sd_bus_vtable bus_manager_vtable[] = {
NULL,,
method_bind_mount_unit,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("MountImageUnit",
+ "sssbba(ss)",
+ SD_BUS_PARAM(name)
+ SD_BUS_PARAM(source)
+ SD_BUS_PARAM(destination)
+ SD_BUS_PARAM(read_only)
+ SD_BUS_PARAM(mkdir)
+ SD_BUS_PARAM(options),
+ NULL,,
+ method_mount_image_unit,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("RefUnit",
"s",
SD_BUS_PARAM(name),
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6df93e44a4..f7cdb51eba 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -95,9 +95,10 @@ static int property_get_exit_status_set(
return sd_bus_message_close_container(reply);
}
-int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- int read_only, make_file_or_directory;
+static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_bus_error *error, bool is_image) {
+ _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
const char *dest, *src, *propagate_directory;
+ int read_only, make_file_or_directory;
Unit *u = userdata;
ExecContext *c;
pid_t unit_pid;
@@ -120,16 +121,22 @@ int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
if (!path_is_absolute(src) || !path_is_normalized(src))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
- if (isempty(dest))
+ if (!is_image && isempty(dest))
dest = src;
else if (!path_is_absolute(dest) || !path_is_normalized(dest))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
+ if (is_image) {
+ r = bus_read_mount_options(message, error, &options, NULL, "");
+ if (r < 0)
+ return r;
+ }
+
r = bus_verify_manage_units_async_full(
u,
- "bind-mount",
+ is_image ? "mount-image" : "bind-mount",
CAP_SYS_ADMIN,
- N_("Authentication is required to bind mount on '$(unit)'."),
+ N_("Authentication is required to mount on '$(unit)'."),
true,
message,
error);
@@ -158,16 +165,30 @@ int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running");
propagate_directory = strjoina("/run/systemd/propagate/", u->id);
- r = bind_mount_in_namespace(unit_pid,
- propagate_directory,
- "/run/systemd/incoming/",
- src, dest, read_only, make_file_or_directory);
+ if (is_image)
+ r = mount_image_in_namespace(unit_pid,
+ propagate_directory,
+ "/run/systemd/incoming/",
+ src, dest, read_only, make_file_or_directory, options);
+ else
+ r = bind_mount_in_namespace(unit_pid,
+ propagate_directory,
+ "/run/systemd/incoming/",
+ src, dest, read_only, make_file_or_directory);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in unit's namespace: %m", src, dest);
return sd_bus_reply_method_return(message, NULL);
}
+int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_service_method_mount(message, userdata, error, false);
+}
+
+int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_service_method_mount(message, userdata, error, true);
+}
+
const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -233,6 +254,17 @@ const sd_bus_vtable bus_service_vtable[] = {
bus_service_method_bind_mount,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("MountImage",
+ "ssbba(ss)",
+ SD_BUS_PARAM(source)
+ SD_BUS_PARAM(destination)
+ SD_BUS_PARAM(read_only)
+ SD_BUS_PARAM(mkdir)
+ SD_BUS_PARAM(options),
+ NULL,,
+ bus_service_method_mount_image,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
/* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
index 5b7b7b757b..9a05465802 100644
--- a/src/core/dbus-service.h
+++ b/src/core/dbus-service.h
@@ -10,4 +10,5 @@ extern const sd_bus_vtable bus_service_vtable[];
int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitWriteFlags flags, sd_bus_error *error);
int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_service_commit_properties(Unit *u);
diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
index 2d22bc699a..6a6dd1ff41 100644
--- a/src/core/dbus-util.c
+++ b/src/core/dbus-util.c
@@ -3,6 +3,7 @@
#include "bus-polkit.h"
#include "bus-util.h"
#include "dbus-util.h"
+#include "escape.h"
#include "parse-util.h"
#include "path-util.h"
#include "unit-printf.h"
@@ -186,3 +187,78 @@ int bus_verify_manage_units_async_full(
&u->manager->polkit_registry,
error);
}
+
+/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */
+int bus_read_mount_options(
+ sd_bus_message *message,
+ sd_bus_error *error,
+ MountOptions **ret_options,
+ char **ret_format_str,
+ const char *separator) {
+
+ _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
+ _cleanup_free_ char *format_str = NULL;
+ const char *mount_options, *partition;
+ int r;
+
+ assert(message);
+ assert(ret_options);
+ assert(separator);
+
+ r = sd_bus_message_enter_container(message, 'a', "(ss)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
+ _cleanup_free_ char *previous = NULL, *escaped = NULL;
+ _cleanup_free_ MountOptions *o = NULL;
+ PartitionDesignator partition_designator;
+
+ if (chars_intersect(mount_options, WHITESPACE))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Invalid mount options string, contains whitespace character(s): %s", mount_options);
+
+ partition_designator = partition_designator_from_string(partition);
+ if (partition_designator < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
+
+ /* Need to store the options with the escapes, so that they can be parsed again */
+ escaped = shell_escape(mount_options, ":");
+ if (!escaped)
+ return -ENOMEM;
+
+ previous = TAKE_PTR(format_str);
+ format_str = strjoin(previous, previous ? separator : "", partition, ":", escaped);
+ if (!format_str)
+ return -ENOMEM;
+
+ o = new(MountOptions, 1);
+ if (!o)
+ return -ENOMEM;
+ *o = (MountOptions) {
+ .partition_designator = partition_designator,
+ .options = strdup(mount_options),
+ };
+ if (!o->options)
+ return -ENOMEM;
+ LIST_APPEND(mount_options, options, TAKE_PTR(o));
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (!LIST_IS_EMPTY(options)) {
+ if (ret_format_str) {
+ char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str);
+ if (!final)
+ return -ENOMEM;
+ free_and_replace(*ret_format_str, final);
+ }
+ LIST_JOIN(mount_options, *ret_options, options);
+ }
+
+ return 0;
+}
diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
index e35c632d37..bd4fd081c5 100644
--- a/src/core/dbus-util.h
+++ b/src/core/dbus-util.h
@@ -3,6 +3,7 @@
#include "sd-bus.h"
+#include "dissect-image.h"
#include "unit.h"
int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
@@ -249,3 +250,5 @@ static inline int bus_set_transient_usec_fix_0(Unit *u, const char *name, usec_t
return bus_set_transient_usec_internal(u, name, p, true, message, flags, error);
}
int bus_verify_manage_units_async_full(Unit *u, const char *verb, int capability, const char *polkit_message, bool interactive, sd_bus_message *call, sd_bus_error *error);
+
+int bus_read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 12d9e4c867..db9a12319d 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -962,75 +962,13 @@ static int mount_run(const MountEntry *m) {
}
static int mount_images(const MountEntry *m) {
- _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
- _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
- DissectImageFlags dissect_image_flags;
int r;
assert(m);
- r = verity_settings_load(&verity, mount_entry_source(m), NULL, NULL);
- if (r < 0)
- return log_debug_errno(r, "Failed to load root hash: %m");
-
- dissect_image_flags =
- (m->read_only ? DISSECT_IMAGE_READ_ONLY : 0) |
- (verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0);
-
- r = loop_device_make_by_path(
- mount_entry_source(m),
- m->read_only ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */,
- verity.data_path ? 0 : LO_FLAGS_PARTSCAN,
- &loop_device);
- if (r < 0)
- return log_debug_errno(r, "Failed to create loop device for image: %m");
-
- r = dissect_image(
- loop_device->fd,
- &verity,
- m->image_options,
- dissect_image_flags,
- &dissected_image);
- /* No partition table? Might be a single-filesystem image, try again */
- if (!verity.data_path && r == -ENOPKG)
- r = dissect_image(
- loop_device->fd,
- &verity,
- m->image_options,
- dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE,
- &dissected_image);
- if (r < 0)
- return log_debug_errno(r, "Failed to dissect image: %m");
-
- r = dissected_image_decrypt(
- dissected_image,
- NULL,
- &verity,
- dissect_image_flags,
- &decrypted_image);
- if (r < 0)
- return log_debug_errno(r, "Failed to decrypt dissected image: %m");
-
- r = mkdir_p_label(mount_entry_path(m), 0755);
- if (r < 0)
- return log_debug_errno(r, "Failed to create destination directory %s: %m", mount_entry_path(m));
- r = umount_recursive(mount_entry_path(m), 0);
- if (r < 0)
- return log_debug_errno(r, "Failed to umount under destination directory %s: %m", mount_entry_path(m));
-
- r = dissected_image_mount(dissected_image, mount_entry_path(m), UID_INVALID, dissect_image_flags);
+ r = verity_dissect_and_mount(mount_entry_source(m), mount_entry_path(m), m->image_options);
if (r < 0)
- return log_debug_errno(r, "Failed to mount image: %m");
-
- if (decrypted_image) {
- r = decrypted_image_relinquish(decrypted_image);
- if (r < 0)
- return log_debug_errno(r, "Failed to relinquish decrypted image: %m");
- }
-
- loop_device_relinquish(loop_device);
+ return log_debug_errno(r, "Failed to mount image %s on %s: %m", mount_entry_source(m), mount_entry_path(m));
return 1;
}
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 0cea4d2b02..f405b27658 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -228,6 +228,10 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="MountImageUnit"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="KillUnit"/>
<allow send_destination="org.freedesktop.systemd1"
@@ -400,6 +404,10 @@
send_interface="org.freedesktop.systemd1.Service"
send_member="BindMount"/>
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Service"
+ send_member="MountImage"/>
+
<!-- Managed via polkit or other criteria: org.freedesktop.systemd1.Scope interface -->
<allow send_destination="org.freedesktop.systemd1"