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