NetBSD Problem Report #47591

From www@NetBSD.org  Mon Feb 25 06:27:36 2013
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
	by www.NetBSD.org (Postfix) with ESMTP id C7C6C63E522
	for <gnats-bugs@gnats.NetBSD.org>; Mon, 25 Feb 2013 06:27:35 +0000 (UTC)
Message-Id: <20130225062734.5779C63E522@www.NetBSD.org>
Date: Mon, 25 Feb 2013 06:27:34 +0000 (UTC)
From: akr@fsij.org
Reply-To: akr@fsij.org
To: gnats-bugs@NetBSD.org
Subject: Unix domain accept() returns the server socket name if client socket is closed before accept() call.
X-Send-Pr-Version: www-1.0

>Number:         47591
>Category:       kern
>Synopsis:       Unix domain accept() returns the server socket name if client socket is closed before accept() call.
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Feb 25 06:30:00 +0000 2013
>Closed-Date:    Fri Dec 20 12:01:11 +0000 2013
>Last-Modified:  Fri Dec 20 12:01:11 +0000 2013
>Originator:     Tanaka Akira
>Release:        NetBSD 6.0.1
>Organization:
>Environment:
NetBSD netbsd6 6.0.1 NetBSD 6.0.1 (GENERIC) amd64
>Description:
I found that accept() for Unix domain socket can return curious socket names.

The test program creates a Unix domain server socket named as "socket-file"
and a client socket connected to that.  The program shows the address obtained
by accept().

However the client socket is closed before accept() call for the server
socket.

In that case, accept() returns the server socket name with garbage.

I think this behavior is a bug because accept() should return client socket name.

The result of test program is follows.

  % ./a.out 
  client socket length: 106
  client socket name: j\x01socket-file\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00,9>\x80\xfe\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  % rm socket-file; ./a.out
  client socket length: 106
  client socket name: j\x01socket-file\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\xac\xd4>\x80\xfe\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00

The "client socket name" field shows struct sockaddr_un.
The first 2 bytes, "j\x01", is sun_len and sun_family.
sun_path field placed after that begins with the server socket name,
"socket-file".
sun_path field also contains garbage which is changed slightly
for each run.


>How-To-Repeat:
% uname -a
NetBSD netbsd6 6.0.1 NetBSD 6.0.1 (GENERIC) amd64
% ls
tst.c
% cat tst.c         
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
  int serv, clnt, acpt;
  struct sockaddr_un addr;
  struct sockaddr_un acpt_addr;
  socklen_t acept_addrlen;
  int ret;
  int i;

  serv = socket(AF_UNIX, SOCK_STREAM, 0);
  if (serv == -1) { perror("socket"); exit(EXIT_FAILURE); }

  memset(&addr, '\0', sizeof(addr));
  addr.sun_family = AF_UNIX;
  strcpy(addr.sun_path, "socket-file");

  ret = bind(serv, (struct sockaddr *)&addr, sizeof(addr));
  if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); }

  ret = listen(serv, SOMAXCONN);
  if (ret == -1) { perror("listen"); exit(EXIT_FAILURE); }

  clnt = socket(AF_UNIX, SOCK_STREAM, 0);
  if (clnt == -1) { perror("socket"); exit(EXIT_FAILURE); }

  ret = connect(clnt, (struct sockaddr *)&addr, sizeof(addr));
  if (ret == -1) { perror("connect"); exit(EXIT_FAILURE); }

  ret = close(clnt);
  if (ret == -1) { perror("close"); exit(EXIT_FAILURE); }

  acept_addrlen = sizeof(acpt_addr);
  acpt = accept(serv, (struct sockaddr *)&acpt_addr, &acept_addrlen);
  if (acpt == -1) { perror("accept"); exit(EXIT_FAILURE); }

  printf("client socket length: %d\n", (int)acept_addrlen);
  printf("client socket name: ");
  for (i = 0; i < acept_addrlen; i++) {
    int ch = ((unsigned char *)&acpt_addr)[i];
    if (ch < ' ' || '~' < ch)
      printf("\\x%02x", ch);
    else
      printf("%c", ch);
    if (i % 16 == 15)
      printf("\n");
  }
  printf("\n");

  return EXIT_SUCCESS;
}
% gcc -Wall -g tst.c
% ./a.out 
client socket length: 106
client socket name: j\x01socket-file\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00,9>\x80\xfe\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
% rm socket-file; ./a.out
client socket length: 106
client socket name: j\x01socket-file\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\xac\xd4>\x80\xfe\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
% rm socket-file; ./a.out
client socket length: 106
client socket name: j\x01socket-file\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00d\xcd9\x80\xfe\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
% 

>Fix:

>Release-Note:

>Audit-Trail:
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/47591 CVS commit: src/sys/kern
Date: Mon, 7 Oct 2013 20:29:24 -0400

 Module Name:	src
 Committed By:	christos
 Date:		Tue Oct  8 00:29:24 UTC 2013

 Modified Files:
 	src/sys/kern: uipc_syscalls.c

 Log Message:
 PR/47591: Michael Plass: If the unix socket is closed before accept,
 unp->unp_conn will be NULL in PRU_ACCEPT, as called from
 sys_accept->so_accept. This will cause the usrreq to return with
 no error, leaving the mbuf gotten from m_get() with an uninitialized
 length, containing junk from a previous call. Initialize m_len to
 be 0 to handle this case. This is yet another reason why Beverly's
 idea of setting m_len = 0 in m_get() makes a lot of sense. Arguably
 this could be an error, since the data we return now has 0 family
 and length.


 To generate a diff of this commit:
 cvs rdiff -u -r1.162 -r1.163 src/sys/kern/uipc_syscalls.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Stephen Borrill" <sborrill@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/47591 CVS commit: [netbsd-5] src/sys/kern
Date: Fri, 13 Dec 2013 12:22:39 +0000

 Module Name:	src
 Committed By:	sborrill
 Date:		Fri Dec 13 12:22:39 UTC 2013

 Modified Files:
 	src/sys/kern [netbsd-5]: uipc_syscalls.c

 Log Message:
 Pull up the following revisions(s) (requested by spz in ticket #1891):
 	sys/kern/uipc_syscalls.c:	revision 1.163

 If the unix socket is closed before accept, the mbuf returned by
 m_get() will have an uninitialized length and contain junk from a
 previous call. Initialize m_len to be 0 to handle this case.
 Fixes PR/47591


 To generate a diff of this commit:
 cvs rdiff -u -r1.134.4.3 -r1.134.4.4 src/sys/kern/uipc_syscalls.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Manuel Bouyer" <bouyer@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/47591 CVS commit: [netbsd-6] src/sys/kern
Date: Sat, 14 Dec 2013 19:36:33 +0000

 Module Name:	src
 Committed By:	bouyer
 Date:		Sat Dec 14 19:36:33 UTC 2013

 Modified Files:
 	src/sys/kern [netbsd-6]: uipc_syscalls.c

 Log Message:
 Pull up following revision(s) (requested by spz in ticket #996):
 	sys/kern/uipc_syscalls.c: revision 1.163
 PR/47591: Michael Plass: If the unix socket is closed before accept,
 unp->unp_conn will be NULL in PRU_ACCEPT, as called from
 sys_accept->so_accept. This will cause the usrreq to return with
 no error, leaving the mbuf gotten from m_get() with an uninitialized
 length, containing junk from a previous call. Initialize m_len to
 be 0 to handle this case. This is yet another reason why Beverly's
 idea of setting m_len = 0 in m_get() makes a lot of sense. Arguably
 this could be an error, since the data we return now has 0 family
 and length.


 To generate a diff of this commit:
 cvs rdiff -u -r1.154.2.4 -r1.154.2.5 src/sys/kern/uipc_syscalls.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Manuel Bouyer" <bouyer@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/47591 CVS commit: [netbsd-6-1] src/sys/kern
Date: Sat, 14 Dec 2013 19:36:58 +0000

 Module Name:	src
 Committed By:	bouyer
 Date:		Sat Dec 14 19:36:58 UTC 2013

 Modified Files:
 	src/sys/kern [netbsd-6-1]: uipc_syscalls.c

 Log Message:
 Pull up following revision(s) (requested by spz in ticket #996):
 	sys/kern/uipc_syscalls.c: revision 1.163
 PR/47591: Michael Plass: If the unix socket is closed before accept,
 unp->unp_conn will be NULL in PRU_ACCEPT, as called from
 sys_accept->so_accept. This will cause the usrreq to return with
 no error, leaving the mbuf gotten from m_get() with an uninitialized
 length, containing junk from a previous call. Initialize m_len to
 be 0 to handle this case. This is yet another reason why Beverly's
 idea of setting m_len = 0 in m_get() makes a lot of sense. Arguably
 this could be an error, since the data we return now has 0 family
 and length.


 To generate a diff of this commit:
 cvs rdiff -u -r1.154.2.4 -r1.154.2.4.2.1 src/sys/kern/uipc_syscalls.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Manuel Bouyer" <bouyer@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/47591 CVS commit: [netbsd-6-0] src/sys/kern
Date: Sat, 14 Dec 2013 19:37:02 +0000

 Module Name:	src
 Committed By:	bouyer
 Date:		Sat Dec 14 19:37:02 UTC 2013

 Modified Files:
 	src/sys/kern [netbsd-6-0]: uipc_syscalls.c

 Log Message:
 Pull up following revision(s) (requested by spz in ticket #996):
 	sys/kern/uipc_syscalls.c: revision 1.163
 PR/47591: Michael Plass: If the unix socket is closed before accept,
 unp->unp_conn will be NULL in PRU_ACCEPT, as called from
 sys_accept->so_accept. This will cause the usrreq to return with
 no error, leaving the mbuf gotten from m_get() with an uninitialized
 length, containing junk from a previous call. Initialize m_len to
 be 0 to handle this case. This is yet another reason why Beverly's
 idea of setting m_len = 0 in m_get() makes a lot of sense. Arguably
 this could be an error, since the data we return now has 0 family
 and length.


 To generate a diff of this commit:
 cvs rdiff -u -r1.154.2.1.4.1 -r1.154.2.1.4.2 src/sys/kern/uipc_syscalls.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->feedback
State-Changed-By: bouyer@NetBSD.org
State-Changed-When: Sat, 14 Dec 2013 19:44:46 +0000
State-Changed-Why:
Hello,
a fix has been commioted to HEAD and pulled up to all netbsd-6 branches.
Is it OK to close the PR ?


From: Tanaka Akira <akr@fsij.org>
To: gnats-bugs@netbsd.org
Cc: kern-bug-people@netbsd.org, netbsd-bugs@netbsd.org, gnats-admin@netbsd.org, 
	bouyer@netbsd.org
Subject: Re: kern/47591 (Unix domain accept() returns the server socket name
 if client socket is closed before accept() call.)
Date: Fri, 20 Dec 2013 17:54:20 +0900

 2013/12/15  <bouyer@netbsd.org>:
 > Synopsis: Unix domain accept() returns the server socket name if client socket is closed before accept() call.

 > Hello,
 > a fix has been commioted to HEAD and pulled up to all netbsd-6 branches.
 > Is it OK to close the PR ?

 Thank you.
 I confirmed that the problem is fixed in NetBSD 6.99.28.

 No problem to close this PR.

 $ uname -mrsv
 NetBSD 6.99.28 NetBSD 6.99.28 (GENERIC) #0: Tue Dec 17 11:48:16 UTC
 2013  builds@b8.netbsd.org:/home/builds/ab/HEAD/amd64/201312171040Z-obj/home/builds/ab/HEAD/src/sys/arch/amd64/compile/GENERIC
 amd64
 -- 
 Tanaka Akira

State-Changed-From-To: feedback->closed
State-Changed-By: bouyer@NetBSD.org
State-Changed-When: Fri, 20 Dec 2013 12:01:11 +0000
State-Changed-Why:
Confirmed fixed.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.