>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"