NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/47591: Unix domain accept() returns the server socket name if client socket is closed before accept() call.



>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:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Feb 25 06:30:00 +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:



Home | Main Index | Thread Index | Old Index