From: Lennart Poettering Date: Tue, 2 Aug 2022 16:16:21 +0000 (+0200) Subject: repart: when keeping ref to backing inode/devnode, use fd_reopen() rathern than F_DUPFD X-Git-Tag: v252-rc1~537 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38f81e937426993cfc899aa09298f69f00935852;p=thirdparty%2Fsystemd.git repart: when keeping ref to backing inode/devnode, use fd_reopen() rathern than F_DUPFD Via the "backing_fd" variable we intend to pin the backing inode through our entire code. So far we typically created the fd via F_DUPFD_CLOEXEC, and thus any BSD lock taken one the original fd is shared with our backing_fd reference. And if the origina fd is closed but our backing_fd is not, we'll keep the BSD lock open, even if we then reopen the block device through the backing_fd. If hit, this results in a deadlock. Let's fix that by creating the backing_fd via fd_reopen(), so that the locks are no longer shared, and if the original fd is closed all BSD locks on it that are in effect are auto-released. (Note the deadlock is only triggered if multiple operations on the same backing inode are executed, i.e. factory reset, resize and applying of partitions.) Replaces: #24181 --- diff --git a/src/partition/repart.c b/src/partition/repart.c index 8044b2eef7e..893431da2a9 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -1612,9 +1612,9 @@ static int context_load_partition_table( if (*backing_fd < 0) { /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */ - *backing_fd = fcntl(fdisk_get_devfd(c), F_DUPFD_CLOEXEC, 3); + *backing_fd = fd_reopen(fdisk_get_devfd(c), O_RDONLY|O_CLOEXEC); if (*backing_fd < 0) - return log_error_errno(errno, "Failed to duplicate fdisk fd: %m"); + return log_error_errno(*backing_fd, "Failed to duplicate fdisk fd: %m"); } /* Tell udev not to interfere while we are processing the device */