diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 4d2a7bb47e6..8a144519086 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -13,6 +13,7 @@ #include "dbus-service.h" #include "dbus-util.h" #include "execute.h" +#include "exec-credential.h" #include "exit-status.h" #include "fd-util.h" #include "fileio.h" @@ -129,33 +130,36 @@ static int property_get_exit_status_set( } 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 = ASSERT_PTR(userdata); - ExecContext *c; int r; assert(message); if (!MANAGER_IS_SYSTEM(u->manager)) - return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Adding bind mounts at runtime is only supported for system managers."); + return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Adding bind mounts at runtime is only supported by system manager"); + + if (u->type != UNIT_SERVICE) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not of type .service"); r = mac_selinux_unit_access_check(u, message, "start", error); if (r < 0) return r; + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + const char *src, *dest; + int read_only, make_file_or_directory; + r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory); if (r < 0) return r; if (!path_is_absolute(src) || !path_is_normalized(src)) - return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized."); + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized"); if (!is_image && isempty(dest)) dest = src; else if (!path_is_absolute(dest) || !path_is_normalized(dest)) - return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized."); + return sd_bus_error_set(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, ""); @@ -174,26 +178,28 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_ if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - if (u->type != UNIT_SERVICE) - return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not of type .service"); + const PidRef *unit_pid = unit_main_pid(u); + if (!pidref_is_set(unit_pid) || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) + return sd_bus_error_set(error, BUS_ERROR_UNIT_INACTIVE, "Unit is not running"); - /* If it would be dropped at startup time, return an error. The context should always be available, but - * there's an assert in exec_needs_mount_namespace, so double-check just in case. */ - c = unit_get_exec_context(u); + /* The context should always be available, but there's an assert in exec_needs_mount_namespace, + * so double-check just in case. */ + ExecContext *c = unit_get_exec_context(u); if (!c) - return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot access unit execution context"); - if (path_startswith_strv(dest, c->inaccessible_paths)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s is not accessible to this unit", dest); + return -ENXIO; /* Ensure that the unit was started in a private mount namespace */ if (!exec_needs_mount_namespace(c, NULL, unit_get_exec_runtime(u))) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit not running in private mount namespace, cannot activate bind mount"); - PidRef* unit_pid = unit_main_pid(u); - if (!pidref_is_set(unit_pid) || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) - return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running"); + if (mount_point_is_credentials(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], dest)) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Refusing to bind mount over credential mounts"); - propagate_directory = strjoina("/run/systemd/propagate/", u->id); + /* If it would be dropped at startup time, return an error. */ + if (path_startswith_strv(dest, c->inaccessible_paths)) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "%s is not accessible to this unit", dest); + + const char *propagate_directory = strjoina("/run/systemd/propagate/", u->id); if (is_image) r = mount_image_in_namespace( unit_pid, @@ -213,7 +219,7 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_ 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_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); } diff --git a/src/core/exec-credential.c b/src/core/exec-credential.c index 7772a929f02..bce0ee7968e 100644 --- a/src/core/exec-credential.c +++ b/src/core/exec-credential.c @@ -242,6 +242,19 @@ bool exec_context_has_encrypted_credentials(const ExecContext *c) { return false; } +bool mount_point_is_credentials(const char *runtime_prefix, const char *path) { + const char *e; + + assert(runtime_prefix); + assert(path); + + e = path_startswith(path, runtime_prefix); + if (!e) + return false; + + return path_startswith(e, "credentials"); +} + static int get_credential_directory( const char *runtime_prefix, const char *unit, diff --git a/src/core/exec-credential.h b/src/core/exec-credential.h index 88d7f715801..65c9a83b359 100644 --- a/src/core/exec-credential.h +++ b/src/core/exec-credential.h @@ -67,3 +67,5 @@ int exec_setup_credentials( const char *unit, uid_t uid, gid_t gid); + +bool mount_point_is_credentials(const char *runtime_prefix, const char *path); diff --git a/src/core/mount.c b/src/core/mount.c index 61aa8bb590a..3f53b2be7bc 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -11,6 +11,7 @@ #include "dbus-mount.h" #include "dbus-unit.h" #include "device.h" +#include "exec-credential.h" #include "exit-status.h" #include "format-util.h" #include "fs-util.h" @@ -425,22 +426,6 @@ static bool mount_is_extrinsic(Unit *u) { return false; } -static bool mount_point_is_credentials(Manager *manager, const char *path) { - const char *e; - - assert(manager); - assert(path); - - /* Returns true if this is a credentials mount. We don't want to generate mount units for them, - * since their lifetime is strictly bound to services. */ - - e = path_startswith(path, manager->prefix[EXEC_DIRECTORY_RUNTIME]); - if (!e) - return false; - - return !isempty(path_startswith(e, "credentials")); -} - static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, UnitDependencyMask mask) { const char *after, *before, *e; int r; @@ -581,7 +566,7 @@ static int mount_verify(Mount *m) { return log_unit_error_errno(UNIT(m), SYNTHETIC_ERRNO(ENOEXEC), "Cannot create mount unit for API file system '%s'. Refusing.", m->where); - if (mount_point_is_credentials(UNIT(m)->manager, m->where)) + if (mount_point_is_credentials(UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME], m->where)) return log_unit_error_errno(UNIT(m), SYNTHETIC_ERRNO(ENOEXEC), "Cannot create mount unit for credential mount '%s'. Refusing.", m->where); @@ -1830,8 +1815,10 @@ static int mount_setup_unit( assert(fstype); /* Ignore API and credential mount points. They should never be referenced in dependencies ever. - * Also check the comment for mount_point_is_credentials(). */ - if (mount_point_is_api(where) || mount_point_ignore(where) || mount_point_is_credentials(m, where)) + * Furthermore, the lifetime of credential mounts is strictly bound to the owning services, + * so mount units make little sense for them. */ + if (mount_point_is_api(where) || mount_point_ignore(where) || + mount_point_is_credentials(m->prefix[EXEC_DIRECTORY_RUNTIME], where)) return 0; if (streq(fstype, "autofs"))