diff options
| author | Paul Eggert | 2017-05-17 13:35:52 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-05-17 13:36:56 -0700 |
| commit | e54a3b4fde0c3de7964a2e604c7381101e5d9951 (patch) | |
| tree | d663011b3e5c07c978078a4879f77907d1db3262 /src | |
| parent | 184d74ce002ecb7399cb2b47fc671bfb2feb9855 (diff) | |
| download | emacs-e54a3b4fde0c3de7964a2e604c7381101e5d9951.tar.gz emacs-e54a3b4fde0c3de7964a2e604c7381101e5d9951.zip | |
Avoid undefined behavior in struct sockaddr
Problem noted by Philipp Stephani in:
http://lists.gnu.org/archive/html/emacs-devel/2017-05/msg00391.html
* src/conf_post.h (ATTRIBUTE_MAY_ALIAS, DECLARE_POINTER_ALIAS):
New macros.
* src/process.c (conv_sockaddr_to_lisp, conv_lisp_to_sockaddr)
(connect_network_socket, network_interface_info)
(server_accept_connection): Use it when aliasing non-char objects.
Diffstat (limited to 'src')
| -rw-r--r-- | src/conf_post.h | 14 | ||||
| -rw-r--r-- | src/process.c | 31 |
2 files changed, 31 insertions, 14 deletions
diff --git a/src/conf_post.h b/src/conf_post.h index 1462bd16c75..c05c93b8190 100644 --- a/src/conf_post.h +++ b/src/conf_post.h | |||
| @@ -263,6 +263,20 @@ extern int emacs_setenv_TZ (char const *); | |||
| 263 | #define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST | 263 | #define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST |
| 264 | #define ATTRIBUTE_UNUSED _GL_UNUSED | 264 | #define ATTRIBUTE_UNUSED _GL_UNUSED |
| 265 | 265 | ||
| 266 | #if GNUC_PREREQ (3, 3, 0) | ||
| 267 | # define ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__)) | ||
| 268 | #else | ||
| 269 | # define ATTRIBUTE_MAY_ALIAS | ||
| 270 | #endif | ||
| 271 | |||
| 272 | /* Declare NAME to be a pointer to an object of type TYPE, initialized | ||
| 273 | to the address ADDR, which may be of a different type. Accesses | ||
| 274 | via NAME may alias with other accesses with the traditional | ||
| 275 | behavior, even if options like gcc -fstrict-aliasing are used. */ | ||
| 276 | |||
| 277 | #define DECLARE_POINTER_ALIAS(name, type, addr) \ | ||
| 278 | type ATTRIBUTE_MAY_ALIAS *name = (type *) (addr) | ||
| 279 | |||
| 266 | #if 3 <= __GNUC__ | 280 | #if 3 <= __GNUC__ |
| 267 | # define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) | 281 | # define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) |
| 268 | #else | 282 | #else |
diff --git a/src/process.c b/src/process.c index 8180feaba9a..c30173955d2 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -2476,7 +2476,7 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len) | |||
| 2476 | { | 2476 | { |
| 2477 | case AF_INET: | 2477 | case AF_INET: |
| 2478 | { | 2478 | { |
| 2479 | struct sockaddr_in *sin = (struct sockaddr_in *) sa; | 2479 | DECLARE_POINTER_ALIAS (sin, struct sockaddr_in, sa); |
| 2480 | len = sizeof (sin->sin_addr) + 1; | 2480 | len = sizeof (sin->sin_addr) + 1; |
| 2481 | address = Fmake_vector (make_number (len), Qnil); | 2481 | address = Fmake_vector (make_number (len), Qnil); |
| 2482 | p = XVECTOR (address); | 2482 | p = XVECTOR (address); |
| @@ -2487,8 +2487,8 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len) | |||
| 2487 | #ifdef AF_INET6 | 2487 | #ifdef AF_INET6 |
| 2488 | case AF_INET6: | 2488 | case AF_INET6: |
| 2489 | { | 2489 | { |
| 2490 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; | 2490 | DECLARE_POINTER_ALIAS (sin6, struct sockaddr_in6, sa); |
| 2491 | uint16_t *ip6 = (uint16_t *) &sin6->sin6_addr; | 2491 | DECLARE_POINTER_ALIAS (ip6, uint16_t, &sin6->sin6_addr); |
| 2492 | len = sizeof (sin6->sin6_addr) / 2 + 1; | 2492 | len = sizeof (sin6->sin6_addr) / 2 + 1; |
| 2493 | address = Fmake_vector (make_number (len), Qnil); | 2493 | address = Fmake_vector (make_number (len), Qnil); |
| 2494 | p = XVECTOR (address); | 2494 | p = XVECTOR (address); |
| @@ -2501,7 +2501,7 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len) | |||
| 2501 | #ifdef HAVE_LOCAL_SOCKETS | 2501 | #ifdef HAVE_LOCAL_SOCKETS |
| 2502 | case AF_LOCAL: | 2502 | case AF_LOCAL: |
| 2503 | { | 2503 | { |
| 2504 | struct sockaddr_un *sockun = (struct sockaddr_un *) sa; | 2504 | DECLARE_POINTER_ALIAS (sockun, struct sockaddr_un, sa); |
| 2505 | ptrdiff_t name_length = len - offsetof (struct sockaddr_un, sun_path); | 2505 | ptrdiff_t name_length = len - offsetof (struct sockaddr_un, sun_path); |
| 2506 | /* If the first byte is NUL, the name is a Linux abstract | 2506 | /* If the first byte is NUL, the name is a Linux abstract |
| 2507 | socket name, and the name can contain embedded NULs. If | 2507 | socket name, and the name can contain embedded NULs. If |
| @@ -2612,7 +2612,7 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int | |||
| 2612 | p = XVECTOR (address); | 2612 | p = XVECTOR (address); |
| 2613 | if (family == AF_INET) | 2613 | if (family == AF_INET) |
| 2614 | { | 2614 | { |
| 2615 | struct sockaddr_in *sin = (struct sockaddr_in *) sa; | 2615 | DECLARE_POINTER_ALIAS (sin, struct sockaddr_in, sa); |
| 2616 | len = sizeof (sin->sin_addr) + 1; | 2616 | len = sizeof (sin->sin_addr) + 1; |
| 2617 | hostport = XINT (p->contents[--len]); | 2617 | hostport = XINT (p->contents[--len]); |
| 2618 | sin->sin_port = htons (hostport); | 2618 | sin->sin_port = htons (hostport); |
| @@ -2622,8 +2622,8 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int | |||
| 2622 | #ifdef AF_INET6 | 2622 | #ifdef AF_INET6 |
| 2623 | else if (family == AF_INET6) | 2623 | else if (family == AF_INET6) |
| 2624 | { | 2624 | { |
| 2625 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; | 2625 | DECLARE_POINTER_ALIAS (sin6, struct sockaddr_in6, sa); |
| 2626 | uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr; | 2626 | DECLARE_POINTER_ALIAS (ip6, uint16_t, &sin6->sin6_addr); |
| 2627 | len = sizeof (sin6->sin6_addr) / 2 + 1; | 2627 | len = sizeof (sin6->sin6_addr) / 2 + 1; |
| 2628 | hostport = XINT (p->contents[--len]); | 2628 | hostport = XINT (p->contents[--len]); |
| 2629 | sin6->sin6_port = htons (hostport); | 2629 | sin6->sin6_port = htons (hostport); |
| @@ -2645,7 +2645,7 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int | |||
| 2645 | #ifdef HAVE_LOCAL_SOCKETS | 2645 | #ifdef HAVE_LOCAL_SOCKETS |
| 2646 | if (family == AF_LOCAL) | 2646 | if (family == AF_LOCAL) |
| 2647 | { | 2647 | { |
| 2648 | struct sockaddr_un *sockun = (struct sockaddr_un *) sa; | 2648 | DECLARE_POINTER_ALIAS (sockun, struct sockaddr_un, sa); |
| 2649 | cp = SDATA (address); | 2649 | cp = SDATA (address); |
| 2650 | for (i = 0; i < sizeof (sockun->sun_path) && *cp; i++) | 2650 | for (i = 0; i < sizeof (sockun->sun_path) && *cp; i++) |
| 2651 | sockun->sun_path[i] = *cp++; | 2651 | sockun->sun_path[i] = *cp++; |
| @@ -3436,13 +3436,15 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos, | |||
| 3436 | == offsetof (struct sockaddr_in6, sin6_port)) | 3436 | == offsetof (struct sockaddr_in6, sin6_port)) |
| 3437 | && sizeof (sa1.sin_port) == sizeof (sa6.sin6_port)); | 3437 | && sizeof (sa1.sin_port) == sizeof (sa6.sin6_port)); |
| 3438 | #endif | 3438 | #endif |
| 3439 | if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0) | 3439 | DECLARE_POINTER_ALIAS (psa1, struct sockaddr, &sa1); |
| 3440 | if (getsockname (s, psa1, &len1) == 0) | ||
| 3440 | { | 3441 | { |
| 3441 | Lisp_Object service = make_number (ntohs (sa1.sin_port)); | 3442 | Lisp_Object service = make_number (ntohs (sa1.sin_port)); |
| 3442 | contact = Fplist_put (contact, QCservice, service); | 3443 | contact = Fplist_put (contact, QCservice, service); |
| 3443 | /* Save the port number so that we can stash it in | 3444 | /* Save the port number so that we can stash it in |
| 3444 | the process object later. */ | 3445 | the process object later. */ |
| 3445 | ((struct sockaddr_in *) sa)->sin_port = sa1.sin_port; | 3446 | DECLARE_POINTER_ALIAS (psa, struct sockaddr_in, sa); |
| 3447 | psa->sin_port = sa1.sin_port; | ||
| 3446 | } | 3448 | } |
| 3447 | } | 3449 | } |
| 3448 | #endif | 3450 | #endif |
| @@ -3550,9 +3552,10 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos, | |||
| 3550 | { | 3552 | { |
| 3551 | struct sockaddr_storage sa1; | 3553 | struct sockaddr_storage sa1; |
| 3552 | socklen_t len1 = sizeof (sa1); | 3554 | socklen_t len1 = sizeof (sa1); |
| 3553 | if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0) | 3555 | DECLARE_POINTER_ALIAS (psa1, struct sockaddr, &sa1); |
| 3556 | if (getsockname (s, psa1, &len1) == 0) | ||
| 3554 | contact = Fplist_put (contact, QClocal, | 3557 | contact = Fplist_put (contact, QClocal, |
| 3555 | conv_sockaddr_to_lisp ((struct sockaddr *)&sa1, len1)); | 3558 | conv_sockaddr_to_lisp (psa1, len1)); |
| 3556 | } | 3559 | } |
| 3557 | #endif | 3560 | #endif |
| 3558 | } | 3561 | } |
| @@ -4401,7 +4404,7 @@ network_interface_info (Lisp_Object ifname) | |||
| 4401 | 4404 | ||
| 4402 | for (it = ifap; it != NULL; it = it->ifa_next) | 4405 | for (it = ifap; it != NULL; it = it->ifa_next) |
| 4403 | { | 4406 | { |
| 4404 | struct sockaddr_dl *sdl = (struct sockaddr_dl *) it->ifa_addr; | 4407 | DECLARE_POINTER_ALIAS (sdl, struct sockaddr_dl, it->ifa_addr); |
| 4405 | unsigned char linkaddr[6]; | 4408 | unsigned char linkaddr[6]; |
| 4406 | int n; | 4409 | int n; |
| 4407 | 4410 | ||
| @@ -4722,7 +4725,7 @@ server_accept_connection (Lisp_Object server, int channel) | |||
| 4722 | { | 4725 | { |
| 4723 | args[nargs++] = procname_format_in6; | 4726 | args[nargs++] = procname_format_in6; |
| 4724 | nargs++; | 4727 | nargs++; |
| 4725 | uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr; | 4728 | DECLARE_POINTER_ALIAS (ip6, uint16_t, &saddr.in6.sin6_addr); |
| 4726 | service = make_number (ntohs (saddr.in.sin_port)); | 4729 | service = make_number (ntohs (saddr.in.sin_port)); |
| 4727 | for (int i = 0; i < 8; i++) | 4730 | for (int i = 0; i < 8; i++) |
| 4728 | args[nargs++] = make_number (ip6[i]); | 4731 | args[nargs++] = make_number (ip6[i]); |