kern/149227: struct msghdr.msg_controllen left unititialized in freebsd32_recvmsg

Stef Walter stef at memberwebs.com
Tue Aug 3 10:10:09 UTC 2010


>Number:         149227
>Category:       kern
>Synopsis:       struct msghdr.msg_controllen left unititialized in freebsd32_recvmsg
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 03 10:10:04 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Stef Walter
>Release:        FreeBSD 8.1
>Organization:
>Environment:
FreeBSD a2.ams.npubs.net 8.1-RELEASE FreeBSD 8.1-RELEASE #2: Tue Aug  3 09:15:35 UTC 2010     stef at a2.ams.npubs.net:/usr/obj/usr/src/sys/RACK2  amd64
>Description:
In the freebsd32 compat layer msgdhr.msg_controllen is not set to zero when no control data was returned via recvmsg. It is left at its original value, and can cause userland crashes or accesses to uninitialized memory.

This occurs when 32-bit userland (such as in a jail) is running on a 64-bit kernel and calls recvmsg().

>How-To-Repeat:
/* Will crash or produce erroneous output on 32-bit userland running on 64-bit kernel */
/* gcc -o test_cmsghdr test_cmsghdr.c */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <err.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#define SOCKET_PATH "/tmp/cmsghdr.sock"
#define TEST_DATA "This is the test data we sent."

int
perform_send (void)
{
	struct sockaddr_un addr;
	ssize_t sent;
	int sock;

	sock = socket (AF_UNIX, SOCK_DGRAM, 0);
	if (sock < 0)
		err (1, "send socket");

	memset (&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy (addr.sun_path, SOCKET_PATH, sizeof (addr.sun_path));

	if (connect (sock, (struct sockaddr*)&addr, sizeof (addr)) < 0)
		err (1, "send connect");

	sent = send (sock, TEST_DATA, strlen (TEST_DATA), 0);
	if (sent < 0)
		err (1, "send send");

	if (sent < strlen (TEST_DATA))
		errx (1, "short send");

	close (sock);
	return 0;
}

int
main (void)
{
	char buffer[256];
	char control[256];
	struct sockaddr_un addr;
	struct msghdr msg;
	struct cmsghdr *cmsg;
	struct iovec iov;
	int sock;
	ssize_t len;
	socklen_t slen;

	sock = socket (AF_UNIX, SOCK_DGRAM, 0);
	if (sock < 0)
		err (1, "recv socket");

	memset (&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	strncpy (addr.sun_path, SOCKET_PATH, sizeof (addr.sun_path));

	unlink (SOCKET_PATH);
	if (bind (sock, (struct sockaddr*)&addr, sizeof (addr)) < 0)
		err (1, "recv bind");

	if (fork () == 0)
		return perform_send ();

	memset (&iov, 0, sizeof (iov));
	iov.iov_base = buffer;
	iov.iov_len = sizeof (buffer) - 1;

	memset (&msg, 0, sizeof (msg));
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = control;
	msg.msg_controllen = sizeof (control);

	/* Screw up memory in these buffers */
	memset (control, 0xAB, sizeof (control));
	memset (buffer, 0xBA, sizeof (buffer));

	len = recvmsg (sock, &msg, 0);
	if (len < 0)
		err (1, "recv recvfrom");

	if (len >= sizeof (buffer))
		err (1, "recv too long");

	buffer[len] = 0;
	warnx ("received data:");
	fprintf (stderr, "%s\n", buffer);

	warnx ("flags: %x", msg.msg_flags);
	warnx ("length of control: %d", msg.msg_controllen);

	if (msg.msg_controllen) {
		for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
			warnx ("cmsg of len: 0x%08x", cmsg->cmsg_len);
	}

	close (sock);
	return 0;
}
>Fix:
Will attach a patch

Patch attached with submission follows:

--- ./sys/compat/freebsd32/freebsd32_misc.c.orig	2010-08-03 09:08:40.000000000 +0000
+++ ./sys/compat/freebsd32/freebsd32_misc.c	2010-08-03 09:55:29.000000000 +0000
@@ -1063,4 +1063,6 @@ freebsd32_recvmsg(td, uap)
 		if (control != NULL)
 			error = freebsd32_copy_msg_out(&msg, control);
+		else
+			msg.msg_controllen = 0;
 		
 		if (error == 0)


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


More information about the freebsd-bugs mailing list