OpenSSH 2.9p1: lastlog_get_entry() should be more careful

Patrick J. LoPresti patl at curl.com
Tue Jun 5 01:01:15 EST 2001


In OpenSSH 2.9p1, the function loginrec.c:lastlog_get_entry() looks
like this:

int
lastlog_get_entry(struct logininfo *li)
{
	struct lastlog last;
	int fd;

	if (lastlog_openseek(li, &fd, O_RDONLY)) {
		if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) {
			log("lastlog_get_entry: Error reading from %s: %s",
			    LASTLOG_FILE, strerror(errno));
			return 0;
		} else {
			lastlog_populate_entry(li, &last);
			return 1;
		}
	} else {
		return 0;
	}
}


On Linux (at least version 2.2.19), the call to lastlog_openseek() can
succeed even when the /var/log/lastlog file is short (e.g., 0 bytes).
Subsequent calls to read() on the file descriptor return zero (EOF).
Consequently, the call to atomicio in the function above returns zero,
causing OpenSSH to log a bogus error message by examining a bogus
errno value.

I suggest that the call to atomicio() be checked to see if it returns
zero, with no error message generated for this case.  That is, I
suggest the function be rewritten something like this:

int
lastlog_get_entry(struct logininfo *li)
{
	struct lastlog last;
	int fd;

	if (lastlog_openseek(li, &fd, O_RDONLY)) {
		int ret = atomicio(read, fd, &last, sizeof(last));

		if (ret == sizeof(last)) {
			lastlog_populate_entry(li, &last);
			return 1;
                } else if (ret == 0) {
			return 0;
		} else {
			log("lastlog_get_entry: Error reading from %s: %s",
			    LASTLOG_FILE, strerror(errno));
			return 0;
		}
	} else {
		return 0;
	}
}


The above is just for illustration; it is still not quite correct.
Strictly speaking, you should not examine errno unless atomicio()
returns a negative value, because a short read will not set errno
either.

 - Pat



More information about the openssh-unix-dev mailing list