>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     s...@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:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to