Subject: bin/23409: last -H ... can blindly print out non-NUL terminated strings
To: None <gnats-bugs@gnats.netbsd.org>
From: None <gcw@primenet.com.au>
List: netbsd-bugs
Date: 11/11/2003 16:20:32
>Number: 23409
>Category: bin
>Synopsis: last -H ... can blindly print out non-NUL terminated strings
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Nov 11 05:21:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator: Geoff C. Wing
>Release: NetBSD 1.6ZE (2003/11/11)
>Organization:
>Environment:
System: NetBSD g.primenet.com.au 1.6ZE NetBSD 1.6ZE (G) #0: Mon Nov 10 14:30:01 EST 2003 gcw@g.primenet.com.au:/usr/netbsd/src/sys/arch/i386/compile/G i386
Architecture: i386
Machine: i386
>Description:
when querying a wtmp file, ``last -H <n>'' where <n> is greater than
UT_HOSTSIZE will spew out data from outside the ut_host[] field if
the ut_host[] entry is UT_HOSTSIZE long (and doesn't have a NUL
terminator). From inspection, the same is true of -L <n> and -N <n>
options. And IIRC also true of wtmpx files.
>How-To-Repeat:
Do ``last -H 30 -f /var/log/wtmp'' on some host which has had logins
from hosts with >=16 letter hostnames.
>Fix:
If parameters passed are greater than field sizes then these fields
need to be copied out and NUL-terminated before being printed.
Something along the lines of the following:
--- want.c.org 2003-08-09 12:02:04.000000000 +1000
+++ want.c 2003-11-11 16:16:43.000000000 +1100
@@ -48,12 +48,29 @@
int bytes, wfd;
char *ct, *crmsg;
size_t len = sizeof(*buf) * MAXUTMP;
+ int checkname, checkline, checkhost;
+ char *namebuf, *linebuf, *hostbuf;
if ((buf = malloc(len)) == NULL)
err(1, "Cannot allocate utmp buffer");
crmsg = NULL;
+ checkname = namesz > sizeof(bp->ut_name) ? 1 : 0;
+ checkline = linesz > sizeof(bp->ut_line) ? 1 : 0;
+ checkhost = hostsz > sizeof(bp->ut_host) ? 1 : 0;
+
+ if (checkname)
+ namebuf = malloc(namesz + 1);
+ if (checkline)
+ linebuf = malloc(linesz + 1);
+ if (checkhost)
+ hostbuf = malloc(hostsz + 1);
+ if ((checkname && namebuf == NULL)
+ || (checkline && linebuf == NULL)
+ || (checkhost && hostbuf == NULL))
+ err(1, "Cannot allocate buffer");
+
if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1)
err(1, "%s", file);
bl = (stb.st_size + len - 1) / len;
@@ -67,23 +84,45 @@
(bytes = read(wfd, buf, len)) == -1)
err(1, "%s", file);
for (bp = &buf[bytes / sizeof(*buf) - 1]; bp >= buf; --bp) {
+ if (!checkname)
+ namebuf = bp->ut_name;
+ else {
+ strncpy(namebuf, bp->ut_name,
+ sizeof(bp->ut_name));
+ namebuf[sizeof(bp->ut_name)] = '\0';
+ }
+ if (!checkline)
+ linebuf = bp->ut_line;
+ else {
+ strncpy(linebuf, bp->ut_line,
+ sizeof(bp->ut_line));
+ linebuf[sizeof(bp->ut_line)] = '\0';
+ }
+ if (!checkhost)
+ hostbuf = bp->ut_host;
+ else {
+ strncpy(hostbuf, bp->ut_host,
+ sizeof(bp->ut_host));
+ hostbuf[sizeof(bp->ut_host)] = '\0';
+ }
+
/*
* if the terminal line is '~', the machine stopped.
* see utmp(5) for more info.
*/
- if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
+ if (linebuf[0] == '~' && !linebuf[1]) {
/* everybody just logged out */
for (T = ttylist; T; T = T->next)
T->logout = -bp->ut_timefld;
currentout = -bp->ut_timefld;
- crmsg = strncmp(bp->ut_name, "shutdown",
+ crmsg = strncmp(namebuf, "shutdown",
namesz) ? "crash" : "shutdown";
if (want(bp, NO)) {
ct = fmttime(bp->ut_timefld, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s\n",
- namesz, namesz, bp->ut_name,
- linesz, linesz, bp->ut_line,
- hostsz, hostsz, bp->ut_host, ct);
+ namesz, namesz, namebuf,
+ linesz, linesz, linebuf,
+ hostsz, hostsz, hostbuf, ct);
if (maxrec != -1 && !--maxrec)
return;
}
@@ -93,17 +132,14 @@
* if the line is '{' or '|', date got set; see
* utmp(5) for more info.
*/
- if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
- && !bp->ut_line[1]) {
+ if ((linebuf[0] == '{' || linebuf[0] == '|')
+ && !linebuf[1]) {
if (want(bp, NO)) {
ct = fmttime(bp->ut_timefld, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s\n",
- namesz, namesz,
- bp->ut_name,
- linesz, linesz,
- bp->ut_line,
- hostsz, hostsz,
- bp->ut_host,
+ namesz, namesz, namebuf,
+ linesz, linesz, linebuf,
+ hostsz, hostsz, hostbuf,
ct);
if (maxrec && !--maxrec)
return;
@@ -114,20 +150,20 @@
for (T = ttylist;; T = T->next) {
if (!T) {
/* add new one */
- T = addtty(bp->ut_line);
+ T = addtty(linebuf);
break;
}
- if (!strncmp(T->tty, bp->ut_line, LINESIZE))
+ if (!strncmp(T->tty, linebuf, LINESIZE))
break;
}
if (TYPE(bp) == SIGNATURE)
continue;
- if (bp->ut_name[0] && want(bp, YES)) {
+ if (namebuf[0] && want(bp, YES)) {
ct = fmttime(bp->ut_timefld, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s ",
- namesz, namesz, bp->ut_name,
- linesz, linesz, bp->ut_line,
- hostsz, hostsz, bp->ut_host,
+ namesz, namesz, namebuf,
+ linesz, linesz, linebuf,
+ hostsz, hostsz, hostbuf,
ct);
if (!T->logout)
puts(" still logged in");
>Release-Note:
>Audit-Trail:
>Unformatted: