Print this page
8429 getallifaddrs dereferences invalid pointer causing SIGSEGV
Reviewed by: Sebastian Wiedenroth <sw@core.io>
Reviewed by: Yuri Pankov <yuripv@gmx.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libsocket/inet/getifaddrs.c
+++ new/usr/src/lib/libsocket/inet/getifaddrs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2017 RackTop Systems.
24 25 */
25 26
26 27 #include <netdb.h>
27 28 #include <nss_dbdefs.h>
28 29 #include <netinet/in.h>
29 30 #include <sys/socket.h>
30 31 #include <string.h>
31 32 #include <stdio.h>
32 33 #include <sys/sockio.h>
33 34 #include <sys/types.h>
34 35 #include <stdlib.h>
35 36 #include <net/if.h>
36 37 #include <ifaddrs.h>
37 38 #include <libsocket_priv.h>
38 39
39 40 /*
40 41 * Create a linked list of `struct ifaddrs' structures, one for each
41 42 * address that is UP. If successful, store the list in *ifap and
42 43 * return 0. On errors, return -1 and set `errno'.
43 44 *
44 45 * The storage returned in *ifap is allocated dynamically and can
45 46 * only be properly freed by passing it to `freeifaddrs'.
46 47 */
47 48 int
48 49 getifaddrs(struct ifaddrs **ifap)
49 50 {
50 51 int err;
51 52 char *cp;
52 53 struct ifaddrs *curr;
53 54
54 55 if (ifap == NULL) {
55 56 errno = EINVAL;
56 57 return (-1);
57 58 }
58 59 *ifap = NULL;
59 60 err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED);
60 61 if (err == 0) {
61 62 for (curr = *ifap; curr != NULL; curr = curr->ifa_next) {
62 63 if ((cp = strchr(curr->ifa_name, ':')) != NULL)
63 64 *cp = '\0';
64 65 }
65 66 }
66 67 return (err);
67 68 }
68 69
69 70 void
70 71 freeifaddrs(struct ifaddrs *ifa)
71 72 {
72 73 struct ifaddrs *curr;
73 74
74 75 while (ifa != NULL) {
75 76 curr = ifa;
76 77 ifa = ifa->ifa_next;
77 78 free(curr->ifa_name);
78 79 free(curr->ifa_addr);
79 80 free(curr->ifa_netmask);
80 81 free(curr->ifa_dstaddr);
81 82 free(curr);
82 83 }
83 84 }
84 85
85 86 /*
86 87 * Returns all addresses configured on the system. If flags contain
87 88 * LIFC_ENABLED, only the addresses that are UP are returned.
88 89 * Address list that is returned by this function must be freed
89 90 * using freeifaddrs().
90 91 */
91 92 int
92 93 getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags)
93 94 {
94 95 struct lifreq *buf = NULL;
↓ open down ↓ |
61 lines elided |
↑ open up ↑ |
95 96 struct lifreq *lifrp;
96 97 struct lifreq lifrl;
97 98 int ret;
98 99 int s, n, numifs;
99 100 struct ifaddrs *curr, *prev;
100 101 sa_family_t lifr_af;
101 102 int sock4;
102 103 int sock6;
103 104 int err;
104 105
106 + /*
107 + * Initialize ifap to NULL so we can safely call freeifaddrs
108 + * on it in case of error.
109 + */
110 + if (ifap == NULL)
111 + return (EINVAL);
112 + *ifap = NULL;
113 +
105 114 if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
106 115 return (-1);
107 116 if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
108 117 err = errno;
109 118 close(sock4);
110 119 errno = err;
111 120 return (-1);
112 121 }
113 122
114 123 retry:
115 124 /* Get all interfaces from SIOCGLIFCONF */
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
116 125 ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED));
117 126 if (ret != 0)
118 127 goto fail;
119 128
120 129 /*
121 130 * Loop through the interfaces obtained from SIOCGLIFCOMF
122 131 * and retrieve the addresses, netmask and flags.
123 132 */
124 133 prev = NULL;
125 134 lifrp = buf;
126 - *ifap = NULL;
127 135 for (n = 0; n < numifs; n++, lifrp++) {
128 136
129 137 /* Prepare for the ioctl call */
130 138 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
131 139 sizeof (lifrl.lifr_name));
132 140 lifr_af = lifrp->lifr_addr.ss_family;
133 141 if (af != AF_UNSPEC && lifr_af != af)
134 142 continue;
135 143
136 144 s = (lifr_af == AF_INET ? sock4 : sock6);
137 145
138 146 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
139 147 goto fail;
140 148 if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP))
141 149 continue;
142 150
143 151 /*
144 152 * Allocate the current list node. Each node contains data
145 153 * for one ifaddrs structure.
146 154 */
147 155 curr = calloc(1, sizeof (struct ifaddrs));
148 156 if (curr == NULL)
149 157 goto fail;
150 158
151 159 if (prev != NULL) {
152 160 prev->ifa_next = curr;
153 161 } else {
154 162 /* First node in the linked list */
155 163 *ifap = curr;
156 164 }
157 165 prev = curr;
158 166
159 167 curr->ifa_flags = lifrl.lifr_flags;
160 168 if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL)
161 169 goto fail;
162 170
163 171 curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
164 172 if (curr->ifa_addr == NULL)
165 173 goto fail;
166 174 (void) memcpy(curr->ifa_addr, &lifrp->lifr_addr,
167 175 sizeof (struct sockaddr_storage));
168 176
169 177 /* Get the netmask */
170 178 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0)
171 179 goto fail;
172 180 curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
173 181 if (curr->ifa_netmask == NULL)
174 182 goto fail;
175 183 (void) memcpy(curr->ifa_netmask, &lifrl.lifr_addr,
176 184 sizeof (struct sockaddr_storage));
177 185
178 186 /* Get the destination for a pt-pt interface */
179 187 if (curr->ifa_flags & IFF_POINTOPOINT) {
180 188 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0)
181 189 goto fail;
182 190 curr->ifa_dstaddr = malloc(
183 191 sizeof (struct sockaddr_storage));
184 192 if (curr->ifa_dstaddr == NULL)
185 193 goto fail;
186 194 (void) memcpy(curr->ifa_dstaddr, &lifrl.lifr_addr,
187 195 sizeof (struct sockaddr_storage));
188 196 } else if (curr->ifa_flags & IFF_BROADCAST) {
189 197 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0)
190 198 goto fail;
191 199 curr->ifa_broadaddr = malloc(
192 200 sizeof (struct sockaddr_storage));
193 201 if (curr->ifa_broadaddr == NULL)
194 202 goto fail;
195 203 (void) memcpy(curr->ifa_broadaddr, &lifrl.lifr_addr,
196 204 sizeof (struct sockaddr_storage));
197 205 }
198 206
199 207 }
200 208 free(buf);
201 209 close(sock4);
202 210 close(sock6);
203 211 return (0);
204 212 fail:
205 213 err = errno;
206 214 free(buf);
207 215 freeifaddrs(*ifap);
208 216 *ifap = NULL;
209 217 if (err == ENXIO)
210 218 goto retry;
211 219 close(sock4);
212 220 close(sock6);
213 221 errno = err;
214 222 return (-1);
215 223 }
216 224
217 225 /*
218 226 * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
219 227 */
220 228 int
221 229 getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
222 230 int64_t lifc_flags)
223 231 {
224 232 struct lifnum lifn;
225 233 struct lifconf lifc;
226 234 size_t bufsize;
227 235 char *tmp;
228 236 caddr_t *buf = (caddr_t *)lifr;
229 237
230 238 lifn.lifn_family = af;
231 239 lifn.lifn_flags = lifc_flags;
232 240
233 241 *buf = NULL;
234 242 retry:
235 243 if (ioctl(s, SIOCGLIFNUM, &lifn) < 0)
236 244 goto fail;
237 245
238 246 /*
239 247 * When calculating the buffer size needed, add a small number
240 248 * of interfaces to those we counted. We do this to capture
241 249 * the interface status of potential interfaces which may have
242 250 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
243 251 */
244 252 bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq);
245 253
246 254 if ((tmp = realloc(*buf, bufsize)) == NULL)
247 255 goto fail;
248 256
249 257 *buf = tmp;
250 258 lifc.lifc_family = af;
251 259 lifc.lifc_flags = lifc_flags;
252 260 lifc.lifc_len = bufsize;
253 261 lifc.lifc_buf = *buf;
254 262 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
255 263 goto fail;
256 264
257 265 *numifs = lifc.lifc_len / sizeof (struct lifreq);
258 266 if (*numifs >= (lifn.lifn_count + 4)) {
259 267 /*
260 268 * If every entry was filled, there are probably
261 269 * more interfaces than (lifn.lifn_count + 4).
262 270 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
263 271 * get all the interfaces.
264 272 */
265 273 goto retry;
266 274 }
267 275 return (0);
268 276 fail:
269 277 free(*buf);
270 278 *buf = NULL;
271 279 return (-1);
272 280 }
↓ open down ↓ |
136 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX