Change-Id: I0f0c6289d284d375224c9c4ed3f5c182a991a48f
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/3456
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,344 @@ |
0 |
+From f6110a8fee2ca36f8e2d2abecf3cba9fa7b8ea7d Mon Sep 17 00:00:00 2001 |
|
1 |
+From: Florian Weimer <fweimer@redhat.com> |
|
2 |
+Date: Mon, 19 Jun 2017 17:09:55 +0200 |
|
3 |
+Subject: [PATCH 1/1] CVE-2017-1000366: Ignore LD_LIBRARY_PATH for AT_SECURE=1 |
|
4 |
+ programs [BZ #21624] |
|
5 |
+ |
|
6 |
+LD_LIBRARY_PATH can only be used to reorder system search paths, which |
|
7 |
+is not useful functionality. |
|
8 |
+ |
|
9 |
+This makes an exploitable unbounded alloca in _dl_init_paths unreachable |
|
10 |
+for AT_SECURE=1 programs. |
|
11 |
+--- |
|
12 |
+ elf/rtld.c | 3 ++- |
|
13 |
+ 1 files changed, 2 insertions(+), 1 deletion(-) |
|
14 |
+ |
|
15 |
+diff --git a/elf/rtld.c b/elf/rtld.c |
|
16 |
+index 2446a87..2269dbe 100644 |
|
17 |
+--- a/elf/rtld.c |
|
18 |
+@@ -2422,7 +2422,8 @@ process_envvars (enum mode *modep) |
|
19 |
+ |
|
20 |
+ case 12: |
|
21 |
+ /* The library search path. */ |
|
22 |
+- if (memcmp (envline, "LIBRARY_PATH", 12) == 0) |
|
23 |
++ if (!__libc_enable_secure |
|
24 |
++ && memcmp (envline, "LIBRARY_PATH", 12) == 0) |
|
25 |
+ { |
|
26 |
+ library_path = &envline[13]; |
|
27 |
+ break; |
|
28 |
+From 6d0ba622891bed9d8394eef1935add53003b12e8 Mon Sep 17 00:00:00 2001 |
|
29 |
+From: Florian Weimer <fweimer@redhat.com> |
|
30 |
+Date: Mon, 19 Jun 2017 22:31:04 +0200 |
|
31 |
+Subject: [PATCH] ld.so: Reject overly long LD_PRELOAD path elements |
|
32 |
+ |
|
33 |
+--- |
|
34 |
+ elf/rtld.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
|
35 |
+ 1 files changed, 73 insertions(+), 16 deletions(-) |
|
36 |
+ |
|
37 |
+diff --git a/elf/rtld.c b/elf/rtld.c |
|
38 |
+index 2269dbe..86ae20c 100644 |
|
39 |
+--- a/elf/rtld.c |
|
40 |
+@@ -99,6 +99,35 @@ uintptr_t __pointer_chk_guard_local |
|
41 |
+ strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) |
|
42 |
+ #endif |
|
43 |
+ |
|
44 |
++/* Length limits for names and paths, to protect the dynamic linker, |
|
45 |
++ particularly when __libc_enable_secure is active. */ |
|
46 |
++#ifdef NAME_MAX |
|
47 |
++# define SECURE_NAME_LIMIT NAME_MAX |
|
48 |
++#else |
|
49 |
++# define SECURE_NAME_LIMIT 255 |
|
50 |
++#endif |
|
51 |
++#ifdef PATH_MAX |
|
52 |
++# define SECURE_PATH_LIMIT PATH_MAX |
|
53 |
++#else |
|
54 |
++# define SECURE_PATH_LIMIT 1024 |
|
55 |
++#endif |
|
56 |
++ |
|
57 |
++/* Check that AT_SECURE=0, or that the passed name does not contain |
|
58 |
++ directories and is not overly long. Reject empty names |
|
59 |
++ unconditionally. */ |
|
60 |
++static bool |
|
61 |
++dso_name_valid_for_suid (const char *p) |
|
62 |
++{ |
|
63 |
++ if (__glibc_unlikely (__libc_enable_secure)) |
|
64 |
++ { |
|
65 |
++ /* Ignore pathnames with directories for AT_SECURE=1 |
|
66 |
++ programs, and also skip overlong names. */ |
|
67 |
++ size_t len = strlen (p); |
|
68 |
++ if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL) |
|
69 |
++ return false; |
|
70 |
++ } |
|
71 |
++ return *p != '\0'; |
|
72 |
++} |
|
73 |
+ |
|
74 |
+ /* List of auditing DSOs. */ |
|
75 |
+ static struct audit_list |
|
76 |
+@@ -718,6 +747,42 @@ static const char *preloadlist attribute_relro; |
|
77 |
+ /* Nonzero if information about versions has to be printed. */ |
|
78 |
+ static int version_info attribute_relro; |
|
79 |
+ |
|
80 |
++/* The LD_PRELOAD environment variable gives list of libraries |
|
81 |
++ separated by white space or colons that are loaded before the |
|
82 |
++ executable's dependencies and prepended to the global scope list. |
|
83 |
++ (If the binary is running setuid all elements containing a '/' are |
|
84 |
++ ignored since it is insecure.) Return the number of preloads |
|
85 |
++ performed. */ |
|
86 |
++unsigned int |
|
87 |
++handle_ld_preload (const char *preloadlist, struct link_map *main_map) |
|
88 |
++{ |
|
89 |
++ unsigned int npreloads = 0; |
|
90 |
++ const char *p = preloadlist; |
|
91 |
++ char fname[SECURE_PATH_LIMIT]; |
|
92 |
++ |
|
93 |
++ while (*p != '\0') |
|
94 |
++ { |
|
95 |
++ /* Split preload list at space/colon. */ |
|
96 |
++ size_t len = strcspn (p, " :"); |
|
97 |
++ if (len > 0 && len < sizeof (fname)) |
|
98 |
++ { |
|
99 |
++ memcpy (fname, p, len); |
|
100 |
++ fname[len] = '\0'; |
|
101 |
++ } |
|
102 |
++ else |
|
103 |
++ fname[0] = '\0'; |
|
104 |
++ |
|
105 |
++ /* Skip over the substring and the following delimiter. */ |
|
106 |
++ p += len; |
|
107 |
++ if (*p != '\0') |
|
108 |
++ ++p; |
|
109 |
++ |
|
110 |
++ if (dso_name_valid_for_suid (fname)) |
|
111 |
++ npreloads += do_preload (fname, main_map, "LD_PRELOAD"); |
|
112 |
++ } |
|
113 |
++ return npreloads; |
|
114 |
++} |
|
115 |
++ |
|
116 |
+ static void |
|
117 |
+ dl_main (const ElfW(Phdr) *phdr, |
|
118 |
+ ElfW(Word) phnum, |
|
119 |
+@@ -1464,23 +1529,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", |
|
120 |
+ |
|
121 |
+ if (__glibc_unlikely (preloadlist != NULL)) |
|
122 |
+ { |
|
123 |
+- /* The LD_PRELOAD environment variable gives list of libraries |
|
124 |
+- separated by white space or colons that are loaded before the |
|
125 |
+- executable's dependencies and prepended to the global scope |
|
126 |
+- list. If the binary is running setuid all elements |
|
127 |
+- containing a '/' are ignored since it is insecure. */ |
|
128 |
+- char *list = strdupa (preloadlist); |
|
129 |
+- char *p; |
|
130 |
+- |
|
131 |
+ HP_TIMING_NOW (start); |
|
132 |
+- |
|
133 |
+- /* Prevent optimizing strsep. Speed is not important here. */ |
|
134 |
+- while ((p = (strsep) (&list, " :")) != NULL) |
|
135 |
+- if (p[0] != '\0' |
|
136 |
+- && (__builtin_expect (! __libc_enable_secure, 1) |
|
137 |
+- || strchr (p, '/') == NULL)) |
|
138 |
+- npreloads += do_preload (p, main_map, "LD_PRELOAD"); |
|
139 |
+- |
|
140 |
++ npreloads += handle_ld_preload (preloadlist, main_map); |
|
141 |
+ HP_TIMING_NOW (stop); |
|
142 |
+ HP_TIMING_DIFF (diff, start, stop); |
|
143 |
+ HP_TIMING_ACCUM_NT (load_time, diff); |
|
144 |
+From 81b82fb966ffbd94353f793ad17116c6088dedd9 Mon Sep 17 00:00:00 2001 |
|
145 |
+From: Florian Weimer <fweimer@redhat.com> |
|
146 |
+Date: Mon, 19 Jun 2017 22:32:12 +0200 |
|
147 |
+Subject: [PATCH] ld.so: Reject overly long LD_AUDIT path elements |
|
148 |
+ |
|
149 |
+Also only process the last LD_AUDIT entry. |
|
150 |
+--- |
|
151 |
+ elf/rtld.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
|
152 |
+ 1 files changed, 106 insertions(+), 15 deletions(-) |
|
153 |
+ |
|
154 |
+diff --git a/elf/rtld.c b/elf/rtld.c |
|
155 |
+index 86ae20c..65647fb 100644 |
|
156 |
+--- a/elf/rtld.c |
|
157 |
+@@ -129,13 +129,91 @@ dso_name_valid_for_suid (const char *p) |
|
158 |
+ return *p != '\0'; |
|
159 |
+ } |
|
160 |
+ |
|
161 |
+-/* List of auditing DSOs. */ |
|
162 |
++/* LD_AUDIT variable contents. Must be processed before the |
|
163 |
++ audit_list below. */ |
|
164 |
++const char *audit_list_string; |
|
165 |
++ |
|
166 |
++/* Cyclic list of auditing DSOs. audit_list->next is the first |
|
167 |
++ element. */ |
|
168 |
+ static struct audit_list |
|
169 |
+ { |
|
170 |
+ const char *name; |
|
171 |
+ struct audit_list *next; |
|
172 |
+ } *audit_list; |
|
173 |
+ |
|
174 |
++/* Iterator for audit_list_string followed by audit_list. */ |
|
175 |
++struct audit_list_iter |
|
176 |
++{ |
|
177 |
++ /* Tail of audit_list_string still needing processing, or NULL. */ |
|
178 |
++ const char *audit_list_tail; |
|
179 |
++ |
|
180 |
++ /* The list element returned in the previous iteration. NULL before |
|
181 |
++ the first element. */ |
|
182 |
++ struct audit_list *previous; |
|
183 |
++ |
|
184 |
++ /* Scratch buffer for returning a name which is part of |
|
185 |
++ audit_list_string. */ |
|
186 |
++ char fname[SECURE_NAME_LIMIT]; |
|
187 |
++}; |
|
188 |
++ |
|
189 |
++/* Initialize an audit list iterator. */ |
|
190 |
++static void |
|
191 |
++audit_list_iter_init (struct audit_list_iter *iter) |
|
192 |
++{ |
|
193 |
++ iter->audit_list_tail = audit_list_string; |
|
194 |
++ iter->previous = NULL; |
|
195 |
++} |
|
196 |
++ |
|
197 |
++/* Iterate through both audit_list_string and audit_list. */ |
|
198 |
++static const char * |
|
199 |
++audit_list_iter_next (struct audit_list_iter *iter) |
|
200 |
++{ |
|
201 |
++ if (iter->audit_list_tail != NULL) |
|
202 |
++ { |
|
203 |
++ /* First iterate over audit_list_string. */ |
|
204 |
++ while (*iter->audit_list_tail != '\0') |
|
205 |
++ { |
|
206 |
++ /* Split audit list at colon. */ |
|
207 |
++ size_t len = strcspn (iter->audit_list_tail, ":"); |
|
208 |
++ if (len > 0 && len < sizeof (iter->fname)) |
|
209 |
++ { |
|
210 |
++ memcpy (iter->fname, iter->audit_list_tail, len); |
|
211 |
++ iter->fname[len] = '\0'; |
|
212 |
++ } |
|
213 |
++ else |
|
214 |
++ /* Do not return this name to the caller. */ |
|
215 |
++ iter->fname[0] = '\0'; |
|
216 |
++ |
|
217 |
++ /* Skip over the substring and the following delimiter. */ |
|
218 |
++ iter->audit_list_tail += len; |
|
219 |
++ if (*iter->audit_list_tail == ':') |
|
220 |
++ ++iter->audit_list_tail; |
|
221 |
++ |
|
222 |
++ /* If the name is valid, return it. */ |
|
223 |
++ if (dso_name_valid_for_suid (iter->fname)) |
|
224 |
++ return iter->fname; |
|
225 |
++ /* Otherwise, wrap around and try the next name. */ |
|
226 |
++ } |
|
227 |
++ /* Fall through to the procesing of audit_list. */ |
|
228 |
++ } |
|
229 |
++ |
|
230 |
++ if (iter->previous == NULL) |
|
231 |
++ { |
|
232 |
++ if (audit_list == NULL) |
|
233 |
++ /* No pre-parsed audit list. */ |
|
234 |
++ return NULL; |
|
235 |
++ /* Start of audit list. The first list element is at |
|
236 |
++ audit_list->next (cyclic list). */ |
|
237 |
++ iter->previous = audit_list->next; |
|
238 |
++ return iter->previous->name; |
|
239 |
++ } |
|
240 |
++ if (iter->previous == audit_list) |
|
241 |
++ /* Cyclic list wrap-around. */ |
|
242 |
++ return NULL; |
|
243 |
++ iter->previous = iter->previous->next; |
|
244 |
++ return iter->previous->name; |
|
245 |
++} |
|
246 |
++ |
|
247 |
+ #ifndef HAVE_INLINED_SYSCALLS |
|
248 |
+ /* Set nonzero during loading and initialization of executable and |
|
249 |
+ libraries, cleared before the executable's entry point runs. This |
|
250 |
+@@ -1305,11 +1383,13 @@ of this helper program; chances are you did not intend to run this program.\n\ |
|
251 |
+ GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); |
|
252 |
+ |
|
253 |
+ /* If we have auditing DSOs to load, do it now. */ |
|
254 |
+- if (__glibc_unlikely (audit_list != NULL)) |
|
255 |
++ bool need_security_init = true; |
|
256 |
++ if (__glibc_unlikely (audit_list != NULL) |
|
257 |
++ || __glibc_unlikely (audit_list_string != NULL)) |
|
258 |
+ { |
|
259 |
+- /* Iterate over all entries in the list. The order is important. */ |
|
260 |
+ struct audit_ifaces *last_audit = NULL; |
|
261 |
+- struct audit_list *al = audit_list->next; |
|
262 |
++ struct audit_list_iter al_iter; |
|
263 |
++ audit_list_iter_init (&al_iter); |
|
264 |
+ |
|
265 |
+ /* Since we start using the auditing DSOs right away we need to |
|
266 |
+ initialize the data structures now. */ |
|
267 |
+@@ -1320,9 +1400,14 @@ of this helper program; chances are you did not intend to run this program.\n\ |
|
268 |
+ use different values (especially the pointer guard) and will |
|
269 |
+ fail later on. */ |
|
270 |
+ security_init (); |
|
271 |
++ need_security_init = false; |
|
272 |
+ |
|
273 |
+- do |
|
274 |
++ while (true) |
|
275 |
+ { |
|
276 |
++ const char *name = audit_list_iter_next (&al_iter); |
|
277 |
++ if (name == NULL) |
|
278 |
++ break; |
|
279 |
++ |
|
280 |
+ int tls_idx = GL(dl_tls_max_dtv_idx); |
|
281 |
+ |
|
282 |
+ /* Now it is time to determine the layout of the static TLS |
|
283 |
+@@ -1331,7 +1416,7 @@ of this helper program; chances are you did not intend to run this program.\n\ |
|
284 |
+ no DF_STATIC_TLS bit is set. The reason is that we know |
|
285 |
+ glibc will use the static model. */ |
|
286 |
+ struct dlmopen_args dlmargs; |
|
287 |
+- dlmargs.fname = al->name; |
|
288 |
++ dlmargs.fname = name; |
|
289 |
+ dlmargs.map = NULL; |
|
290 |
+ |
|
291 |
+ const char *objname; |
|
292 |
+@@ -1344,7 +1429,7 @@ of this helper program; chances are you did not intend to run this program.\n\ |
|
293 |
+ not_loaded: |
|
294 |
+ _dl_error_printf ("\ |
|
295 |
+ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", |
|
296 |
+- al->name, err_str); |
|
297 |
++ name, err_str); |
|
298 |
+ if (malloced) |
|
299 |
+ free ((char *) err_str); |
|
300 |
+ } |
|
301 |
+@@ -1448,10 +1533,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", |
|
302 |
+ goto not_loaded; |
|
303 |
+ } |
|
304 |
+ } |
|
305 |
+- |
|
306 |
+- al = al->next; |
|
307 |
+ } |
|
308 |
+- while (al != audit_list->next); |
|
309 |
+ |
|
310 |
+ /* If we have any auditing modules, announce that we already |
|
311 |
+ have two objects loaded. */ |
|
312 |
+@@ -1715,7 +1797,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", |
|
313 |
+ if (tcbp == NULL) |
|
314 |
+ tcbp = init_tls (); |
|
315 |
+ |
|
316 |
+- if (__glibc_likely (audit_list == NULL)) |
|
317 |
++ if (__glibc_likely (need_security_init)) |
|
318 |
+ /* Initialize security features. But only if we have not done it |
|
319 |
+ earlier. */ |
|
320 |
+ security_init (); |
|
321 |
+@@ -2346,9 +2428,7 @@ process_dl_audit (char *str) |
|
322 |
+ char *p; |
|
323 |
+ |
|
324 |
+ while ((p = (strsep) (&str, ":")) != NULL) |
|
325 |
+- if (p[0] != '\0' |
|
326 |
+- && (__builtin_expect (! __libc_enable_secure, 1) |
|
327 |
+- || strchr (p, '/') == NULL)) |
|
328 |
++ if (dso_name_valid_for_suid (p)) |
|
329 |
+ { |
|
330 |
+ /* This is using the local malloc, not the system malloc. The |
|
331 |
+ memory can never be freed. */ |
|
332 |
+@@ -2412,7 +2492,7 @@ process_envvars (enum mode *modep) |
|
333 |
+ break; |
|
334 |
+ } |
|
335 |
+ if (memcmp (envline, "AUDIT", 5) == 0) |
|
336 |
+- process_dl_audit (&envline[6]); |
|
337 |
++ audit_list_string = &envline[6]; |
|
338 |
+ break; |
|
339 |
+ |
|
340 |
+ case 7: |
... | ... |
@@ -4,7 +4,7 @@ |
4 | 4 |
Summary: Main C library |
5 | 5 |
Name: glibc |
6 | 6 |
Version: 2.25 |
7 |
-Release: 3%{?dist} |
|
7 |
+Release: 4%{?dist} |
|
8 | 8 |
License: LGPLv2+ |
9 | 9 |
URL: http://www.gnu.org/software/libc |
10 | 10 |
Group: Applications/System |
... | ... |
@@ -16,6 +16,7 @@ Source1: locale-gen.sh |
16 | 16 |
Source2: locale-gen.conf |
17 | 17 |
Patch0: http://www.linuxfromscratch.org/patches/downloads/glibc/glibc-2.25-fhs-1.patch |
18 | 18 |
Patch1: glibc-2.24-bindrsvport-blacklist.patch |
19 |
+Patch2: glibc-fix-CVE-2017-1000366.patch |
|
19 | 20 |
Provides: rtld(GNU_HASH) |
20 | 21 |
Requires: filesystem |
21 | 22 |
%description |
... | ... |
@@ -71,6 +72,7 @@ Name Service Cache Daemon |
71 | 71 |
sed -i 's/\\$$(pwd)/`pwd`/' timezone/Makefile |
72 | 72 |
%patch0 -p1 |
73 | 73 |
%patch1 -p1 |
74 |
+%patch2 -p1 |
|
74 | 75 |
install -vdm 755 %{_builddir}/%{name}-build |
75 | 76 |
# do not try to explicitly provide GLIBC_PRIVATE versioned libraries |
76 | 77 |
%define __find_provides %{_builddir}/%{name}-%{version}/find_provides.sh |
... | ... |
@@ -253,6 +255,8 @@ sed -i 's@#!/bin/bash@#!/bin/sh@' %{buildroot}/usr/bin/tzselect |
253 | 253 |
|
254 | 254 |
|
255 | 255 |
%changelog |
256 |
+* Tue Aug 08 2017 Anish Swaminathan <anishs@vmware.com> 2.25-4 |
|
257 |
+- Apply fix for CVE-2017-1000366 |
|
256 | 258 |
* Thu May 4 2017 Bo Gan <ganb@vmware.com> 2.25-3 |
257 | 259 |
- Remove bash dependency in post/postun script |
258 | 260 |
* Fri Apr 21 2017 Alexey Makhalov <amakhalov@vmware.com> 2.25-2 |