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