diff --git a/src/nsresourced/userns-registry.c b/src/nsresourced/userns-registry.c index 50efcd1153..a9e3f82e59 100644 --- a/src/nsresourced/userns-registry.c +++ b/src/nsresourced/userns-registry.c @@ -838,9 +838,11 @@ int userns_registry_remove(int dir_fd, UserNamespaceInfo *info) { continue; } - _cleanup_free_ char *delegate_uid_fn = NULL; + _cleanup_free_ char *delegate_uid_fn = NULL, *delegate_gid_fn = NULL; if (asprintf(&delegate_uid_fn, "u" UID_FMT ".delegate", delegate->start_uid) < 0) return log_oom_debug(); + if (asprintf(&delegate_gid_fn, "g" GID_FMT ".delegate", delegate->start_gid) < 0) + return log_oom_debug(); if (existing.n_ancestor_userns > 0) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *delegate_def = NULL, *ancestor_array = NULL; @@ -876,10 +878,18 @@ int userns_registry_remove(int dir_fd, UserNamespaceInfo *info) { return log_debug_errno(r, "Failed to format delegation JSON object: %m"); r = write_string_file_at(dir_fd, delegate_uid_fn, delegate_buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); - if (r < 0) + if (r < 0) { RET_GATHER(ret, log_debug_errno(r, "Failed to write restored delegation data to '%s' in registry: %m", delegate_uid_fn)); + continue; + } + + /* The atomic write above replaced the UID file with a new inode, so the + * hardlink to the GID file is now broken. Re-create it to keep the two in + * sync. */ + r = linkat_replace(dir_fd, delegate_uid_fn, dir_fd, delegate_gid_fn); + if (r < 0) + RET_GATHER(ret, log_debug_errno(r, "Failed to re-link '%s' to '%s' in registry: %m", delegate_uid_fn, delegate_gid_fn)); - /* GID link already points to the UID file, no need to update it */ continue; } @@ -891,10 +901,6 @@ int userns_registry_remove(int dir_fd, UserNamespaceInfo *info) { if (r < 0) RET_GATHER(ret, log_debug_errno(r, "Failed to remove %s: %m", delegate_uid_fn)); - _cleanup_free_ char *delegate_gid_fn = NULL; - if (asprintf(&delegate_gid_fn, "g" GID_FMT ".delegate", delegate->start_gid) < 0) - return log_oom_debug(); - r = RET_NERRNO(unlinkat(dir_fd, delegate_gid_fn, 0)); if (r < 0) RET_GATHER(ret, log_debug_errno(r, "Failed to remove %s: %m", delegate_gid_fn));