Hi,

while debugging, I apparently stumbled upon a bug of getsockname() for a 
bound unix socket, as also the attached test program shows: sun_path is 
left unfilled, as also the comment of S_socket_whatis_address() in 
hurd/pflocal/pf.c would suggest.

There's also another possibly weird behaviour in that: 
S_socket_whatis_address() sets its sockaddr_len parameter in what seems 
also what Linux does, ie
  offsetof(struct sockaddr, sa_data) + strlen(sun_path) + 1
instead of sizeof(struct sockaddr_un), like apparently most of other 
OSes do[1]; of course, given that sun_path is never filled (as said 
above), the returned sockaddr_len is always 3.

[1] in perl's code, I've seen this snippet:
unpack_sockaddr_un(sun_sv)
[...]
#   ifndef __linux__
        /* On Linux sockaddrlen on sockets returned by accept, recvfrom,
           getpeername and getsockname is not equal to sizeof(addr). */
        if (sockaddrlen != sizeof(addr)) {
            croak("Bad arg length for %s, length is %d, should be %d",
                        "Socket::unpack_sockaddr_un",
                        sockaddrlen, sizeof(addr));
        }
#   endif

-- 
Pino Toscano
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>

static const char s_socketpath[] = "/tmp/test.sn.sock";

void die(int x, const char *s)
{
  perror(s);
  unlink(s_socketpath);
  exit(x);
}

int main()
{
  int ret;
  int s;
  struct sockaddr_un sock;
  char namebuf[256];
  socklen_t bufsize = sizeof(namebuf);

  namebuf[0] = 'a';
  namebuf[1] = 0;

  memset(&sock, 0, sizeof(sock));
  sock.sun_family = AF_UNIX;
  strcpy(sock.sun_path, s_socketpath);

  s = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
  if (s < 0) die(1, "socket");

  ret = bind(s, (struct sockaddr *)&sock, sizeof(sock));
  if (ret < 0) die(2, "bind");

  ret = getsockname(s, (struct sockaddr *)namebuf, &bufsize);
  {
    struct sockaddr_un *ss = (struct sockaddr_un *)namebuf;
    printf("> getsockname: %d, %d ('%s') vs %u/%u\n", ret, bufsize, namebuf, offsetof(struct sockaddr, sa_data) + strlen(ss->sun_path) + 1,sizeof(sock));
    printf("> ... %d vs %d, %s (%u)\n", ss->sun_family, AF_UNIX, ss->sun_path, strlen(ss->sun_path));
  }
  if (ret < 0) die(3, "getsockname");

  shutdown(s, SHUT_RDWR);
  close(s);

  unlink(s_socketpath);

  return 0;
}

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to