d8307d
commit 628598be7e1bfaa04f34df71ef6678f2c5103dfd
d8307d
Author: Florian Weimer <fweimer@redhat.com>
d8307d
Date:   Thu Aug 15 16:09:05 2019 +0200
d8307d
d8307d
    login: Disarm timer after utmp lock acquisition [BZ #24879]
d8307d
    
d8307d
    If the file processing takes a long time for some reason, SIGALRM can
d8307d
    arrive while the file is still being processed.  At that point, file
d8307d
    access will fail with EINTR.  Disarming the timer after lock
d8307d
    acquisition avoids that.  (If there was a previous alarm, it is the
d8307d
    responsibility of the caller to deal with the EINTR error.)
d8307d
d8307d
diff --git a/login/utmp_file.c b/login/utmp_file.c
d8307d
index 8b6fee96b623fa90..a736d3d25e005920 100644
d8307d
--- a/login/utmp_file.c
d8307d
+++ b/login/utmp_file.c
d8307d
@@ -55,32 +55,23 @@ static void timeout_handler (int signum) {};
d8307d
 
d8307d
 /* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
d8307d
    operation failed and recovery needs to be performed.
d8307d
-   (file_lock_restore (LOCKING) still needs to be called.)
d8307d
 
d8307d
    file_unlock (FD) removes the lock (which must have been
d8307d
-   acquired).
d8307d
-
d8307d
-   file_lock_restore (LOCKING) is needed to clean up in both
d8307d
-   cases.  */
d8307d
-
d8307d
-struct file_locking
d8307d
-{
d8307d
-  struct sigaction old_action;
d8307d
-  unsigned int old_timeout;
d8307d
-};
d8307d
+   successfully acquired). */
d8307d
 
d8307d
 static bool
d8307d
-try_file_lock (struct file_locking *locking, int fd, int type)
d8307d
+try_file_lock (int fd, int type)
d8307d
 {
d8307d
   /* Cancel any existing alarm.  */
d8307d
-  locking->old_timeout = alarm (0);
d8307d
+  int old_timeout = alarm (0);
d8307d
 
d8307d
   /* Establish signal handler.  */
d8307d
+  struct sigaction old_action;
d8307d
   struct sigaction action;
d8307d
   action.sa_handler = timeout_handler;
d8307d
   __sigemptyset (&action.sa_mask);
d8307d
   action.sa_flags = 0;
d8307d
-  __sigaction (SIGALRM, &action, &locking->old_action);
d8307d
+  __sigaction (SIGALRM, &action, &old_action);
d8307d
 
d8307d
   alarm (TIMEOUT);
d8307d
 
d8307d
@@ -90,7 +81,23 @@ try_file_lock (struct file_locking *locking, int fd, int type)
d8307d
     .l_type = type,
d8307d
     fl.l_whence = SEEK_SET,
d8307d
    };
d8307d
- return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
d8307d
+
d8307d
+ bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
d8307d
+ int saved_errno = errno;
d8307d
+
d8307d
+ /* Reset the signal handler and alarm.  We must reset the alarm
d8307d
+    before resetting the handler so our alarm does not generate a
d8307d
+    spurious SIGALRM seen by the user.  However, we cannot just set
d8307d
+    the user's old alarm before restoring the handler, because then
d8307d
+    it's possible our handler could catch the user alarm's SIGARLM and
d8307d
+    then the user would never see the signal he expected.  */
d8307d
+  alarm (0);
d8307d
+  __sigaction (SIGALRM, &old_action, NULL);
d8307d
+  if (old_timeout != 0)
d8307d
+    alarm (old_timeout);
d8307d
+
d8307d
+  __set_errno (saved_errno);
d8307d
+  return status;
d8307d
 }
d8307d
 
d8307d
 static void
d8307d
@@ -103,21 +110,6 @@ file_unlock (int fd)
d8307d
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
d8307d
 }
d8307d
 
d8307d
-static void
d8307d
-file_lock_restore (struct file_locking *locking)
d8307d
-{
d8307d
-  /* Reset the signal handler and alarm.  We must reset the alarm
d8307d
-     before resetting the handler so our alarm does not generate a
d8307d
-     spurious SIGALRM seen by the user.  However, we cannot just set
d8307d
-     the user's old alarm before restoring the handler, because then
d8307d
-     it's possible our handler could catch the user alarm's SIGARLM
d8307d
-     and then the user would never see the signal he expected.  */
d8307d
-  alarm (0);
d8307d
-  __sigaction (SIGALRM, &locking->old_action, NULL);
d8307d
-  if (locking->old_timeout != 0)
d8307d
-    alarm (locking->old_timeout);
d8307d
-}
d8307d
-
d8307d
 #ifndef TRANSFORM_UTMP_FILE_NAME
d8307d
 # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
d8307d
 #endif
d8307d
@@ -166,8 +158,7 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
d8307d
       return -1;
d8307d
     }
d8307d
 
d8307d
-  struct file_locking fl;
d8307d
-  if (try_file_lock (&fl, file_fd, F_RDLCK))
d8307d
+  if (try_file_lock (file_fd, F_RDLCK))
d8307d
     nbytes = 0;
d8307d
   else
d8307d
     {
d8307d
@@ -175,7 +166,6 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
d8307d
       nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
d8307d
       file_unlock (file_fd);
d8307d
     }
d8307d
-  file_lock_restore (&fl);
d8307d
 
d8307d
   if (nbytes != sizeof (struct utmp))
d8307d
     {
d8307d
@@ -201,11 +191,9 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
d8307d
 {
d8307d
   int result = -1;
d8307d
 
d8307d
-  struct file_locking fl;
d8307d
-  if (try_file_lock (&fl, file_fd, F_RDLCK))
d8307d
+  if (try_file_lock (file_fd, F_RDLCK))
d8307d
     {
d8307d
       *lock_failed = true;
d8307d
-      file_lock_restore (&fl);
d8307d
       return -1;
d8307d
     }
d8307d
 
d8307d
@@ -257,7 +245,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
d8307d
 
d8307d
 unlock_return:
d8307d
   file_unlock (file_fd);
d8307d
-  file_lock_restore (&fl);
d8307d
 
d8307d
   return result;
d8307d
 }
d8307d
@@ -303,11 +290,9 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
d8307d
       return -1;
d8307d
     }
d8307d
 
d8307d
-  struct file_locking fl;
d8307d
-  if (try_file_lock (&fl, file_fd, F_RDLCK))
d8307d
+  if (try_file_lock (file_fd, F_RDLCK))
d8307d
     {
d8307d
       *result = NULL;
d8307d
-      file_lock_restore (&fl);
d8307d
       return -1;
d8307d
     }
d8307d
 
d8307d
@@ -337,7 +322,6 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
d8307d
 
d8307d
 unlock_return:
d8307d
   file_unlock (file_fd);
d8307d
-  file_lock_restore (&fl);
d8307d
 
d8307d
   return ((*result == NULL) ? -1 : 0);
d8307d
 }
d8307d
@@ -394,12 +378,8 @@ __libc_pututline (const struct utmp *data)
d8307d
 	}
d8307d
     }
d8307d
 
d8307d
-  struct file_locking fl;
d8307d
-  if (try_file_lock (&fl, file_fd, F_WRLCK))
d8307d
-    {
d8307d
-      file_lock_restore (&fl);
d8307d
-      return NULL;
d8307d
-    }
d8307d
+  if (try_file_lock (file_fd, F_WRLCK))
d8307d
+    return NULL;
d8307d
 
d8307d
   if (found < 0)
d8307d
     {
d8307d
@@ -442,7 +422,6 @@ __libc_pututline (const struct utmp *data)
d8307d
 
d8307d
  unlock_return:
d8307d
   file_unlock (file_fd);
d8307d
-  file_lock_restore (&fl);
d8307d
 
d8307d
   return pbuf;
d8307d
 }
d8307d
@@ -471,10 +450,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
d8307d
   if (fd < 0)
d8307d
     return -1;
d8307d
 
d8307d
-  struct file_locking fl;
d8307d
-  if (try_file_lock (&fl, fd, F_WRLCK))
d8307d
+  if (try_file_lock (fd, F_WRLCK))
d8307d
     {
d8307d
-      file_lock_restore (&fl);
d8307d
       __close_nocancel_nostatus (fd);
d8307d
       return -1;
d8307d
     }
d8307d
@@ -504,7 +481,6 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
d8307d
 
d8307d
 unlock_return:
d8307d
   file_unlock (fd);
d8307d
-  file_lock_restore (&fl);
d8307d
 
d8307d
   /* Close WTMP file.  */
d8307d
   __close_nocancel_nostatus (fd);