This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/6634] New: pututline_file() corrupts utmp file when internal_getut_r() returns -1 due to LOCK_FILE timeout.


The 'pututline' utmp entry insertion function can corrupt
the utmp file with duplicate entries when the system is busy.

Root cause:

If the utmp entry already exists and the timeout for the lock (re:LOCK_FILE) in
internal_getur_r() expires internal_getur_r() returns -1 to pututline_file().


The pututline_file() function incorrectly interprets the -1 return value as
"entry not found" rather than "lock timed out" AND then incorrectly appends a
duplicate entry to the utmp file.

This can happen whenever there are simultaneous pututline executions and the
system is under a high enough load to cause the lock to time out.

The program logic needs to be repaired to assure that a lock timeout will never
cause a duplicate entry to be added.

Perhaps a backoff algorithm could be used to retry the lock or the lock timeout
could be increased as well to accommodate systems under greater stress.

The problem was identified on an x86 machine.

The macro (FILE_LOCK) expanded version of internal_getur_r follows:

internal_getut_r (const struct utmp *id, struct utmp *buffer)
{
  int result = -1;

  {
    struct flock fl;
    struct sigaction action, old_action;
    unsigned int old_timeout;
    old_timeout = alarm (0);
    action.__sigaction_handler.sa_handler = timeout_handler;
    (__builtin_memset (&action.sa_mask, '\0', sizeof (sigset_t)), 0);
    action.sa_flags = 0;
    __sigaction (14, &action, &old_action);
    alarm (1);
    memset (&fl, '\0', sizeof (struct flock));
    fl.l_type = (0);
    fl.l_whence = 0;
    if (__fcntl_nocancel ((file_fd), 7, &fl) < 0)
      goto unalarm_return;

    if (id->ut_type == 1 || id->ut_type == 2
        || id->ut_type == 4 || id->ut_type == 3)
      {
        while (1)
          {
            if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
                != sizeof (struct utmp))
              {
                (__libc_errno = (3));
                file_offset = -1l;
                goto unlock_return;
              }
            file_offset += sizeof (struct utmp);

            if (id->ut_type == buffer->ut_type)
              break;
          }
      }
    else
      {
        while (1)
          {
            if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
                != sizeof (struct utmp))
              {
                (__libc_errno = (3));
                file_offset = -1l;
                goto unlock_return;
              }
            file_offset += sizeof (struct utmp);
            if (__utmp_equal (buffer, id))
              break;
          }
      }
    result = 0;

  unlock_return:
    fl.l_type = 2;
    __fcntl_nocancel ((file_fd), 7, &fl);
  unalarm_return:alarm (0);
    __sigaction (14, &old_action, ((void *) 0));
    if (old_timeout != 0)
      alarm (old_timeout);
  }
  while (0);

  return result;
}

-- 
           Summary: pututline_file() corrupts utmp file when
                    internal_getut_r() returns -1 due to LOCK_FILE timeout.
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
        AssignedTo: drepper at redhat dot com
        ReportedBy: rsa at us dot ibm dot com
                CC: glibc-bugs at sources dot redhat dot com,suzuki at in
                    dot ibm dot com


http://sourceware.org/bugzilla/show_bug.cgi?id=6634

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]