Subject: kern/4280: sending fd's over AF_UNIX sockets causes kernel panic
To: None <gnats-bugs@gnats.netbsd.org>
From: Chris Jones <cjones@rupert.honors.montana.edu>
List: netbsd-bugs
Date: 10/16/1997 12:21:26
>Number:         4280
>Category:       kern
>Synopsis:       sending fd's over AF_UNIX sockets causes kernel panic
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Oct 16 11:35:02 1997
>Last-Modified:
>Originator:     Chris Jones
>Organization:
-------------------------------------------------------------------------------
Chris Jones                                      cjones@rupert.oscs.montana.edu
           Mad scientist in training...
"Is this going to be a stand-up programming session, sir, or another bug hunt?"
>Release:        Yesterday.
>Environment:
	
System: NetBSD rupert.honors.montana.edu 1.2G NetBSD 1.2G (RUPERT) #4: Thu Jul 24 13:05:55 MDT 1997 cjones@rupert.honors.montana.edu:/usr/src/sys/arch/mac68k/compile/RUPERT mac68k


>Description:

On two NetBSD-1.2G machines, one a mac68k and one i386, I can cause a
kernel panic by attempting to send multiple file descriptors in one
message.  Even if the man page didn't say this was an acceptable thing
to do, it's a problem because a userland program shouldn't be able to
cause a kernel panic, IMHO.  :)

>How-To-Repeat:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/un.h>
#include <errno.h>

int
main(int argc,
     char *argv[])
{
    struct sockaddr_un sockname;
    int i, sock;
    char buf[1024];
    struct msghdr msg;
    struct cmsghdr cmsg;

    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if(sock == -1) {
	fprintf(stderr, "%s: socket: %s\n", argv[0], strerror(errno));
	exit(1);
    }

    sockname.sun_family = AF_UNIX;
    /* Use /var/run/printer, because it doesn't appear to matter what
       process is on the other end of the socket, as long as it's
       AF_UNIX and SOCK_STREAM. */
    strcpy(sockname.sun_path, "/var/run/printer");
    sockname.sun_len = sizeof(sockname) - sizeof(sockname.sun_path) +
	strlen(sockname.sun_path);
    if(connect(sock, (struct sockaddr *)&sockname, sockname.sun_len)
       == -1) {
	fprintf(stderr, "%s: connect: %s\n", argv[0], strerror(errno));
	exit(1);
    }

    /* Send fd's 0, 1, and 2. */
    cmsg.cmsg_len = sizeof(cmsg.cmsg_len) +
	sizeof(cmsg.cmsg_level) + sizeof(cmsg.cmsg_type) +
	sizeof(i) * 3;
    cmsg.cmsg_level = SOL_SOCKET;
    cmsg.cmsg_type = SCM_RIGHTS;
    bcopy(&cmsg, buf, sizeof(cmsg));
    for(i = 0; i < 3; i++)
	bcopy(&i, buf + sizeof(cmsg) + sizeof(i) * i, sizeof(i));
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = NULL;
    msg.msg_iovlen = 0;
    msg.msg_control = buf;
    msg.msg_controllen = cmsg.cmsg_len;
    msg.msg_flags = 0;
    if(sendmsg(sock, &msg, 0) == -1) {
	fprintf(stderr, "%s: sendmsg: %s\n", argv[0],
		strerror(errno));
	exit(1);
    }

    printf("Wow; your machine didn't crash!  You're lucky!\n");
    exit(0);
}

>Fix:

The same program, if it's modified to send fd's one at a time, doesn't
crash anything.
>Audit-Trail:
>Unformatted: