nos
nos

Reputation: 229108

Proper length of an AF_UNIX socket when calling bind()

bind() needs a length of the sockaddr structure you've given it. Now, for unix sockets, sockaddr_un is used

What's the proper ways of calculating the length of this when you've filled in the sun_path member ? I've seen multiple approaches:

socklen_t len = sizeof(sockaddr_un);
socklen_t len = offsetof(sockaddr_un,sun_path) + strlen(addr.sun_path);
socklen_t len = offsetof(sockaddr_un,sun_path) + strlen(addr.sun_path) + 1;
socklen_t len = sizeof(sockaddr.sun_family  ) + strlen(addr.sun_path);

And even other approaches. Is it ok to just take the sizeof(sockaddr_un) - or what is the proper way ?

Upvotes: 9

Views: 8353

Answers (2)

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84169

You are supposed to use SUN_LEN macro. Here's from /usr/include/sys/un.h on my Mac:

#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
/* actual length of an initialized sockaddr_un */
#define SUN_LEN(su) \
        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif  /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */

Edit:

Yes, it's not portable and not POSIX, but we work on real platforms, don't we?

The thing is that you have to zero-terminate the path and the above code is as good as sizeof( struct sockaddr_un ) but might save you a few bytes when copying from user to kernel but wastes a few cycles in strlen.

Look at how Linux handles that length (from http://lxr.linux.no/linux+v2.6.32/net/unix/af_unix.c#L200):

static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp)
{
    if (len <= sizeof(short) || len > sizeof(*sunaddr))
        return -EINVAL;
    if (!sunaddr || sunaddr->sun_family != AF_UNIX)
        return -EINVAL;
    if (sunaddr->sun_path[0]) {
        /*
         * This may look like an off by one error but it is a bit more
         * subtle. 108 is the longest valid AF_UNIX path for a binding.
         * sun_path[108] doesnt as such exist.  However in kernel space
         * we are guaranteed that it is a valid memory location in our
         * kernel address buffer.
         */
        ((char *)sunaddr)[len] = 0;
        len = strlen(sunaddr->sun_path)+1+sizeof(short);
        return len;
    }

    *hashp = unix_hash_fold(csum_partial(sunaddr, len, 0));
    return len;
}

Here len is directly from third argument to bind system call, but sunaddr is already copied into kernel space with that length. You can't have address longer then sizeof( sockadd_un ). Kernel does the strlen anyway.

So yes, doing sizeof( sockaddr_un ) is probably safer across the board, but telling kernel exact length doesn't hurt either.

Upvotes: 10

St&#233;phan Kochen
St&#233;phan Kochen

Reputation: 19943

sizeof(struct sockaddr_un) is fine.

Take a look at the manpage unix(7). The field sun_path is a character array that is part of the struct.

Upvotes: 4

Related Questions