1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-11-11 21:48:50 +01:00

common: Fix a race condition removing stale lockfile.

* common/dotlock.c (read_lockfile): Return the file descriptor when
R_FD is available.
(dotlock_take_unix): Check the case the lockfile was already removed.

--

GnuPG-bug-id: 5884
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2022-03-18 14:33:53 +09:00
parent a30359cecb
commit d94b411f12

View File

@ -526,7 +526,7 @@ maybe_deadlock (dotlock_t h)
has been created on the same node. */ has been created on the same node. */
#ifdef HAVE_POSIX_SYSTEM #ifdef HAVE_POSIX_SYSTEM
static int static int
read_lockfile (dotlock_t h, int *same_node ) read_lockfile (dotlock_t h, int *same_node, int *r_fd)
{ {
char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
names are usually shorter. */ names are usually shorter. */
@ -579,7 +579,11 @@ read_lockfile (dotlock_t h, int *same_node )
nread += res; nread += res;
} }
while (res && nread != expected_len); while (res && nread != expected_len);
close(fd);
if (r_fd)
*r_fd = fd;
else
close(fd);
if (nread < 11) if (nread < 11)
{ {
@ -1027,13 +1031,12 @@ dotlock_take_unix (dotlock_t h, long timeout)
const char *maybe_dead=""; const char *maybe_dead="";
int same_node; int same_node;
int saveerrno; int saveerrno;
int fd;
again: again:
if (h->use_o_excl) if (h->use_o_excl)
{ {
/* No hardlink support - use open(O_EXCL). */ /* No hardlink support - use open(O_EXCL). */
int fd;
do do
{ {
my_set_errno (0); my_set_errno (0);
@ -1103,7 +1106,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
} }
/* Check for stale lock files. */ /* Check for stale lock files. */
if ( (pid = read_lockfile (h, &same_node)) == -1 ) if ( (pid = read_lockfile (h, &same_node, &fd)) == -1 )
{ {
if ( errno != ENOENT ) if ( errno != ENOENT )
{ {
@ -1119,18 +1122,30 @@ dotlock_take_unix (dotlock_t h, long timeout)
{ {
my_info_0 ("Oops: lock already held by us\n"); my_info_0 ("Oops: lock already held by us\n");
h->locked = 1; h->locked = 1;
close (fd);
return 0; /* okay */ return 0; /* okay */
} }
else if ( same_node && kill (pid, 0) && errno == ESRCH ) else if ( same_node && kill (pid, 0) && errno == ESRCH )
{ {
/* Note: It is unlikely that we get a race here unless a pid is struct stat sb;
reused too fast or a new process with the same pid as the one
of the stale file tries to lock right at the same time as we. */ /* Check if it's unlocked during examining the lockfile. */
if (fstat (fd, &sb) || sb.st_nlink == 0)
{
/* It's gone already. */
close (fd);
goto again;
}
close (fd);
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid); my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
unlink (h->lockname); unlink (h->lockname);
goto again; goto again;
} }
close (fd);
if (lastpid == -1) if (lastpid == -1)
lastpid = pid; lastpid = pid;
ownerchanged = (pid != lastpid); ownerchanged = (pid != lastpid);
@ -1277,7 +1292,7 @@ dotlock_release_unix (dotlock_t h)
int pid, same_node; int pid, same_node;
int saveerrno; int saveerrno;
pid = read_lockfile (h, &same_node); pid = read_lockfile (h, &same_node, NULL);
if ( pid == -1 ) if ( pid == -1 )
{ {
saveerrno = errno; saveerrno = errno;