rev |
line source |
shann@12476
|
1 From 4ab2ab03d4351914ee53248dc5aef4a8c88ff8b9 Mon Sep 17 00:00:00 2001
|
shann@12476
|
2 From: Florian Weimer <fweimer@redhat.com>
|
shann@12476
|
3 Date: Fri, 29 Apr 2016 10:35:34 +0200
|
shann@12476
|
4 Subject: [PATCH] CVE-2016-3706: getaddrinfo: stack overflow in hostent
|
shann@12476
|
5 conversion [BZ #20010]
|
shann@12476
|
6
|
shann@12476
|
7 When converting a struct hostent response to struct gaih_addrtuple, the
|
shann@12476
|
8 gethosts macro (which is called from gaih_inet) used alloca, without
|
shann@12476
|
9 malloc fallback for large responses. This commit changes this code to
|
shann@12476
|
10 use calloc unconditionally.
|
shann@12476
|
11
|
shann@12476
|
12 This commit also consolidated a second hostent-to-gaih_addrtuple
|
shann@12476
|
13 conversion loop (in gaih_inet) to use the new conversion function.
|
shann@12476
|
14
|
shann@12476
|
15 diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
|
shann@12476
|
16 index 1ef3f20..fed2d3b 100644
|
shann@12476
|
17 --- a/sysdeps/posix/getaddrinfo.c
|
shann@12476
|
18 +++ b/sysdeps/posix/getaddrinfo.c
|
shann@12476
|
19 @@ -168,9 +168,58 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
|
shann@12476
|
20 return 0;
|
shann@12476
|
21 }
|
shann@12476
|
22
|
shann@12476
|
23 +/* Convert struct hostent to a list of struct gaih_addrtuple objects.
|
shann@12476
|
24 + h_name is not copied, and the struct hostent object must not be
|
shann@12476
|
25 + deallocated prematurely. *RESULT must be NULL or a pointer to an
|
shann@12476
|
26 + object allocated using malloc, which is freed. */
|
shann@12476
|
27 +static bool
|
shann@12476
|
28 +convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
shann@12476
|
29 + int family,
|
shann@12476
|
30 + struct hostent *h,
|
shann@12476
|
31 + struct gaih_addrtuple **result)
|
shann@12476
|
32 +{
|
shann@12476
|
33 + free (*result);
|
shann@12476
|
34 + *result = NULL;
|
shann@12476
|
35 +
|
shann@12476
|
36 + /* Count the number of addresses in h->h_addr_list. */
|
shann@12476
|
37 + size_t count = 0;
|
shann@12476
|
38 + for (char **p = h->h_addr_list; *p != NULL; ++p)
|
shann@12476
|
39 + ++count;
|
shann@12476
|
40 +
|
shann@12476
|
41 + /* Report no data if no addresses are available, or if the incoming
|
shann@12476
|
42 + address size is larger than what we can store. */
|
shann@12476
|
43 + if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
|
shann@12476
|
44 + return true;
|
shann@12476
|
45 +
|
shann@12476
|
46 + struct gaih_addrtuple *array = calloc (count, sizeof (*array));
|
shann@12476
|
47 + if (array == NULL)
|
shann@12476
|
48 + return false;
|
shann@12476
|
49 +
|
shann@12476
|
50 + for (size_t i = 0; i < count; ++i)
|
shann@12476
|
51 + {
|
shann@12476
|
52 + if (family == AF_INET && req->ai_family == AF_INET6)
|
shann@12476
|
53 + {
|
shann@12476
|
54 + /* Perform address mapping. */
|
shann@12476
|
55 + array[i].family = AF_INET6;
|
shann@12476
|
56 + memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t));
|
shann@12476
|
57 + array[i].addr[2] = htonl (0xffff);
|
shann@12476
|
58 + }
|
shann@12476
|
59 + else
|
shann@12476
|
60 + {
|
shann@12476
|
61 + array[i].family = family;
|
shann@12476
|
62 + memcpy (array[i].addr, h->h_addr_list[i], h->h_length);
|
shann@12476
|
63 + }
|
shann@12476
|
64 + array[i].next = array + i + 1;
|
shann@12476
|
65 + }
|
shann@12476
|
66 + array[0].name = h->h_name;
|
shann@12476
|
67 + array[count - 1].next = NULL;
|
shann@12476
|
68 +
|
shann@12476
|
69 + *result = array;
|
shann@12476
|
70 + return true;
|
shann@12476
|
71 +}
|
shann@12476
|
72 +
|
shann@12476
|
73 #define gethosts(_family, _type) \
|
shann@12476
|
74 { \
|
shann@12476
|
75 - int i; \
|
shann@12476
|
76 int herrno; \
|
shann@12476
|
77 struct hostent th; \
|
shann@12476
|
78 struct hostent *h; \
|
shann@12476
|
79 @@ -219,36 +268,23 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
|
shann@12476
|
80 } \
|
shann@12476
|
81 else if (h != NULL) \
|
shann@12476
|
82 { \
|
shann@12476
|
83 - for (i = 0; h->h_addr_list[i]; i++) \
|
shann@12476
|
84 + /* Make sure that addrmem can be freed. */ \
|
shann@12476
|
85 + if (!malloc_addrmem) \
|
shann@12476
|
86 + addrmem = NULL; \
|
shann@12476
|
87 + if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem)) \
|
shann@12476
|
88 { \
|
shann@12476
|
89 - if (*pat == NULL) \
|
shann@12476
|
90 - { \
|
shann@12476
|
91 - *pat = __alloca (sizeof (struct gaih_addrtuple)); \
|
shann@12476
|
92 - (*pat)->scopeid = 0; \
|
shann@12476
|
93 - } \
|
shann@12476
|
94 - uint32_t *addr = (*pat)->addr; \
|
shann@12476
|
95 - (*pat)->next = NULL; \
|
shann@12476
|
96 - (*pat)->name = i == 0 ? strdupa (h->h_name) : NULL; \
|
shann@12476
|
97 - if (_family == AF_INET && req->ai_family == AF_INET6) \
|
shann@12476
|
98 - { \
|
shann@12476
|
99 - (*pat)->family = AF_INET6; \
|
shann@12476
|
100 - addr[3] = *(uint32_t *) h->h_addr_list[i]; \
|
shann@12476
|
101 - addr[2] = htonl (0xffff); \
|
shann@12476
|
102 - addr[1] = 0; \
|
shann@12476
|
103 - addr[0] = 0; \
|
shann@12476
|
104 - } \
|
shann@12476
|
105 - else \
|
shann@12476
|
106 - { \
|
shann@12476
|
107 - (*pat)->family = _family; \
|
shann@12476
|
108 - memcpy (addr, h->h_addr_list[i], sizeof(_type)); \
|
shann@12476
|
109 - } \
|
shann@12476
|
110 - pat = &((*pat)->next); \
|
shann@12476
|
111 + _res.options |= old_res_options & RES_USE_INET6; \
|
shann@12476
|
112 + result = -EAI_SYSTEM; \
|
shann@12476
|
113 + goto free_and_return; \
|
shann@12476
|
114 } \
|
shann@12476
|
115 + *pat = addrmem; \
|
shann@12476
|
116 + /* The conversion uses malloc unconditionally. */ \
|
shann@12476
|
117 + malloc_addrmem = true; \
|
shann@12476
|
118 \
|
shann@12476
|
119 if (localcanon != NULL && canon == NULL) \
|
shann@12476
|
120 canon = strdupa (localcanon); \
|
shann@12476
|
121 \
|
shann@12476
|
122 - if (_family == AF_INET6 && i > 0) \
|
shann@12476
|
123 + if (_family == AF_INET6 && *pat != NULL) \
|
shann@12476
|
124 got_ipv6 = true; \
|
shann@12476
|
125 } \
|
shann@12476
|
126 }
|
shann@12476
|
127 @@ -612,44 +648,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
shann@12476
|
128 {
|
shann@12476
|
129 if (h != NULL)
|
shann@12476
|
130 {
|
shann@12476
|
131 - int i;
|
shann@12476
|
132 - /* We found data, count the number of addresses. */
|
shann@12476
|
133 - for (i = 0; h->h_addr_list[i]; ++i)
|
shann@12476
|
134 - ;
|
shann@12476
|
135 - if (i > 0 && *pat != NULL)
|
shann@12476
|
136 - --i;
|
shann@12476
|
137 -
|
shann@12476
|
138 - if (__libc_use_alloca (alloca_used
|
shann@12476
|
139 - + i * sizeof (struct gaih_addrtuple)))
|
shann@12476
|
140 - addrmem = alloca_account (i * sizeof (struct gaih_addrtuple),
|
shann@12476
|
141 - alloca_used);
|
shann@12476
|
142 - else
|
shann@12476
|
143 - {
|
shann@12476
|
144 - addrmem = malloc (i
|
shann@12476
|
145 - * sizeof (struct gaih_addrtuple));
|
shann@12476
|
146 - if (addrmem == NULL)
|
shann@12476
|
147 - {
|
shann@12476
|
148 - result = -EAI_MEMORY;
|
shann@12476
|
149 - goto free_and_return;
|
shann@12476
|
150 - }
|
shann@12476
|
151 - malloc_addrmem = true;
|
shann@12476
|
152 - }
|
shann@12476
|
153 -
|
shann@12476
|
154 - /* Now convert it into the list. */
|
shann@12476
|
155 - struct gaih_addrtuple *addrfree = addrmem;
|
shann@12476
|
156 - for (i = 0; h->h_addr_list[i]; ++i)
|
shann@12476
|
157 + /* We found data, convert it. */
|
shann@12476
|
158 + if (!convert_hostent_to_gaih_addrtuple
|
shann@12476
|
159 + (req, AF_INET, h, &addrmem))
|
shann@12476
|
160 {
|
shann@12476
|
161 - if (*pat == NULL)
|
shann@12476
|
162 - {
|
shann@12476
|
163 - *pat = addrfree++;
|
shann@12476
|
164 - (*pat)->scopeid = 0;
|
shann@12476
|
165 - }
|
shann@12476
|
166 - (*pat)->next = NULL;
|
shann@12476
|
167 - (*pat)->family = AF_INET;
|
shann@12476
|
168 - memcpy ((*pat)->addr, h->h_addr_list[i],
|
shann@12476
|
169 - h->h_length);
|
shann@12476
|
170 - pat = &((*pat)->next);
|
shann@12476
|
171 + result = -EAI_MEMORY;
|
shann@12476
|
172 + goto free_and_return;
|
shann@12476
|
173 }
|
shann@12476
|
174 + *pat = addrmem;
|
shann@12476
|
175 + /* The conversion uses malloc unconditionally. */
|
shann@12476
|
176 + malloc_addrmem = true;
|
shann@12476
|
177 }
|
shann@12476
|
178 }
|
shann@12476
|
179 else
|
shann@12476
|
180 --
|
shann@12476
|
181 2.9.3
|
shann@12476
|
182
|