Subject: kern/10698: accept returns garbage w/evanescent connects to unix domain sockets
To: None <gnats-bugs@gnats.netbsd.org>
From: Castor Fu <castor@geocast.com>
List: netbsd-bugs
Date: 07/27/2000 17:07:16
>Number:         10698
>Category:       kern
>Synopsis:       accept returns garbage w/evanescent connects to unix domain sockets
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 27 17:08:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Castor Fu
>Release:        NetBSD-1.4
>Organization:
Geocast Network Systems
>Environment:
	Seen on NetBSD/i386 and Geocast's internal mips based platform.
	Also seen with NetBSD-1.5 branch as of a few days ago on i386.
System: NetBSD swamp.sfo.geocast.net 1.4P NetBSD 1.4P (GEO_STANDARD) #171: Thu Jun 29 15:56:03 PDT 2000 castor@swamp.sfo.geocast.net:/usr/export/home/castor/nb/usr/src/sys/arch/i386/compile/GEO_STANDARD i386


>Description:
	accept(2) on a unix domain socket returns an invalid value
	for the address family in a sockaddr when connector closes
	before the accept is executed.

>How-To-Repeat:

The following two programs and the script can be used to exercise 
this bug.

#!/bin/sh
set -x
./nps &
spid=$!
sleep 1
./xclient &
sleep 1
c1pid=$!
./xclient&
c2pid=$!
sleep 1
kill $c2pid
sleep 1
kill $c1pid
sleep 1
kill -0 $spid

/* nps.c, no NSPR */

#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stdio.h>

#define SOCKET_NAME "/ftsoNSPR"

int main(int argc, char *argv[])
{
    struct sockaddr_un addr;
    int rv;
    int conn = -1;
    struct sockaddr_un serverAddr;
    int listenSocket;
    char buf[256];
    int size;
    int i;
    int addr_len;

    unlink("ftsoNSPR");
    memset(&serverAddr, 0, sizeof(serverAddr)); /* set up address structure */
    serverAddr.sun_len = sizeof(serverAddr);
    serverAddr.sun_family = AF_UNIX;

    if (getcwd(serverAddr.sun_path, sizeof(serverAddr.sun_path)) == NULL) {
        fprintf(stderr, "Can't get current directory.\n");
        return -1;
    }
    size = strlen(serverAddr.sun_path);
    strncat(serverAddr.sun_path, SOCKET_NAME,
            sizeof(serverAddr.sun_path) - size);

    /* create the socket */
    listenSocket = socket(AF_UNIX, SOCK_STREAM, 0);

    if (listenSocket == -1) {
        fprintf(stderr, "Error returned from PR_Socket: %d", errno);
        return -1;
    }

    fprintf(stderr, "path is %s\n", serverAddr.sun_path);

    /* bind the socket */
    if (bind(listenSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == -1) {
        fprintf(stderr, "Server error binding to server address: OS error
%d\n",
               errno);
        return -1;
    }

    /* set the socket up to receive inbound connections */
    if ( listen(listenSocket, 10) == -1) {
        fprintf(stderr, "Server error listening to server socket\n");
        return -1;
    }

    while(1) {
        if (conn == -1) {
            addr_len = sizeof(addr);
	    printf("calling accept\n");
            conn = accept(listenSocket, (struct sockaddr *)&addr, &addr_len);
	    printf("returns %d\n", conn);
            if (addr.sun_family != AF_UNIX) {
                fprintf(stderr, "address family is %d\n", addr.sun_family);
                abort();
            }
            continue;
        }

        if(read(conn, buf, 10) > 0) {
            fprintf(stderr, "read this: ");
            for(i = 0; i < 10; i++)
                fprintf(stderr, "%c", buf[i]);
        } else {
            close(conn);
            conn = -1;
        }
    }
    return 0;
}  


/* xclient.c */
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

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

#define SOCKET_NAME "/ftsoNSPR"

int main(int argc, char *argv[])
{
    struct sockaddr_un serverAddr;
    int l;
    int scriptSock;

    /* set up address structure */
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sun_len = sizeof(serverAddr);
    serverAddr.sun_family = AF_LOCAL;
    if (getcwd(serverAddr.sun_path, sizeof(serverAddr.sun_path)) == NULL) {
        fprintf(stderr, "Can't get current directory.\n");
        exit(1);
    }
    l = strlen(serverAddr.sun_path);
    strncat(serverAddr.sun_path, SOCKET_NAME,
            sizeof(serverAddr.sun_path) - l);

    /* create the socket */
    scriptSock = socket(AF_LOCAL, SOCK_STREAM, 0);

    if ( scriptSock < 0 ) {
        fprintf(stderr,
                "initScriptSocket: Error returned from socket: %s %s\n",
                strerror(errno), serverAddr.sun_path);
        exit(1);
    }

    /* connect */
    if ( connect(scriptSock, (struct sockaddr *) &serverAddr,
	sizeof(serverAddr)) != 0) {
        fprintf(stderr,
                "initScriptSocket: Error returned from connect: %s\n",
                strerror(errno));
        exit(1);
    }

    write(scriptSock, "hi there.\n", 10);

    while(1) {
        sleep(1000);
    }
}

>Fix:
	none yet.
>Release-Note:
>Audit-Trail:
>Unformatted: