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

Bug#702943: Debian GNU/kFreeBSD bind() truncates too long Unix domain socket pathname



Package: kfreebsd-image-9.0-2-amd64
Version: 9.0-10

I found that bind() for Unix domain socket truncates the given
socket pathname if the pathname is too long.

bind() should be failed for too long pathnames.

POSIX 2001 (IEEE Std 1003.1-2001) defines ENAMETOOLONG error for bind()
as follows:

| If the address family of the socket is AF_UNIX, then bind() shall fail if:
| ...
|    [ENAMETOOLONG]
|        A component of a pathname exceeded {NAME_MAX} characters, or an entire
|        pathname exceeded {PATH_MAX} characters.

Other platforms, including GNU/Linux and FreeBSD, fails with ENAMETOOLONG
or EINVAL for too long pathnames.
The maximum length varies, though.

I compared various platforms.  The result is here:
https://github.com/akr/socket-test
http://htmlpreview.github.com/?https://github.com/akr/socket-test/blob/master/results/index.html#unix-stream256c0

The following program reproduce the problem.
It specify a pathname with 4108 bytes (including the terminating NUL) to
bind() and it succeeds but actual socket pathname length is 104 bytes.
The given pathname length is longer than NAME_MAX(255) and PATH_MAX(1024).
So bind() should be failed according to POSIX.

% uname -srvm
GNU/kFreeBSD 9.0-2-amd64 #0 Sat Nov 24 04:44:27 UTC 2012 x86_64
% lsb_release -idrc
Distributor ID:	Debian
Description:	Debian GNU/kFreeBSD 7.0 (wheezy)
Release:	7.0
Codename:	wheezy
% ls
tst.c
% cat tst.c
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
  int s, ret, len;
  char bigbuf[sizeof(struct sockaddr_un)+4000];
  struct sockaddr_un *addr;

  printf("sizeof(sun_path): %d\n", (int)sizeof(addr->sun_path));
  printf("NAME_MAX: %d\n", (int)NAME_MAX);
  printf("PATH_MAX: %d\n", (int)PATH_MAX);

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

  addr = (struct sockaddr_un *)bigbuf;
  memset(addr, '\0', sizeof(bigbuf));

  addr->sun_family = AF_UNIX;

  len = sizeof(bigbuf)-offsetof(struct sockaddr_un, sun_path);
  printf("socket pathname length: %d\n", len);
  memset(addr->sun_path, 's', len-1);
  addr->sun_path[len-1] = '\0';

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

  printf("bind() succeeds.\n");

  exit(EXIT_SUCCESS);
}
% gcc -Wall tst.c
% ./a.out
sizeof(sun_path): 104
NAME_MAX: 255
PATH_MAX: 1024
socket pathname length: 4108
bind() succeeds.
% ls s*|wc
      1       1     105
% ls s*|od -c -Ad
0000000   s   s   s   s   s   s   s   s   s   s   s   s   s   s   s   s
*
0000096   s   s   s   s   s   s   s   s  \n
0000105
% dpkg -l|egrep '\<kfreebsd-image|libc-'
ii  kfreebsd-image-9-amd64            9.0-10
kfreebsd-amd64 kernel of FreeBSD 9 image (meta-package)
ii  kfreebsd-image-9.0-2-amd64        9.0-10
kfreebsd-amd64 kernel of FreeBSD 9.0 image
ii  libc-bin                          2.13-38
kfreebsd-amd64 Embedded GNU C Library: Binaries
ii  libc-dev-bin                      2.13-38
kfreebsd-amd64 Embedded GNU C Library: Development binaries

Note that it is not clear that bind() should be failed or not for
pathnames longer than sizeof(sun_path) but shorter than NAME_MAX.
I feel it should also be failed or succeeds with a socket file with given
length.
The truncation is very unintuitive.
-- 
Tanaka Akira


Reply to: