tech-net archive

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

Re: why not remove AF_LOCAL sockets on last close?



On Thu, 24 Jun 2010 22:55:51 -0400
Thor Simon <tls%coyotepoint.com@localhost> wrote:

> Can anyone tell me why, exactly, we shouldn't remove bound AF_LOCAL
> sockets from the filesystem on last close?  The following test program
> produces "second socket bind failed" on every system I've tested it on,
> and seems to cover the only possible use case for this "feature"...

I initially had the impression that leaving the socket around was a
feature to allow re-binding to the same file by an unprivileged process
after first creating the socket node as root (i.e. at a location where
unprivileged processes cannot create new files such as /var/run/) to
then set its permissions in a way to permit the unprivileged user or
group to bind(2) it.

However, I wrote a small test program and realized that despite
SO_REUSEADDR this doesn't work, and indeed after checking the kernel
code SO_REUSEADDR is ignored in the AF_LOCAL unp_bind() code.


#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
        struct sockaddr_un      sun;
        int                     s, opt;

        if (argc != 2)
                errx(EXIT_FAILURE, "Usage: %s <path>", argv[0]);

        if ((s = socket(PF_LOCAL, SOCK_DGRAM, 0)) == -1)
                err(EXIT_FAILURE, "socket()");

        opt = 1;
        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1)
                err(EXIT_FAILURE, "setsockopt(SO_REUSEADDR)");

        sun.sun_family = AF_UNIX;
        sun.sun_len = sizeof(sun);
        (void)strlcpy(sun.sun_path, argv[1], sizeof(sun.sun_path));

        if (bind(s, (struct sockaddr *)&sun, sun.sun_len) != 0)
                err(EXIT_FAILURE, "bind()");

        (void)close(s);

        return EXIT_SUCCESS;
}

$ cc -o test test.c
$ ./test /tmp/foo.sock
$ ./test /tmp/foo.sock
test: bind(): Address already in use


So I to do what I described above, one has to create a directory
in /var/run instead, with permissions such that the unprivileged
process can create a file there.

Then I'm unsure why we leave those sockets dangling around, although
it's quite easy to explicitely unlink them at close time...
-- 
Matt


Home | Main Index | Thread Index | Old Index