Subject: bin/17933: minor overflow bug in comsat
To: None <gnats-bugs@gnats.netbsd.org>
From: David Holland <dholland@eecs.harvard.edu>
List: netbsd-bugs
Date: 08/13/2002 16:48:17
>Number:         17933
>Category:       bin
>Synopsis:       minor overflow bug in comsat
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 13 13:49:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     David A. Holland
>Release:        NetBSD 1.6E
>Organization:
   - David A. Holland / dholland@eecs.harvard.edu
>Environment:

System: NetBSD alicante 1.6E NetBSD 1.6E (ALICANTE) #3: Mon Aug 5 17:48:40 EDT 2002 dholland@alicante:/usr/src/sys/arch/i386/compile/ALICANTE i386
Architecture: i386
Machine: i386

>Description:

	comsat will zoom off the end of a buffer, as root, if utmp is
	very large.

	As far as I can tell it cannot be exploited usefully - it will
	always run off the end of the heap and dump core.

	(Also, you need write access to utmp to abuse it, so at worst
	it would be a path from group utmp to root... and I suspect
	there are still a lot of those that are much easier to exploit.)

	The problem is that it adds extra space to an off_t, then
	assigns it into a u_int without checking for integer overflow,
	then calls realloc, but casts the original off_t to int
	(promoted to size_t) to specify how much to read.

	The result is that you can make it (1) reallocate the buffer
	so it's very small, and then (2) attempt to read nearly 2^32
	bytes into that buffer.

	Note that this is not even an effective DoS, as if you crash
	comsat this way inetd will just spawn another one.

>How-To-Repeat:
	As above.

>Fix:

Patch follows.

It also corrects a minor article of pedanticism concerning snprintf's
return value a bit further down.

(Note: the patch uses INT_MAX rather than UINT_MAX because the off_t
is cast through int when calling read. This may be excessively
paranoid, but better to be safe.)

Index: comsat.c
===================================================================
RCS file: /cvsroot/basesrc/libexec/comsat/comsat.c,v
retrieving revision 1.23
diff -u -r1.23 comsat.c
--- comsat.c	2002/03/18 23:34:21	1.23
+++ comsat.c	2002/08/13 20:36:10
@@ -56,6 +56,7 @@
 #include <errno.h>
 #include <netdb.h>
 #include <paths.h>
+#include <limits.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
@@ -170,6 +171,11 @@
 	(void)fstat(uf, &statbf);
 	if (statbf.st_mtime > utmpmtime) {
 		utmpmtime = statbf.st_mtime;
+		/* avoid integer overflow */
+		if (statbf.st_size > INT_MAX - 10 * sizeof(struct utmp)) {
+			syslog(LOG_ALERT, "utmp file excessively large");
+			exit(1);
+		}
 		if (statbf.st_size > utmpsize) {
 			utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
 			if ((utmp = realloc(utmp, utmpsize)) == NULL) {
@@ -207,7 +213,7 @@
 		char maildir[128];
 		int l = snprintf(maildir, sizeof(maildir), ":%s/%s",
 				 _PATH_MAILDIR, name);
-		if (l > sizeof(maildir) || strcmp(maildir, fn) != 0)
+		if (l >= sizeof(maildir) || strcmp(maildir, fn) != 0)
 			return;
 	}
 	while (--utp >= utmp)

>Release-Note:
>Audit-Trail:
>Unformatted: