xorl %eax, %eax

Solaris w(1) Heap Overflow Race Condition

with one comment

This vulnerability was discovered and reported by Monarch Rich as a Solaris specific bug. The issue affects Solaris 9 and 10 as well as OpenSolaris based upon builds snv_124 or later according the the original advisory.
The buggy code is available at usr/src/cmd/w/w.c like this:

int
main(int argc, char *argv[])
{
	struct utmpx	*ut;
	struct utmpx	*utmpbegin;
	struct utmpx	*utmpend;
	struct utmpx	*utp;
    ...
	/*
	 * This program needs the proc_owner privilege
	 */
	(void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER,
	    (char *)NULL);
    ...
	if (stat(UTMPX_FILE, &sbuf) == ERR) {
    ...
	entries = sbuf.st_size / sizeof (struct futmpx);
	size = sizeof (struct utmpx) * entries;
	if ((ut = malloc(size)) == NULL) {
		(void) fprintf(stderr, gettext("%s: malloc error of %s: %s\n"),
			prog, UTMPX_FILE, strerror(errno));
		exit(1);
	}

	(void) utmpxname(UTMPX_FILE);

	utmpbegin = ut;
	utmpend = (struct utmpx *)((char *)utmpbegin + size);

	setutxent();
	while ((utp = getutxent()) != NULL)
		(void) memcpy(ut++, utp, sizeof (*ut));
	endutxent();

	(void) time(&now);	/* get current time */
    ...
	return (0);
}

So, in the above code snippet you can see that ‘ut’ pointer is initiallized with the size of UTMPX file’s size divided by the size of structure ‘futmpx’. The size is calculated to fit enough ‘utmpx’ pointers for each record of UTMP log file.
After allocating the required space using malloc(3), a call to utmpxname() takes place to change the filename. Then, variable ‘utmpbegin’ is initialized with the previously allocated ‘ut’ pointer and ‘utmpend’ with ‘utmpbegin + size’ which will return a pointer to the end of the ‘ut’ structure. The subsequent call to setutxent() will reset the input stream to the beginning of the file.
Now, the code execution moves to the main copying loop which is a simple while loop that will initialize ‘utp’ with getutxent() which returns the next entry of the UTMPX file. It will then copy the returned ‘utmpx’ structure to ‘ut’ and increment the pointer to continue the copying. The problem here is that ‘ut’ was initialized based on the ‘sbuf.st_size’ value retrieved using stat(2) system call. Between the stat(2) of the file and the actual copy using memcpy(3) there might have been new entries in the log file that will result in heap memory corruption since the only check is that getutxent() has not reached the last entry in the UTMPX file.
This was fixed by applying the following patch:

	setutxent();
-	while ((utp = getutxent()) != NULL)
+	while ((ut < utmpend) && ((utp = getutxent()) != NULL))
		(void) memcpy(ut++, utp, sizeof (*ut));
	endutxent();

The new loop checks also that the ‘ut’ pointer has not reached the end of the allocated space which is stored in ‘utmpend’.
Apart from this nice bug, Sun Microsystems also silently fixed another one similar heap memory corruption vulnerability in whodo (located in src/cmd/whodo/whodo.c). Here is the patch of whodo:

	utmpbegin = ut;
	/* LINTED pointer cast may result in improper alignment */
	utmpend = (struct utmpx *)((char *)utmpbegin + size);

	setutxent();
-	while ((utp = getutxent()) != NULL)
+	while ((ut < utmpend) && ((utp = getutxent()) != NULL))
		(void) me

Written by xorl

October 14, 2009 at 18:40

Posted in bugs, solaris

One Response

Subscribe to comments with RSS.

  1. Nice write up. Also good job noticing the silent fix.

    Incase you are wondering about exploitability, start by looking at:
    /usr/lib/utmp_update

    The only validation is based on terminal path and that can be avoided with paths like: pts////2

    Monarch

    October 15, 2009 at 13:03


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s