diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-26 16:52:25 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-26 16:52:25 +0100 |
commit | 1361aa2e2d80cb144b4158722de3c913855e6002 (patch) | |
tree | 6fddc0669c8032c4381ba6ba1a32cc407670d905 | |
parent | 57be1eefab8494efd96bcec0f54a84cef3f61e95 (diff) | |
download | busybox-w32-1361aa2e2d80cb144b4158722de3c913855e6002.tar.gz busybox-w32-1361aa2e2d80cb144b4158722de3c913855e6002.tar.bz2 busybox-w32-1361aa2e2d80cb144b4158722de3c913855e6002.zip |
udp_io: fix two more potential cases of unaligned accesses. 0 code size changes.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libbb/udp_io.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/libbb/udp_io.c b/libbb/udp_io.c index b31f28416..d9375eac2 100644 --- a/libbb/udp_io.c +++ b/libbb/udp_io.c | |||
@@ -6,7 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPL version 2, see file LICENSE in this tarball for details. | 7 | * Licensed under GPL version 2, see file LICENSE in this tarball for details. |
8 | */ | 8 | */ |
9 | |||
10 | #include "libbb.h" | 9 | #include "libbb.h" |
11 | 10 | ||
12 | /* | 11 | /* |
@@ -32,22 +31,23 @@ send_to_from(int fd, void *buf, size_t len, int flags, | |||
32 | socklen_t tolen) | 31 | socklen_t tolen) |
33 | { | 32 | { |
34 | #ifndef IP_PKTINFO | 33 | #ifndef IP_PKTINFO |
34 | (void)from; /* suppress "unused from" warning */ | ||
35 | return sendto(fd, buf, len, flags, to, tolen); | 35 | return sendto(fd, buf, len, flags, to, tolen); |
36 | #else | 36 | #else |
37 | struct iovec iov[1]; | 37 | struct iovec iov[1]; |
38 | struct msghdr msg; | 38 | struct msghdr msg; |
39 | union { | 39 | union { |
40 | char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; | 40 | char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; |
41 | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) | 41 | # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
42 | char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; | 42 | char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
43 | #endif | 43 | # endif |
44 | } u; | 44 | } u; |
45 | struct cmsghdr* cmsgptr; | 45 | struct cmsghdr* cmsgptr; |
46 | 46 | ||
47 | if (from->sa_family != AF_INET | 47 | if (from->sa_family != AF_INET |
48 | #if ENABLE_FEATURE_IPV6 | 48 | # if ENABLE_FEATURE_IPV6 |
49 | && from->sa_family != AF_INET6 | 49 | && from->sa_family != AF_INET6 |
50 | #endif | 50 | # endif |
51 | ) { | 51 | ) { |
52 | /* ANY local address */ | 52 | /* ANY local address */ |
53 | return sendto(fd, buf, len, flags, to, tolen); | 53 | return sendto(fd, buf, len, flags, to, tolen); |
@@ -76,20 +76,26 @@ send_to_from(int fd, void *buf, size_t len, int flags, | |||
76 | cmsgptr->cmsg_type = IP_PKTINFO; | 76 | cmsgptr->cmsg_type = IP_PKTINFO; |
77 | cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); | 77 | cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); |
78 | pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr)); | 78 | pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr)); |
79 | /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */ | 79 | /*pktptr->ipi_ifindex = 0; -- already done by memset(u...) */ |
80 | /* In general, CMSG_DATA() can be unaligned, but in this case | ||
81 | * we know for sure it is sufficiently aligned: | ||
82 | * CMSG_FIRSTHDR simply returns &u above, | ||
83 | * and CMSG_DATA returns &u + size_t + int + int. | ||
84 | * Thus direct assignment is ok: | ||
85 | */ | ||
80 | pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; | 86 | pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; |
81 | } | 87 | } |
82 | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) | 88 | # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
83 | else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { | 89 | else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { |
84 | struct in6_pktinfo *pktptr; | 90 | struct in6_pktinfo *pktptr; |
85 | cmsgptr->cmsg_level = IPPROTO_IPV6; | 91 | cmsgptr->cmsg_level = IPPROTO_IPV6; |
86 | cmsgptr->cmsg_type = IPV6_PKTINFO; | 92 | cmsgptr->cmsg_type = IPV6_PKTINFO; |
87 | cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); | 93 | cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); |
88 | pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr)); | 94 | pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr)); |
89 | /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */ | 95 | /* pktptr->ipi6_ifindex = 0; -- already done by memset(u...) */ |
90 | pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr; | 96 | pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr; |
91 | } | 97 | } |
92 | #endif | 98 | # endif |
93 | msg.msg_controllen = cmsgptr->cmsg_len; | 99 | msg.msg_controllen = cmsgptr->cmsg_len; |
94 | 100 | ||
95 | return sendmsg(fd, &msg, flags); | 101 | return sendmsg(fd, &msg, flags); |
@@ -106,15 +112,16 @@ recv_from_to(int fd, void *buf, size_t len, int flags, | |||
106 | socklen_t sa_size) | 112 | socklen_t sa_size) |
107 | { | 113 | { |
108 | #ifndef IP_PKTINFO | 114 | #ifndef IP_PKTINFO |
115 | (void)to; /* suppress "unused to" warning */ | ||
109 | return recvfrom(fd, buf, len, flags, from, &sa_size); | 116 | return recvfrom(fd, buf, len, flags, from, &sa_size); |
110 | #else | 117 | #else |
111 | /* man recvmsg and man cmsg is needed to make sense of code below */ | 118 | /* man recvmsg and man cmsg is needed to make sense of code below */ |
112 | struct iovec iov[1]; | 119 | struct iovec iov[1]; |
113 | union { | 120 | union { |
114 | char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; | 121 | char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; |
115 | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) | 122 | # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
116 | char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; | 123 | char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
117 | #endif | 124 | # endif |
118 | } u; | 125 | } u; |
119 | struct cmsghdr *cmsgptr; | 126 | struct cmsghdr *cmsgptr; |
120 | struct msghdr msg; | 127 | struct msghdr msg; |
@@ -135,6 +142,8 @@ recv_from_to(int fd, void *buf, size_t len, int flags, | |||
135 | if (recv_length < 0) | 142 | if (recv_length < 0) |
136 | return recv_length; | 143 | return recv_length; |
137 | 144 | ||
145 | # define to4 ((struct sockaddr_in*)to) | ||
146 | # define to6 ((struct sockaddr_in6*)to) | ||
138 | /* Here we try to retrieve destination IP and memorize it */ | 147 | /* Here we try to retrieve destination IP and memorize it */ |
139 | for (cmsgptr = CMSG_FIRSTHDR(&msg); | 148 | for (cmsgptr = CMSG_FIRSTHDR(&msg); |
140 | cmsgptr != NULL; | 149 | cmsgptr != NULL; |
@@ -143,25 +152,27 @@ recv_from_to(int fd, void *buf, size_t len, int flags, | |||
143 | if (cmsgptr->cmsg_level == IPPROTO_IP | 152 | if (cmsgptr->cmsg_level == IPPROTO_IP |
144 | && cmsgptr->cmsg_type == IP_PKTINFO | 153 | && cmsgptr->cmsg_type == IP_PKTINFO |
145 | ) { | 154 | ) { |
146 | #define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) ) | 155 | # define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) ) |
147 | to->sa_family = AF_INET; | 156 | to->sa_family = AF_INET; |
148 | ((struct sockaddr_in*)to)->sin_addr = pktinfo(cmsgptr)->ipi_addr; | 157 | /*to4->sin_addr = pktinfo(cmsgptr)->ipi_addr; - may be unaligned */ |
149 | /* ((struct sockaddr_in*)to)->sin_port = 123; */ | 158 | memcpy(&to4->sin_addr, &pktinfo(cmsgptr)->ipi_addr, sizeof(to4->sin_addr)); |
150 | #undef pktinfo | 159 | /*to4->sin_port = 123; - this data is not supplied by kernel */ |
160 | # undef pktinfo | ||
151 | break; | 161 | break; |
152 | } | 162 | } |
153 | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) | 163 | # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
154 | if (cmsgptr->cmsg_level == IPPROTO_IPV6 | 164 | if (cmsgptr->cmsg_level == IPPROTO_IPV6 |
155 | && cmsgptr->cmsg_type == IPV6_PKTINFO | 165 | && cmsgptr->cmsg_type == IPV6_PKTINFO |
156 | ) { | 166 | ) { |
157 | #define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) ) | 167 | # define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) ) |
158 | to->sa_family = AF_INET6; | 168 | to->sa_family = AF_INET6; |
159 | ((struct sockaddr_in6*)to)->sin6_addr = pktinfo(cmsgptr)->ipi6_addr; | 169 | /*to6->sin6_addr = pktinfo(cmsgptr)->ipi6_addr; - may be unaligned */ |
160 | /* ((struct sockaddr_in6*)to)->sin6_port = 123; */ | 170 | memcpy(&to6->sin6_addr, &pktinfo(cmsgptr)->ipi6_addr, sizeof(to6->sin6_addr)); |
161 | #undef pktinfo | 171 | /*to6->sin6_port = 123; */ |
172 | # undef pktinfo | ||
162 | break; | 173 | break; |
163 | } | 174 | } |
164 | #endif | 175 | # endif |
165 | } | 176 | } |
166 | return recv_length; | 177 | return recv_length; |
167 | #endif | 178 | #endif |