The following issue has been SUBMITTED.
======================================================================
https://www.austingroupbugs.net/view.php?id=1641
======================================================================
Reported By: bastien
Assigned To:
======================================================================
Project: 1003.1(2016/18)/Issue7+TC2
Issue ID: 1641
Category: System Interfaces
Type: Clarification Requested
Severity: Editorial
Priority: normal
Status: New
Name: Bastien Roucaries
Organization: debian
User Reference:
Section: sys/socket.h
Page Number: Application usage
Line Number: sockaddr_storage
Interp Status: ---
Final Accepted Text:
======================================================================
Date Submitted: 2023-03-18 07:52 UTC
Last Modified: 2023-03-18 07:52 UTC
======================================================================
Summary: sockaddr_storage is not alias safe
Description:
sockaddr_storage was designed back when strict aliasing wasn’t a
problem.
Back then, one would define a variable of that type, and then access it as
any of the other sockaddr_* types, depending on the value of the first
member. This is Undefined Behavior.
However, there is no
way to use these APIs without invoking Undedfined Behavior, either in
the user program or in libc, so it is still recommended to use this
method. The only correct way to use different types in an API is
through a union.
Exemple of safe use
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
union sockaddr_mayalias {
sa_family_t ss_family;
struct sockaddr sock;
struct sockaddr_storage storage;
struct sockaddr_in in;
struct sockaddr_in6 in6;
struct sockaddr_un un;
};
int main() {
union sockaddr_mayalias sa = {};
socklen_t addrlen = sizeof(sa);
if(getsockname(STDIN_FILENO, &sa.sock, &addrlen) < 0) {
perror("getsockname");
return 1;
}
if(addrlen >= sizeof(sa)) {
errno = EPROTONOSUPPORT;
perror("getsockname return a not supported sock_addr");
return 1;
}
switch(sa.ss_family) {
case(AF_UNSPEC):
printf("AF_UNSPEC socket\n");
break;
case(AF_INET):
{
char s[INET_ADDRSTRLEN];
in_port_t port = ntohs(sa.in.sin_port);
if (inet_ntop(AF_INET, &(sa.in.sin_addr), s, sizeof(s)) == NULL) {
perror("inet_ntop");
return 1;
}
printf("AF_INET socket %s:%i\n",s,(int)port);
break;
}
case(AF_INET6):
{
char s[INET6_ADDRSTRLEN];
in_port_t port = ntohs(sa.in6.sin6_port);
if (inet_ntop(AF_INET6, &(sa.in6.sin6_addr), s, sizeof(s)) == NULL)
{
perror("inet_ntop");
return 1;
}
printf("AF_INET6 socket %s:%i\n",s,(int)port);
break;
}
case(AF_UNIX):
if(addrlen == sizeof(sa_family_t)) {
printf("AF_UNIX socket anonymous\n");
break;
}
/* abstract */
if(sa.un.sun_path[0]=='\0') {
printf("AF_UNIX abstract socket 0x");
for (int i = 0; i < (addrlen - sizeof(sa_family_t)); ++i)
printf("%x",sa.un.sun_path[i]);
printf("\n");
break;
}
/* named */
printf("AF_UNIX named socket ");
for (int i=0; i < strnlen(sa.un.sun_path, addrlen - offsetof(struct
sockaddr_un, sun_path));++i)
printf("%c",sa.un.sun_path[i]);
printf("\n");
break;
default:
errno = EPROTONOSUPPORT;
perror("socket not supported");
return 1;
}
}
Desired Action:
1. document aliasing problem
2. define sockaddr storage as:
struct sockaddr_storage {
union {
sa_family_t ss_family;
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_un sun;
struct _sockaddr_padding padding;
};
};
======================================================================
Issue History
Date Modified Username Field Change
======================================================================
2023-03-18 07:52 bastien New Issue
2023-03-18 07:52 bastien Name => Bastien Roucaries
2023-03-18 07:52 bastien Organization => debian
2023-03-18 07:52 bastien Section => sys/socket.h
2023-03-18 07:52 bastien Page Number => Application usage
2023-03-18 07:52 bastien Line Number => sockaddr_storage
======================================================================