From fredriks@mcs.com  Fri Oct 11 12:22:43 1996
Received: from fredriks-1.pr.mcs.net (fredriks-1.pr.mcs.net [205.164.50.241])
          by freefall.freebsd.org (8.7.5/8.7.3) with ESMTP id MAA19888
          for <FreeBSD-gnats-submit@freebsd.org>; Fri, 11 Oct 1996 12:22:41 -0700 (PDT)
Received: (from fredriks@localhost) by fredriks-1.pr.mcs.net (8.7.6/8.6.6) id LAA03741; Fri, 11 Oct 1996 11:07:27 -0500 (CDT)
Message-Id: <199610111607.LAA03741@fredriks-1.pr.mcs.net>
Date: Fri, 11 Oct 1996 11:07:27 -0500 (CDT)
From: fredriks@mcs.com
Reply-To: fredriks@mcs.com
To: FreeBSD-gnats-submit@freebsd.org
Subject: accept does not preserve filedescriptor flags
X-Send-Pr-Version: 3.2

>Number:         1775
>Category:       kern
>Synopsis:       accept does not preserve file descriptor flags
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Oct 11 12:30:01 PDT 1996
>Closed-Date:    Tue Oct 15 12:30:11 PDT 1996
>Last-Modified:  Tue Oct 15 12:34:14 PDT 1996
>Originator:     & Fredriksen
>Release:        FreeBSD 2.2-961004-SNAP i386
>Organization:
Flaaklypa Hackers
>Environment:

FreeBSD. I think this bug has been around for a while. It is present in
stable as well.

>Description:

	accept1() in uipc_syscalls when it is cloning the listening 
	socket does not preserve the filedescriptor flags, but sets
	them like this:

		fp->f_flag = FREAD|FWRITE;

	If you had turned on O_NONBLOCKING earlier on the listening socket,
	fcntl(newsocket, F_GETFL, 0) will not return the O_NONBLOCKING 
	flag even though the flag is set in the socket itself.

>How-To-Repeat:

	Included is a simple program that will print out what the 
	flags on the accepted socket looks like. Just run it, and 
	telnet lcoalhost 10000 to connect to it.


#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <syslog.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/fcntl.h>


int lsock;
fd_set fm;


procnewclient() {
	int msgsock = -1;
	int sock_flags;

	msgsock = accept(lsock, 0, 0);
	sock_flags = fcntl(msgsock, F_GETFL, 0);
	printf("Socket fcntl options are: %x\n", sock_flags);
	printf(" O_NONBLOCK = %d\n", sock_flags & O_NONBLOCK ? 1 : 0);
	printf(" O_APPEND = %d\n", sock_flags & O_APPEND ? 1 : 0);
	printf(" O_ASYNC = %d\n", sock_flags & O_ASYNC ? 1 : 0);
	close(msgsock);
}



main(int argc, char *argv[]) {
	int flag;
	struct timeval tv;
	struct sockaddr_in inaddr;


	/*
	 * open our listener socket
	 */
	
	lsock = socket(PF_INET, SOCK_STREAM, 0);
	if (lsock < 0) {
		perror("cannot create socket");
		exit(1);
	}

	bzero(&inaddr, sizeof(inaddr));

	inaddr.sin_family = AF_INET;
	inaddr.sin_port = htons(10000);
	inaddr.sin_addr.s_addr = INADDR_ANY;

	flag = 1;

	setsockopt( lsock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof flag);

	if (bind (lsock, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0) {
		perror("bind failed");
		exit(2);
	}


	listen (lsock, 5);

        fcntl(lsock, F_SETFL, O_NDELAY);

	
	while(1) {

		fflush(stdout);
		/*
		 * add in our client log-in socket
		 */
		FD_SET(lsock, &fm);
	
		/*
		 * wait for something to happen
		 */
		if( select( FD_SETSIZE, &fm, (fd_set *)0, (fd_set *)0, (struct timeval *) 0) >= 1) {
			/*
			 * new client???
			 */
			if( FD_ISSET( lsock, &fm)) {
				procnewclient();
			}

		}
	}
}
>Fix:
	Here is a context diff:

*** uipc_syscalls.c.orig	Sun Sep 22 00:26:41 1996
--- uipc_syscalls.c	Sun Sep 22 00:26:47 1996
***************
*** 164,170 ****
  	int *retval;
  	int compat;
  {
! 	struct file *fp;
  	struct mbuf *nam;
  	int namelen, error, s;
  	struct socket *head, *so;
--- 164,170 ----
  	int *retval;
  	int compat;
  {
! 	struct file *fp, tfp;
  	struct mbuf *nam;
  	int namelen, error, s;
  	struct socket *head, *so;
***************
*** 206,211 ****
--- 206,213 ----
  		splx(s);
  		return (error);
  	}
+ 		/* Keep a pointer to old file descriptor */
+ 	tfp = fp;
  	error = falloc(p, &fp, retval);
  	if (error) {
  		splx(s);
***************
*** 221,229 ****
  	head->so_qlen--;
  
  	fp->f_type = DTYPE_SOCKET;
! 	fp->f_flag = FREAD|FWRITE;
  	fp->f_ops = &socketops;
  	fp->f_data = (caddr_t)so;
  	nam = m_get(M_WAIT, MT_SONAME);
  	(void) soaccept(so, nam);
  	if (uap->name) {
--- 223,232 ----
  	head->so_qlen--;
  
  	fp->f_type = DTYPE_SOCKET;
! 	fp->f_flag = tfp->f_flag;
  	fp->f_ops = &socketops;
  	fp->f_data = (caddr_t)so;
+ 	tfp = NULL;
  	nam = m_get(M_WAIT, MT_SONAME);
  	(void) soaccept(so, nam);
  	if (uap->name) {
	

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->analyzed 
State-Changed-By: wollman 
State-Changed-When: Tue Oct 15 11:46:09 PDT 1996 
State-Changed-Why:  
Indeed this is a bug, although my fix will be slightly different. 
State-Changed-From-To: analyzed->closed 
State-Changed-By: wollman 
State-Changed-When: Tue Oct 15 12:30:11 PDT 1996 
State-Changed-Why:  
Fixed in rev. 1.20 of uipc_syscalls.c. 
>Unformatted:
