Вы должны использовать макрос 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 )
, вероятно, более безопасно по всем направлениям, но указание точной длины ядра также не повредит.