From owner-freebsd-bugs@FreeBSD.ORG Wed May 9 21:10:06 2007 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 71A2116A406 for ; Wed, 9 May 2007 21:10:06 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id 506FE13C468 for ; Wed, 9 May 2007 21:10:06 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id l49LA6WK076816 for ; Wed, 9 May 2007 21:10:06 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id l49LA6ua076815; Wed, 9 May 2007 21:10:06 GMT (envelope-from gnats) Resent-Date: Wed, 9 May 2007 21:10:06 GMT Resent-Message-Id: <200705092110.l49LA6ua076815@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Spencer Minear Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 95A3916A403 for ; Wed, 9 May 2007 21:03:48 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [69.147.83.33]) by mx1.freebsd.org (Postfix) with ESMTP id 83E5313C457 for ; Wed, 9 May 2007 21:03:48 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l49L3mCW081168 for ; Wed, 9 May 2007 21:03:48 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.13.1/8.13.1/Submit) id l49Kwlro073690; Wed, 9 May 2007 20:58:47 GMT (envelope-from nobody) Message-Id: <200705092058.l49Kwlro073690@www.freebsd.org> Date: Wed, 9 May 2007 20:58:47 GMT From: Spencer Minear To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.0 Cc: Subject: misc/112554: unp_gc is overly agressive and removes valid file descriptors in transit X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 May 2007 21:10:06 -0000 >Number: 112554 >Category: misc >Synopsis: unp_gc is overly agressive and removes valid file descriptors in transit >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed May 09 21:10:05 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Spencer Minear >Release: Our modified 6.0 system. But the problem still exist in current >Organization: Secure Computing Corp >Environment: Any 6.0 system will show the problem. >Description: The unp_gc function within kern/unpc_usrreq.c is suppose to cleanup file descriptors that were passed in a message when the message contianing the file reference is NO longer accessible. HOWEVER the code is abit aggressive and will remove file descriptors that are in a message buffer waiting on a socket that has yet to be accepted. >How-To-Repeat: The short summary is that it is easiest to show if you have client/server that communicate via a file descriptor sent over a socket. Then run one client server pair that ignores errors and just keeps on running to keep unp_gc working. Then run a separate client/server pair that sets up the listen, but is SLOW to do the accept so that the client socket sits in the message buffer for a long time. unp_gc will screw up this socket nearly every time. README, Makefile and Test program code follow: README file =========================================================== The test program in this directory was created to show that file descriptors passed in a socket can, in some cases get lost. The test evolved as the problem was being investigated. The test was modified so that it can be run in two sets of clinet/server instances. The first client/server pair do trigger the problem, but in its current form running in this form will not print out any notification that the problem occured. It is used just to setup background activity that will result in the second pair failing on the first attempted exchange. Program Operation Overview: The single code file is compiled to a test program named sockpair_test. The program can be run as a server or as a client. The server creates a unix socket in the current working directory and enters a loop to listen for new service connections. Once connection is received and a new socket is obtained via an accept operation, The server will fork a child instance of it self which will select on the new socket and when ready it does a rcvmsg on the socket and expects to receive a yet another new socket which the client passed in the first message. Once received the first socket is closed and a message is sent on the second, and then a return message is read from that socket and the clinet closes this connection and exits. The client side enters a loop which creates a socket which it uses to connect to the server, then it creates a socket pair. It keeps one half of the socket pair and sends the file descriptor for the other half in a message over connection socket. Once the second file descriptor is sent, the client close its end of the transmitted file descriptor, and the connection socket. It waits for a mesasge to be received on it's end of the socket pair and once received sends its reply and repeats process. To build the test: 1. Extract the tarball containing the test source, the makefile and this information file. 2. run "make link" in directory. To run the test establish 4 connections to the system. In the first two connection run the following commands. ./server_side ./client_side Once these report that they are running then run the following two commands in the other two connections. NOTE: you need to run the second command wihtin a second or two of getting the first running. ./server_side -T ./client_side -T After a short delay, about 5 seconds max, the following error messages should appear be observed. sever_side Starting server side New fd 5 recvmsged from new_socket pid read select on already says ready. w_read: read 0 bytes. w_read error from recvmsg: Connection reset by peer Server side socket select timed out client_side Starting client side client: sendmsg() failed, 55, No buffer space available Problem Explantion. The problem is while the client provided file descriptor for the second half of socket pair is sitting in the socket queue waiting to be "received" by the server, the unp_gc function in sys/kern/unp_usrreq.c may see it and think that it is no longer accessible and closes the remain view of the file. Once the server gets to using the socket it finds that it is closed for reading. It can send the initial message, but when it tries to read from it it receives a "Connection reset by peer" error. The Fix The fix is to add logic into the unp_gc function that takes into account the fact that the socket containing the file reference may in a listen state and in that case it should be be removed. Makefile ================================================================== PROG = sockpair_test CLEANFILES += server_side client_side CFLAGS += -g LDFLAGS += -static LDADD+= NO_MAN= link: sockpair_test if test -f server_side; then \ rm server_side; \ fi if test -f client_side; then \ rm client_side; \ fi ln sockpair_test server_side ln sockpair_test client_side .include Code file ========================================= /*--------------------------------------------------------------------------- Test program to demonstrate the lose of file descriptors passed through a socket. This single program can be used in 4 modes. The first two area used to generate enough activity which should result 3rd and 4th modes will detect the failure on the first server client exchange. 1. A quiet Server side test driver used to generate enough traffice to trigger the problem for test modes 3 and 4. 2. A quiet Client side program which talkes to the quiet server. 3. A server side that delays to help trigger an immediate failure and out error messages to report when the problem is detected. Also times out after the clinet goes away for 15 seconds. 4. A client side that reports errors when the problem is detected and exits immediately after the first errro. Processing over view: The server creates a unix socket in the current working directory and enters a loop to listen for new service connections. Once connection is received and a new socket is obtained via an accept operation, The server will fork a child instance of it self which will select on the new socket and when ready it does a rcvmsg on the socket and expects to receive a yet another new socket which the client passed in the first message. Once received the first socket is closed and a message is sent on the second, and then a return message is read from that socket and the clinet closes this connection and exits. The client side enters a loop which creates a socket which it uses to connect to the server, then it creates a socket pair. It keeps one half of the socket pair and sends the file descriptor for the other half in a message over connection socket. Once the second file descriptor is sent, the client close its end of the transmitted file descriptor, and the connection socket. It waits for a mesasge to be received on it's end of the socket pair and once received sends its reply and repeats process. ---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include void do_parent(void); void do_child(void); typedef struct mymsg_s { u_int32_t msg_magic; u_int32_t msg_cnt; char msg_text[40]; } mymsg_t; #define MSG_MAGIC 0x01020304 char *serv_sockets[2] = { "./TESTSERVSOCK1", /* Used for the first quite mode operation */ "./TESTSERVSOCK2" /* Used by the problem reporting operational * mode */ }; int opt_daemon = 0; /* Indicates we are running as a sever */ int opt_client = 1; /* Indicates we are running as a client */ int opt_instance = 0; /* 0 indicates quite background mode * 1 indicates the report problem mode */ int opt_verbose = 0; /* Can be used to have the quite mode print out error messages. On by default for opt_instance 1 */ /*************************************************************************** * * Forward declarations of local functions * ***************************************************************************/ static void sig_child(int sig); static void usage(char *prog); void do_server(int dinst); void do_client(int cinst); int get_sock(int rsock); void saction(int sock); int s_write_msg(int sock, char mkey, char *msg); int s_read_msg(int, char *msg); int c_write_msg(int sock, char mkey, char *msg); int c_read_msg(int, char *msg); void caction(int sock1, int *sockp_p); /*--------------------------------------------------------------------------- Name : Main Function Description: Main entry, detects executaion name and processes arguments to set up option global values and starts the appropriate processing/ ---------------------------------------------------------------------------*/ int main(int argc, char ** argv) { pid_t pid; char ch; if (strstr(argv[0], "server_side") != NULL) { printf("Starting server side\n"); opt_daemon = 1; opt_client = 0; } else { printf("Starting client side\n"); opt_daemon = 0; opt_client = 1; } while ((ch = getopt(argc, argv, "hTdcv")) != EOF) { switch(ch) { case 'T': opt_instance = 1; opt_verbose = 1; break; case 'd': opt_daemon = 1; opt_client = 0; break; case 'c': opt_client = 1; opt_daemon = 0; break; case 'h': usage(argv[0]); exit(0); break; case 'v': opt_verbose = 1; break; default: usage(argv[0]); exit(1); break; } } if (opt_daemon) { do_server(opt_instance); } if (opt_client) { do_client(opt_instance); } } /************************************************************************* * * Local Functions * *************************************************************************/ /*--------------------------------------------------------------------------- Name : sig_child Function Description: Clean up child processes to keep the system clean. Arguments : sig - The signal value being responded to. Should be SIGCHLD ---------------------------------------------------------------------------*/ static void sig_child(int sig) { int child_status; /* Reap _all_ dead children */ if (sig != SIGCHLD) { fprintf(stderr, "Invalid signal %d seen in sig_child()\n", sig); exit(1); } while ( wait3 ( &child_status, WNOHANG, 0 ) > 0 ); } /*--------------------------------------------------------------------------- Name : usage Function Description: Print out a short usage summary Arguments : prog: Name used to start the program. ---------------------------------------------------------------------------*/ static void usage(char * prog) { fprintf(stderr, "%s: [-hbdciT] [-t delay_sec]\n"); fprintf(stderr, "\t-h - print this message\n"); fprintf(stderr, "\t-T - Run expecting to fail on first try\n"); fprintf(stderr, "\t-d - Run as the daemon (use server_side link)\n"); fprintf(stderr, "\t-c - Run as the client (use client_sice link)\n"); fprintf(stderr, "\t-v - Do more verbose output. Default with -T\n"); } /************************************************************************* * * Server Side Functions * *************************************************************************/ #define SUN_PATH_SIZE (sizeof(proxy_addr.sun_path)) /*--------------------------------------------------------------------------- Name : do_server Function Description: Setup the daemon service socket and enter the service loop which waits for a new connection socket. When new connection is received fork a child process to carry out the interaction with the client. Arguments : inst - 0 to indicate running in quiet mode, 1 to indicate running in report error mode. ---------------------------------------------------------------------------*/ void do_server(int inst) { int rsock; struct sockaddr_un proxy_addr; int proxy_len; int new_socket; int pid; struct stat sb; if ( signal(SIGCHLD, sig_child) == SIG_ERR) { printf("failed to set sig child handler\n"); exit(1); } restart: if (stat(serv_sockets[inst], &sb) == 0) { unlink(serv_sockets[inst]); } /* build the service socket */ rsock = socket(AF_UNIX, SOCK_STREAM, 0); fcntl(rsock, F_SETFL, FNDELAY); bzero ( (char *) &proxy_addr , sizeof(proxy_addr) ); proxy_addr.sun_family = AF_UNIX; strcpy ( proxy_addr.sun_path , serv_sockets[inst]); proxy_len = (sizeof(proxy_addr.sun_family) + 1 + strlen(proxy_addr.sun_path)); bind (rsock, (struct sockaddr *)&proxy_addr, proxy_len ); listen(rsock, 5); do { if (inst > 0) { sleep(5); } if((new_socket = get_sock(rsock)) != -1) { switch(pid = fork()) { case 0: saction(new_socket); exit(0); break; default: close(new_socket); } } else { printf("No new socket received\n"); close(rsock); goto restart; } } while(1); } /*--------------------------------------------------------------------------- Name : get_sock Function Description: Wait for new connection and when available accept the new connection and return the file descriptor to the caller. Return Value : file descriptor for the accepted connection socket Arguments : rsock - File descriptor for the server service socket. ---------------------------------------------------------------------------*/ int get_sock(int rsock) { int ns; /* New socket from accept() */ struct sockaddr_un ns_addr; /* Address provided with the acept */ int ns_addr_len; int sres; struct timeval timeout; /* Time till select times out */ fd_set read_ready; ns_addr_len = sizeof(ns_addr); timeout.tv_sec = 15; timeout.tv_usec = 0; reselect: FD_ZERO ( &read_ready ); FD_SET ( rsock, &read_ready ); if ((ns = select(rsock+1, &read_ready, NULL, NULL, &timeout)) == -1 ) { if (errno == EINTR) { goto reselect; } printf("Server side socket select error, %d %s\n", errno, strerror(errno)); exit(1); } else if (ns == 0) { printf("Server side socket select timed out\n"); if (opt_instance > 0) { exit(1); } goto reselect; } if (!FD_ISSET(rsock, &read_ready) ) { printf("No new connection waiting on 'rsock'\n"); return ( -1 ); } ns = accept(rsock, (struct sockaddr *)&ns_addr, &ns_addr_len); if ( ns < 0 ) { printf("Error accept()ing on rsock\n"); return ( -1 ); } return(ns); } /*--------------------------------------------------------------------------- Name : saction Function Description: Wait on the connection socket to receive the first client message which conntains the file descriptor for the per connection communication socket. Close the connection socket once the messge is received. Select on the communication socket with zero timeout. This isn't really necessary but when it comes back with an indication that data is read to read we have a hint that the problem has occurred since the client has not yet sent data. Write the server to client message and wait for the client response message. Arguments : nsock - File descriptor for the newly accepted connection socket ---------------------------------------------------------------------------*/ void saction(int nsoc) { int asoc; char msg_buf[80]; struct msghdr msg; struct { struct cmsghdr hdr; int fd; } control; int bytes_read; /* # of bytes in recvmsg() */ fd_set read_ready; struct timeval timeout; int sres; msg.msg_name = (caddr_t) 0; msg.msg_namelen = 0; msg.msg_iov = (struct iovec *)0; msg.msg_iovlen = 0; msg.msg_control = (caddr_t) &control; msg.msg_controllen = sizeof(control); msg.msg_flags = 0; timeout.tv_sec = 100; timeout.tv_usec= 0; FD_ZERO(&read_ready); FD_SET(nsoc, &read_ready); sres = select(nsoc + 1, &read_ready, (fd_set *)NULL, (fd_set *)NULL, &timeout); if (sres < 0 ) { printf("Error selecting on accepted socket\n"); close (nsoc); return; } if (!FD_ISSET(nsoc, &read_ready)) { printf("Select() reports no data on new_socket\n"); close (nsoc); return; } if ((bytes_read = recvmsg(nsoc, &msg, 0) ) < 0) { printf("Error recvmsg()ing new_socket\n"); close ( nsoc ); return; } asoc = control.fd; if (opt_verbose) { printf( "New fd %d recvmsged from new_socket\n", asoc); } close(nsoc); FD_ZERO(&read_ready); FD_SET(asoc, &read_ready); timeout.tv_sec = 0; timeout.tv_usec= 0; /* This select would not expect not normally expect to to see available data */ sres = select(asoc + 1, &read_ready, (fd_set *)NULL, (fd_set *)NULL, &timeout); if (opt_verbose && (sres > 0)) { printf("pid %d, read select on %d already says ready\n", getpid(), asoc); } if (s_write_msg(asoc, 'a', "msg1") < 0) { if (opt_verbose) { printf("Warder write msg 1 failed: %s\n", strerror(errno)); } close(asoc); return; } bzero(msg_buf, 80); if (s_read_msg(asoc, msg_buf) < 0) { close(asoc); if (opt_instance != 0) { exit(1); } return; } close(asoc); return; } /*--------------------------------------------------------------------------- Name : s_write_msg Function Description: Build and send a message to the client. Return Value : -1 - write failed 1 - operation was successful Arguments : soc - file descriptor of the socket to write to msgkey - First character of the message msg - text of the messge. ---------------------------------------------------------------------------*/ int s_write_msg(int soc, char msgkey, char *msg) { char rmsg[80]; sprintf(&rmsg[0], "%c%s\n", msgkey, msg); if (write(soc, rmsg, strlen(rmsg)) < 0) { return(-1); } return(1); } /*--------------------------------------------------------------------------- Name : s_read_msg Function Description: Select on the socket waiting for data and when availabel read it from the socket and save it in the msg buffer. Return Value : -1 - write failed 1 - operation was successful Arguments : soc - file descriptor from which to read the client messge msg_buf - storage location where the message is placed. ---------------------------------------------------------------------------*/ int s_read_msg(int soc, char *msg_buf) { struct timeval timeout; fd_set read_ready; int rcnt; int scnt; struct msghdr msg; struct { struct cmsghdr hdr; int fd; } control; struct iovec iov[1]; int bytes_read; /* # of bytes in recvmsg() */ retry: bzero(msg_buf, 80); timeout.tv_sec = 100; timeout.tv_usec = 0; FD_ZERO ( &read_ready ); FD_SET (soc, &read_ready ); if ((scnt = select( soc+1, &read_ready, NULL, NULL, &timeout)) == -1) { printf("select error in warder read\n"); return (-1); } else if (scnt == 0) { printf("read message timed out select\n"); return (-1); } if ( !FD_ISSET( soc, &read_ready )) { printf("soc %d is not read after select\n", soc); return (-1); } bzero(&control, sizeof(control)); iov[0].iov_base = msg_buf; iov[0].iov_len = 80; msg.msg_name = (caddr_t) 0; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t) &control; msg.msg_controllen = sizeof(control); msg.msg_flags = 0; if ((rcnt = recvmsg(soc, &msg, 0)) < 0) { if (opt_verbose) { printf("w_read: recvmsg error: %s\n", strerror(errno)); } return (-1); } else if (rcnt == 0) { if (opt_verbose) { printf("w_read: read 0 bytes\n"); } sleep(1); goto retry; } else if (strcmp("bmsg2\n", msg_buf) != 0) { printf("w_read unexpected response len %d, '%s'\n", rcnt, msg); goto retry; } return(1); } /************************************************************************* * * Client Side Functions * *************************************************************************/ /*--------------------------------------------------------------------------- Name : do_client Function Description: Enters a perpetual loop which creates the connection socket, connects to the server. Once the connection is extablished carry out the client side connection actions and then close up the connection file descriptors and repeat the process. Arguments : cinst - 0 to indicate running in quiet mode, 1 to indicate running in report error mode. ---------------------------------------------------------------------------*/ void do_client(int cinst) { int length; int r; struct sockaddr_un peer; char* sockfilename; int sock1; int sockp[2]; int cycle_cnt = 0; while (1) { if ((sock1 = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { printf("client socket failed\n"); exit(0); } memset(&peer, 0, sizeof(peer)); peer.sun_family = AF_UNIX; strcpy( peer.sun_path, serv_sockets[cinst]); length = strlen( peer.sun_path) + sizeof (peer.sun_family) + 1; retry: if (connect (sock1, (struct sockaddr*) & peer, length) < 0) { printf("client connect() failed for %s: %s\n", serv_sockets[0], strerror(errno)); sleep(1); goto retry; } fcntl(sock1, F_SETFD, 1); caction(sock1, sockp); close(sock1); close(sockp[0]); close(sockp[1]); cycle_cnt++; if ((cycle_cnt % 20) == 0) { sleep(5); } } } /*--------------------------------------------------------------------------- Name : caction Function Description: Create a socket pair, send the second file descriptor to the server using the provides connection socket. Close the client file descriptor for the sent file descriptor. Wait for the server message and send the client response. Arguments : sock1 - The file descriptor for the connection socket sockp - Pointer to storage for socket pair file descriptors ---------------------------------------------------------------------------*/ void caction(int sock1, int *sockp) { struct msghdr msg; struct { struct cmsghdr hdr; int fd; } control; char buf[80]; fd_set read_ready; struct timeval timeout; int scnt; if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockp) < 0) { printf("client socket pair failed\n"); exit(0); } fcntl(sockp[0], F_SETFL, O_NONBLOCK); fcntl(sockp[0], F_SETFD, 1); timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO ( &read_ready ); FD_SET ( sockp[1], &read_ready ); if ((scnt =select(sockp[1] + 1, &read_ready, NULL, NULL, &timeout)) < 0) { printf("client: select on socket pair fd %d failed, %s\n", sockp[1], strerror(errno)); } if (scnt > 0) { printf("client: select on socket pair fd1 %d read before being sent\n", sockp[1]); } control.hdr.cmsg_len = sizeof(control); control.hdr.cmsg_level = SOL_SOCKET; control.hdr.cmsg_type = SCM_RIGHTS; control.fd = sockp[1]; msg.msg_name = (caddr_t)0; msg.msg_namelen = 0; msg.msg_iov = (struct iovec *)0; msg.msg_iovlen = 0; msg.msg_control = (caddr_t) &control; msg.msg_controllen = sizeof(control); msg.msg_flags = 0; if (sendmsg(sock1, &msg, 0) < 0) { printf("client: failed to send fd to server. rsock = %d. mine = %d. warder's = %d", sock1, sockp[0], sockp[1]); close(sockp[0]); close(sockp[1]); exit(1); } close(sockp[1]); if (c_read_msg(sockp[0], buf) < 0) { exit(0); } if (c_write_msg(sockp[0], 'b', "msg2\n") < 0) { exit(0); } } /*--------------------------------------------------------------------------- Name : c_read_msg Function Description: Wait on the socket for receipt of data, then read the server mesasge from the provided file descriptor and save the results in the message buffer. Return Value : -1 Operation failed 1 Operaiton was successful Arguments : soc - File descriptor to read the server message from msg_buf - Place to hold the received message. ---------------------------------------------------------------------------*/ int c_read_msg(int soc, char *msg_buf) { struct iovec vec[2]; char prefix; #define BUFSIZE 8000 char buffer[BUFSIZE]; char *dyn_buf; int ready; int r; struct msghdr msg; fd_set read_ready; struct timeval timeout; timeout.tv_sec = 100; timeout.tv_usec = 0; FD_ZERO ( &read_ready ); FD_SET ( soc, &read_ready ); if (select(soc + 1, &read_ready, NULL, NULL, &timeout) < 0) { printf("client read: select error on msg 1: %s\n", strerror(errno)); return(-1); } vec[0].iov_base = & prefix; vec[0].iov_len = 1; vec[1].iov_base = & buffer[0]; vec[1].iov_len = sizeof(buffer); msg.msg_iov = & vec[0]; msg.msg_iovlen = 2; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; if ((r = recvmsg(soc, &msg, 0)) < 0) { printf("client recv msg 1 failed: %s\n", strerror(errno)); return(-1); } else if (r == 0) { printf("clinet recved no data\n"); return(-1); } memcpy(msg_buf, buffer, r - 1); return(1); } /*--------------------------------------------------------------------------- Name : c_write_msg Function Description: Build and send the reply message to the server. In the case that we are running in the detect problem mode we exit processing when the error is detected. Return Value : 1 - Operation completed. Arguments : sock - File descriptor to which to write the message msgkey - First character of the message smsg - Test of the message. ---------------------------------------------------------------------------*/ int c_write_msg(int sock, char msgkey, char *smsg) { struct iovec vec[2]; int count; struct msghdr msg; int total; int r; vec[0].iov_base = &msgkey; vec[0].iov_len = 1; total = vec[0].iov_len; count = 1; if (smsg) { vec[1].iov_base = (void*)smsg; vec[1].iov_len = strlen(smsg); total += vec[1].iov_len; count = 2; } msg.msg_iov = & vec[0]; msg.msg_iovlen = count; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; errno = 0; r = sendmsg(sock, &msg, 0); if (r != total) { if (opt_verbose) { printf("client: sendmsg() failed, %d, %s\n", errno, strerror(errno)); } if (opt_instance == 1) { exit(1); } } return(1); } >Fix: Add code like the following to unp_gc. NOTE: the version numebers do not match FreeBSD CVS, nor to the line nubmers match any freebsd release. BUT, the context should point to the relevant location for a 6.0 copy of the file as well as current. diff -c -r1.12 -r1.14 *** uipc_usrreq.c 9 Jan 2007 22:40:59 -0000 1.12 --- uipc_usrreq.c 13 Feb 2007 23:31:32 -0000 1.14 *************** *** 1675,1680 **** --- 1675,1681 ---- { struct file *fp, *nextfp; struct socket *so; + struct socket *soa; struct file **extra_ref, **fpp; int nunref, i; int nfiles_snap; *************** *** 1762,1767 **** --- 1765,1783 ---- SOCKBUF_LOCK(&so->so_rcv); unp_scan(so->so_rcv.sb_mb, unp_mark); SOCKBUF_UNLOCK(&so->so_rcv); + /* + * If socket is in listening state, then sockets + * in its accept queue are accessible, and so + * are any descriptors in those sockets' receive + * queues. + */ + ACCEPT_LOCK(); + TAILQ_FOREACH(soa, &so->so_comp, so_list) { + SOCKBUF_LOCK(&soa->so_rcv); + unp_scan(soa->so_rcv.sb_mb, unp_mark); + SOCKBUF_UNLOCK(&soa->so_rcv); + } + ACCEPT_UNLOCK(); } } while (unp_defer); sx_sunlock(&filelist_lock); >Release-Note: >Audit-Trail: >Unformatted: