Правильная длина сокета AF_UNIX при вызове bind () - PullRequest
9 голосов
/ 22 февраля 2010

bind () требуется длина заданной вами структуры sockaddr. Теперь для сокетов unix используется sockaddr_un

Как правильно рассчитать длину, когда вы заполнили элемент sun_path? Я видел несколько подходов:

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);

И даже другие подходы. Можно ли просто взять sizeof (sockaddr_un) - или как правильно?

Ответы [ 2 ]

9 голосов
/ 22 февраля 2010

Вы должны использовать макрос SUN_LEN. Вот из /usr/include/sys/un.h на моем 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:

Да, это не портативный и не POSIX, но мы работаем на реальных платформах, не так ли?

Дело в том, что вы должны завершать путь нулем, и приведенный выше код равен sizeof( struct sockaddr_un ), но может сэкономить вам несколько байтов при копировании из пользователя в ядро, но потратит несколько циклов в strlen.

Посмотрите, как Linux обрабатывает эту длину (от 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;
}

Здесь len непосредственно от третьего аргумента до системного вызова bind, но sunaddr уже скопирован в пространство ядра с такой длиной. Вы не можете иметь адрес дольше, чем sizeof( sockadd_un ). Ядро все равно делает strlen.

Так что да, выполнение sizeof( sockaddr_un ), вероятно, более безопасно по всем направлениям, но указание точной длины ядра также не повредит.

4 голосов
/ 22 февраля 2010

sizeof(struct sockaddr_un) в порядке.

Взгляните на справочную страницу unix(7). Поле sun_path является массивом символов, который является частью структуры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...