]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/glibc/glibc-rh1154563.patch
dhcpcd: fix delay after dhcp down.
[ipfire-2.x.git] / src / patches / glibc / glibc-rh1154563.patch
CommitLineData
fe875de8
MT
1#
2# This is a special patch for rhel-6 to fix recursive dlopen.
3# It is likely the upstream patch will always be too risky for
4# rhel-6 and will involve reorganizing the way in which recursive
5# dlopen is allowed to operate and how the _r_debug and stap
6# points are used by gdb for the recursive case.
7#
8# This fix changes the internal API to duplicate the ldconfig
9# cache data. This means that at any point the cache can be
10# unmapped without any consequences. The caller is responsible
11# fore freeing the returned string.
12#
13# A regression test is added to verify the assertion for _r_debug
14# is no longer triggered due to the recursive dlopen. The test to
15# verify the fix in _dl_load_cache_lookup is not automated and
16# has to be run by hand.
17#
18diff -urN glibc-2.12-2-gc4ccff1/elf/dl-cache.c glibc-2.12-2-gc4ccff1.mod/elf/dl-cache.c
19--- glibc-2.12-2-gc4ccff1/elf/dl-cache.c 2010-05-04 07:27:23.000000000 -0400
20+++ glibc-2.12-2-gc4ccff1.mod/elf/dl-cache.c 2014-12-10 21:54:08.801985045 -0500
21@@ -175,9 +175,12 @@
22
23
24 /* Look up NAME in ld.so.cache and return the file name stored there,
25- or null if none is found. */
26-
27-const char *
28+ or null if none is found.
29+ The caller is responsible for freeing the returned string. The ld.so.cache
30+ may be unmapped at any time by a completing recursive dlopen and
31+ this function must take care that it does not return references to
32+ any data in the mapping. */
33+char *
34 internal_function
35 _dl_load_cache_lookup (const char *name)
36 {
37@@ -290,7 +293,17 @@
38 && best != NULL)
39 _dl_debug_printf (" trying file=%s\n", best);
40
41- return best;
42+ if (best == NULL)
43+ return NULL;
44+
45+ /* The double copy is *required* since malloc may be interposed
46+ and call dlopen itself whose completion would unmap the data
47+ we are accessing. Therefore we must make the copy of the
48+ mapping data without using malloc. */
49+ char *temp;
50+ temp = alloca (strlen (best) + 1);
51+ strcpy (temp, best);
52+ return strdup (temp);
53 }
54
55 #ifndef MAP_COPY
56diff -urN glibc-2.12-2-gc4ccff1/elf/dl-load.c glibc-2.12-2-gc4ccff1.mod/elf/dl-load.c
57--- glibc-2.12-2-gc4ccff1/elf/dl-load.c 2014-12-10 11:03:17.966048404 -0500
58+++ glibc-2.12-2-gc4ccff1.mod/elf/dl-load.c 2014-12-10 21:47:29.319387538 -0500
59@@ -2126,7 +2126,7 @@
60 {
61 /* Check the list of libraries in the file /etc/ld.so.cache,
62 for compatibility with Linux's ldconfig program. */
63- const char *cached = _dl_load_cache_lookup (name);
64+ char *cached = _dl_load_cache_lookup (name);
65
66 if (cached != NULL)
67 {
68@@ -2156,6 +2156,7 @@
69 if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
70 {
71 /* The prefix matches. Don't use the entry. */
72+ free (cached);
73 cached = NULL;
74 break;
75 }
76@@ -2172,14 +2173,9 @@
77 &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
78 LA_SER_CONFIG, &found_other_class, false);
79 if (__builtin_expect (fd != -1, 1))
80- {
81- realname = local_strdup (cached);
82- if (realname == NULL)
83- {
84- __close (fd);
85- fd = -1;
86- }
87- }
88+ realname = cached;
89+ else
90+ free (cached);
91 }
92 }
93 }
94diff -urN glibc-2.12-2-gc4ccff1/elf/dl-open.c glibc-2.12-2-gc4ccff1.mod/elf/dl-open.c
95--- glibc-2.12-2-gc4ccff1/elf/dl-open.c 2014-12-10 11:03:18.083048497 -0500
96+++ glibc-2.12-2-gc4ccff1.mod/elf/dl-open.c 2014-12-10 20:34:16.017503638 -0500
97@@ -220,7 +220,11 @@
98 }
99 }
100
101- assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
102+ /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that
103+ may not be true if this is a recursive call to dlopen.
104+ TODO: Fix all of the debug state so we end up at RT_CONSISTENT only when the last
105+ recursive dlopen completes. */
106+ _dl_debug_initialize (0, args->nsid);
107
108 /* Load the named object. */
109 struct link_map *new;
110diff -urN glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h glibc-2.12-2-gc4ccff1.mod/sysdeps/generic/ldsodefs.h
111--- glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h 2014-12-10 11:03:17.944048387 -0500
112+++ glibc-2.12-2-gc4ccff1.mod/sysdeps/generic/ldsodefs.h 2014-12-10 21:46:14.071344018 -0500
113@@ -996,8 +996,8 @@
114 internal_function;
115
116 /* Look up NAME in ld.so.cache and return the file name stored there,
117- or null if none is found. */
118-extern const char *_dl_load_cache_lookup (const char *name)
119+ or null if none is found. Caller must free returned string. */
120+extern char *_dl_load_cache_lookup (const char *name)
121 internal_function;
122
123 /* If the system does not support MAP_COPY we cannot leave the file open
124diff -urN glibc-2.12-2-gc4ccff1/dlfcn/Makefile glibc-2.12-2-gc4ccff1.mod/dlfcn/Makefile
125--- glibc-2.12-2-gc4ccff1/dlfcn/Makefile 2010-05-04 07:27:23.000000000 -0400
126+++ glibc-2.12-2-gc4ccff1.mod/dlfcn/Makefile 2014-12-11 16:58:55.719803063 -0500
127@@ -42,12 +42,12 @@
128 ifeq (yes,$(build-shared))
129 tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
130 bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
131- bug-atexit3 tstatexit
132+ bug-atexit3 tstatexit tst-rec-dlopen
133 endif
134 modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
135 defaultmod2 errmsg1mod modatexit modcxaatexit \
136 bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
137- bug-atexit2-lib bug-atexit3-lib
138+ bug-atexit2-lib bug-atexit3-lib moddummy1 moddummy2
139
140 failtestmod.so-no-z-defs = yes
141 glreflib2.so-no-z-defs = yes
142@@ -142,6 +142,8 @@
143 $(objpfx)bug-atexit3-lib.so: $(common-objpfx)libc.so \
144 $(common-objpfx)libc_nonshared.a
145
146+LDLIBS-tst-rec-dlopen = -ldl
147+$(objpfx)tst-rec-dlopen: $(libdl)
148
149 # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
150 # This ensures they will load libc.so for needed symbols if loaded by
151diff -urN glibc-2.12-2-gc4ccff1/dlfcn/moddummy1.c glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy1.c
152--- glibc-2.12-2-gc4ccff1/dlfcn/moddummy1.c 1969-12-31 19:00:00.000000000 -0500
153+++ glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy1.c 2014-12-11 16:57:54.108797285 -0500
154@@ -0,0 +1,13 @@
155+/* Provide a dummy DSO for tst-recursive-dlopen to use. */
156+#include <stdio.h>
157+#include <stdlib.h>
158+
159+int called_dummy1;
160+
161+void
162+dummy1 (void)
163+{
164+ printf ("Called dummy1()\n");
165+ called_dummy1++;
166+}
167+
168diff -urN glibc-2.12-2-gc4ccff1/dlfcn/moddummy2.c glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy2.c
169--- glibc-2.12-2-gc4ccff1/dlfcn/moddummy2.c 1969-12-31 19:00:00.000000000 -0500
170+++ glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy2.c 2014-12-11 16:57:54.108797285 -0500
171@@ -0,0 +1,13 @@
172+/* Provide a dummy DSO for tst-recursive-dlopen to use. */
173+#include <stdio.h>
174+#include <stdlib.h>
175+
176+int called_dummy2;
177+
178+void
179+dummy2 (void)
180+{
181+ printf ("Called dummy2()\n");
182+ called_dummy2++;
183+}
184+
185diff -urN glibc-2.12-2-gc4ccff1/dlfcn/tst-rec-dlopen.c glibc-2.12-2-gc4ccff1.mod/dlfcn/tst-rec-dlopen.c
186--- glibc-2.12-2-gc4ccff1/dlfcn/tst-rec-dlopen.c 1969-12-31 19:00:00.000000000 -0500
187+++ glibc-2.12-2-gc4ccff1.mod/dlfcn/tst-rec-dlopen.c 2014-12-11 20:53:28.617848774 -0500
188@@ -0,0 +1,145 @@
189+/* Test recursive dlopen using malloc hooks.
190+ Copyright (C) 1998-2014 Free Software Foundation, Inc.
191+ This file is part of the GNU C Library.
192+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
193+
194+ The GNU C Library is free software; you can redistribute it and/or
195+ modify it under the terms of the GNU Lesser General Public
196+ License as published by the Free Software Foundation; either
197+ version 2.1 of the License, or (at your option) any later version.
198+
199+ The GNU C Library is distributed in the hope that it will be useful,
200+ but WITHOUT ANY WARRANTY; without even the implied warranty of
201+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
202+ Lesser General Public License for more details.
203+
204+ You should have received a copy of the GNU Lesser General Public
205+ License along with the GNU C Library; if not, see
206+ <http://www.gnu.org/licenses/>. */
207+
208+#include <stdio.h>
209+#include <stdlib.h>
210+#include <malloc.h>
211+#include <dlfcn.h>
212+
213+#define DSO "moddummy1.so"
214+#define FUNC "dummy1"
215+
216+#define DSO1 "moddummy2.so"
217+#define FUNC1 "dummy2"
218+
219+/* Prevent the compiler from moving the assignment to called_func
220+ before (*func)() since the compiler doesn't know we might abort
221+ or catch a SIGSEGV signal and it may move the store. */
222+volatile int called_func;
223+
224+/* Prototype for my hook. */
225+void *custom_malloc_hook (size_t, const void *);
226+
227+/* Pointer to old malloc hooks. */
228+void *(*old_malloc_hook) (size_t, const void *);
229+
230+/* Call function func_name in DSO dso_name via dlopen. */
231+void
232+call_func (const char *dso_name, const char *func_name)
233+{
234+ int ret;
235+ void *dso;
236+ void (*func) (void);
237+ char *err;
238+
239+ /* Open the DSO. */
240+ dso = dlopen (dso_name, RTLD_NOW|RTLD_GLOBAL);
241+ if (dso == NULL)
242+ {
243+ err = dlerror ();
244+ fprintf (stderr, "%s\n", err);
245+ exit (1);
246+ }
247+ /* Clear any errors. */
248+ dlerror ();
249+
250+ /* Lookup func. */
251+ *(void **) (&func) = dlsym (dso, func_name);
252+ if (func == NULL)
253+ {
254+ err = dlerror ();
255+ if (err != NULL)
256+ {
257+ fprintf (stderr, "%s\n", err);
258+ exit (1);
259+ }
260+ }
261+ /* Call func. */
262+ (*func) ();
263+ called_func = 1;
264+
265+ /* Close the library and look for errors too. */
266+ ret = dlclose (dso);
267+ if (ret != 0)
268+ {
269+ err = dlerror ();
270+ fprintf (stderr, "%s\n", err);
271+ exit (1);
272+ }
273+
274+}
275+
276+/* Empty hook that does nothing. */
277+void *
278+custom_malloc_hook (size_t size, const void *caller)
279+{
280+ void *result;
281+ /* Restore old hooks. */
282+ __malloc_hook = old_malloc_hook;
283+ /* First call a function in another library via dlopen. */
284+ call_func (DSO1, FUNC1);
285+ /* Called recursively. */
286+ result = malloc (size);
287+ /* Restore new hooks. */
288+ __malloc_hook = custom_malloc_hook;
289+ return result;
290+}
291+
292+static int
293+do_test (void)
294+{
295+ /* Save old hook. */
296+ old_malloc_hook = __malloc_hook;
297+ /* Install new hook. */
298+ __malloc_hook = custom_malloc_hook;
299+
300+ /* Bug 17702 fixes two things:
301+ * A recursive dlopen unmapping the ld.so.cache.
302+ * An assertion that _r_debug is RT_CONSISTENT at entry to dlopen.
303+ We can only test the latter. Testing the former requires modifying
304+ ld.so.conf to cache the dummy libraries, then running ldconfig,
305+ then run the test. If you do all of that (and glibc's test
306+ infrastructure doesn't support that yet) then the test will
307+ SEGFAULT without the fix. If you don't do that, then the test
308+ will abort because of the assert described in detail below. */
309+ call_func (DSO, FUNC);
310+
311+ /* Restore old hook. */
312+ __malloc_hook = old_malloc_hook;
313+
314+ /* The function dummy2() is called by the malloc hook. Check to
315+ see that it was called. This ensures the second recursive
316+ dlopen happened and we called the function in that library.
317+
318+ Before the fix you either get a SIGSEGV when accessing mmap'd
319+ ld.so.cache data or an assertion failure about _r_debug not
320+ beint RT_CONSISTENT. We don't test for the SIGSEGV since it
321+ would require finding moddummy1 or moddummy2 in the cache and
322+ we don't have any infrastructure to test that, but the _r_debug
323+ assertion triggers. */
324+ if (called_func > 0)
325+ printf ("PASS: Function call_func() called more than once.\n");
326+ else
327+ printf ("FAIL: Function call_func() not called.\n");
328+
329+ return 0;
330+}
331+
332+#define TEST_FUNCTION do_test ()
333+#include "../test-skeleton.c"