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