1
0
mirror of https://github.com/systemd/systemd synced 2024-07-08 20:15:55 +00:00

core/credential,mount: re-read /proc/self/mountinfo before invoking umount command

When a unit has credentials, stopping the service unmounts the credentials
directory. On shutdown, stopping the service and the corresponding mount
unit may be done mostly simultaneously, and if we invoke umount command soon
after umount() being called on stopping the service, the mount unit will
fail.

This makes Mount.invalidated_state flag set when umount() is called for a path,
and re-read /proc/self/mouninfo before invoking umount command if the flag is set.

Fixes #25527.
Replaces #26959.
This commit is contained in:
Yu Watanabe 2023-08-24 23:41:05 +09:00
parent 25033cca08
commit 1e1225614c
5 changed files with 45 additions and 6 deletions

View File

@ -12,6 +12,7 @@
#include "label-util.h"
#include "mkdir-label.h"
#include "mount-util.h"
#include "mount.h"
#include "mountpoint-util.h"
#include "process-util.h"
#include "random-util.h"
@ -138,19 +139,21 @@ int unit_add_default_credential_dependencies(Unit *u, const ExecContext *c) {
return unit_add_dependency_by_name(u, UNIT_AFTER, m, /* add_reference= */ true, UNIT_DEPENDENCY_FILE);
}
int exec_context_destroy_credentials(const ExecContext *c, const char *runtime_prefix, const char *unit) {
int exec_context_destroy_credentials(Unit *u) {
_cleanup_free_ char *p = NULL;
int r;
assert(c);
assert(u);
r = get_credential_directory(runtime_prefix, unit, &p);
r = get_credential_directory(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], u->id, &p);
if (r <= 0)
return r;
/* This is either a tmpfs/ramfs of its own, or a plain directory. Either way, let's first try to
* unmount it, and afterwards remove the mount point */
(void) umount2(p, MNT_DETACH|UMOUNT_NOFOLLOW);
if (umount2(p, MNT_DETACH|UMOUNT_NOFOLLOW) >= 0)
(void) mount_invalidate_state_by_path(u->manager, p);
(void) rm_rf(p, REMOVE_ROOT|REMOVE_CHMOD);
return 0;

View File

@ -45,7 +45,7 @@ int exec_context_get_credential_directory(
int unit_add_default_credential_dependencies(Unit *u, const ExecContext *c);
int exec_context_destroy_credentials(const ExecContext *c, const char *runtime_root, const char *unit);
int exec_context_destroy_credentials(Unit *u);
int exec_setup_credentials(
const ExecContext *context,
const ExecParameters *params,

View File

@ -1284,6 +1284,11 @@ static int mount_stop(Unit *u) {
assert(m);
/* When we directly call umount() for a path, then the state of the corresponding mount unit may be
* outdated. Let's re-read mountinfo now and update the state. */
if (m->invalidated_state)
(void) mount_process_proc_self_mountinfo(u->manager);
switch (m->state) {
case MOUNT_UNMOUNTING:
@ -1318,6 +1323,11 @@ static int mount_stop(Unit *u) {
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS);
return 0;
case MOUNT_DEAD:
case MOUNT_FAILED:
/* The mount has just been unmounted by somebody else. */
return 0;
default:
assert_not_reached();
}
@ -2067,6 +2077,8 @@ static int mount_process_proc_self_mountinfo(Manager *m) {
LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
Mount *mount = MOUNT(u);
mount->invalidated_state = false;
if (!mount_is_mounted(mount)) {
/* A mount point is not around right now. It might be gone, or might never have
@ -2160,6 +2172,26 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
return mount_process_proc_self_mountinfo(m);
}
int mount_invalidate_state_by_path(Manager *manager, const char *path) {
_cleanup_free_ char *name = NULL;
Unit *u;
int r;
assert(manager);
assert(path);
r = unit_name_from_path(path, ".mount", &name);
if (r < 0)
return log_debug_errno(r, "Failed to generate unit name from path \"%s\", ignoring: %m", path);
u = manager_get_unit(manager, name);
if (!u)
return -ENOENT;
MOUNT(u)->invalidated_state = true;
return 0;
}
static void mount_reset_failed(Unit *u) {
Mount *m = MOUNT(u);

View File

@ -49,6 +49,8 @@ struct Mount {
MountParameters parameters_proc_self_mountinfo;
MountParameters parameters_fragment;
bool invalidated_state:1; /* Set when the 'state' of the mount unit may be outdated, and we need to
* re-read /proc/self/mountinfo. */
bool from_proc_self_mountinfo:1;
bool from_fragment:1;
@ -92,6 +94,8 @@ extern const UnitVTable mount_vtable;
void mount_fd_event(Manager *m, int events);
int mount_invalidate_state_by_path(Manager *manager, const char *path);
const char* mount_exec_command_to_string(MountExecCommand i) _const_;
MountExecCommand mount_exec_command_from_string(const char *s) _pure_;

View File

@ -5994,7 +5994,7 @@ void unit_destroy_runtime_data(Unit *u, const ExecContext *context) {
if (context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
exec_context_destroy_runtime_directory(context, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
exec_context_destroy_credentials(context, u->manager->prefix[EXEC_DIRECTORY_RUNTIME], u->id);
exec_context_destroy_credentials(u);
exec_context_destroy_mount_ns_dir(u);
}