diff options
Diffstat (limited to 'meta')
-rw-r--r-- | meta/recipes-core/glibc/glibc/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch | 668 | ||||
-rw-r--r-- | meta/recipes-core/glibc/glibc_2.24.bb | 1 |
2 files changed, 669 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch b/meta/recipes-core/glibc/glibc/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch new file mode 100644 index 0000000000..66f1fcd0f0 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch | |||
@@ -0,0 +1,668 @@ | |||
1 | From e7ba24f05d86acf7072e066ea6d7b235a106688c Mon Sep 17 00:00:00 2001 | ||
2 | From: Carlos O'Donell <carlos@redhat.com> | ||
3 | Date: Sat, 28 Jan 2017 19:13:34 -0500 | ||
4 | Subject: [PATCH] Bug 20116: Fix use after free in pthread_create() | ||
5 | |||
6 | The commit documents the ownership rules around 'struct pthread' and | ||
7 | when a thread can read or write to the descriptor. With those ownership | ||
8 | rules in place it becomes obvious that pd->stopped_start should not be | ||
9 | touched in several of the paths during thread startup, particularly so | ||
10 | for detached threads. In the case of detached threads, between the time | ||
11 | the thread is created by the OS kernel and the creating thread checks | ||
12 | pd->stopped_start, the detached thread might have already exited and the | ||
13 | memory for pd unmapped. As a regression test we add a simple test which | ||
14 | exercises this exact case by quickly creating detached threads with | ||
15 | large enough stacks to ensure the thread stack cache is bypassed and the | ||
16 | stacks are unmapped. Before the fix the testcase segfaults, after the | ||
17 | fix it works correctly and completes without issue. | ||
18 | |||
19 | For a detailed discussion see: | ||
20 | https://www.sourceware.org/ml/libc-alpha/2017-01/msg00505.html | ||
21 | |||
22 | (cherry-picked from commit f8bf15febcaf137bbec5a61101e88cd5a9d56ca8) | ||
23 | |||
24 | Upstream-Status: Backport [master] | ||
25 | Signed-off-by: Yuanjie Huang <yuanjie.huang@windriver.com> | ||
26 | --- | ||
27 | ChangeLog | 23 ++++ | ||
28 | nptl/Makefile | 3 +- | ||
29 | nptl/createthread.c | 10 +- | ||
30 | nptl/pthread_create.c | 207 +++++++++++++++++++++++++++------ | ||
31 | nptl/pthread_getschedparam.c | 1 + | ||
32 | nptl/pthread_setschedparam.c | 1 + | ||
33 | nptl/pthread_setschedprio.c | 1 + | ||
34 | nptl/tpp.c | 2 + | ||
35 | nptl/tst-create-detached.c | 137 ++++++++++++++++++++++ | ||
36 | sysdeps/nacl/createthread.c | 10 +- | ||
37 | sysdeps/unix/sysv/linux/createthread.c | 16 ++- | ||
38 | 11 files changed, 356 insertions(+), 55 deletions(-) | ||
39 | create mode 100644 nptl/tst-create-detached.c | ||
40 | |||
41 | diff --git a/ChangeLog b/ChangeLog | ||
42 | index 84ae7a7af8..0fbda9020e 100644 | ||
43 | --- a/ChangeLog | ||
44 | +++ b/ChangeLog | ||
45 | @@ -1,3 +1,26 @@ | ||
46 | +2016-01-28 Carlos O'Donell <carlos@redhat.com> | ||
47 | + Alexey Makhalov <amakhalov@vmware.com> | ||
48 | + Florian Weimer <fweimer@redhat.com> | ||
49 | + | ||
50 | + [BZ #20116] | ||
51 | + * nptl/pthread_create.c: Document concurrency notes. | ||
52 | + Enhance thread creation notes. | ||
53 | + (create_thread): Use bool *stopped_start. | ||
54 | + (START_THREAD_DEFN): Comment ownership of PD. | ||
55 | + (__pthread_create_2_1): Add local bool stopped_start and use | ||
56 | + that instead of pd->stopped_start where appropriate. | ||
57 | + * nptl/createthread.c (create_thread): Use bool *stopped_start. | ||
58 | + * sysdeps/nacl/createthread.c (create_thread): Use bool *stopped_start. | ||
59 | + * sysdeps/unix/sysv/linux/createthread.c (create_thread): Likewise. | ||
60 | + * nptl/tst-create-detached.c: New file. | ||
61 | + * nptl/Makefile (tests): Add tst-create-detached. | ||
62 | + * nptl/pthread_getschedparam.c (__pthread_getschedparam): | ||
63 | + Reference the enhanced thread creation notes. | ||
64 | + * nptl/pthread_setschedparam.c (__pthread_setschedparam): Likewise. | ||
65 | + * nptl/pthread_setschedprio.c (pthread_setschedprio): Likewise. | ||
66 | + * nptl/tpp.c (__pthread_tpp_change_priority): Likewise. | ||
67 | + (__pthread_current_priority): Likewise. | ||
68 | + | ||
69 | 2016-08-04 Carlos O'Donell <carlos@redhat.com> | ||
70 | |||
71 | * po/de.po: Update from Translation Project. | ||
72 | diff --git a/nptl/Makefile b/nptl/Makefile | ||
73 | index 0d8aadebed..7dec4edb53 100644 | ||
74 | --- a/nptl/Makefile | ||
75 | +++ b/nptl/Makefile | ||
76 | @@ -290,7 +290,8 @@ tests = tst-typesizes \ | ||
77 | tst-initializers1 $(addprefix tst-initializers1-,\ | ||
78 | c89 gnu89 c99 gnu99 c11 gnu11) \ | ||
79 | tst-bad-schedattr \ | ||
80 | - tst-thread_local1 tst-mutex-errorcheck tst-robust10 | ||
81 | + tst-thread_local1 tst-mutex-errorcheck tst-robust10 \ | ||
82 | + tst-create-detached \ | ||
83 | xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ | ||
84 | tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 | ||
85 | test-srcs = tst-oddstacklimit | ||
86 | diff --git a/nptl/createthread.c b/nptl/createthread.c | ||
87 | index ba2f9c7167..328f85865d 100644 | ||
88 | --- a/nptl/createthread.c | ||
89 | +++ b/nptl/createthread.c | ||
90 | @@ -25,16 +25,14 @@ | ||
91 | |||
92 | static int | ||
93 | create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
94 | - bool stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) | ||
95 | + bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) | ||
96 | { | ||
97 | /* If the implementation needs to do some tweaks to the thread after | ||
98 | it has been created at the OS level, it can set STOPPED_START here. */ | ||
99 | |||
100 | - pd->stopped_start = stopped_start; | ||
101 | - if (__glibc_unlikely (stopped_start)) | ||
102 | - /* We make sure the thread does not run far by forcing it to get a | ||
103 | - lock. We lock it here too so that the new thread cannot continue | ||
104 | - until we tell it to. */ | ||
105 | + pd->stopped_start = *stopped_start; | ||
106 | + if (__glibc_unlikely (*stopped_start)) | ||
107 | + /* See CONCURRENCY NOTES in nptl/pthread_create.c. */ | ||
108 | lll_lock (pd->lock, LLL_PRIVATE); | ||
109 | |||
110 | return ENOSYS; | ||
111 | diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c | ||
112 | index a834063ad5..44b17bec86 100644 | ||
113 | --- a/nptl/pthread_create.c | ||
114 | +++ b/nptl/pthread_create.c | ||
115 | @@ -54,25 +54,141 @@ unsigned int __nptl_nthreads = 1; | ||
116 | /* Code to allocate and deallocate a stack. */ | ||
117 | #include "allocatestack.c" | ||
118 | |||
119 | -/* createthread.c defines this function, and two macros: | ||
120 | +/* CONCURRENCY NOTES: | ||
121 | + | ||
122 | + Understanding who is the owner of the 'struct pthread' or 'PD' | ||
123 | + (refers to the value of the 'struct pthread *pd' function argument) | ||
124 | + is critically important in determining exactly which operations are | ||
125 | + allowed and which are not and when, particularly when it comes to the | ||
126 | + implementation of pthread_create, pthread_join, pthread_detach, and | ||
127 | + other functions which all operate on PD. | ||
128 | + | ||
129 | + The owner of PD is responsible for freeing the final resources | ||
130 | + associated with PD, and may examine the memory underlying PD at any | ||
131 | + point in time until it frees it back to the OS or to reuse by the | ||
132 | + runtime. | ||
133 | + | ||
134 | + The thread which calls pthread_create is called the creating thread. | ||
135 | + The creating thread begins as the owner of PD. | ||
136 | + | ||
137 | + During startup the new thread may examine PD in coordination with the | ||
138 | + owner thread (which may be itself). | ||
139 | + | ||
140 | + The four cases of ownership transfer are: | ||
141 | + | ||
142 | + (1) Ownership of PD is released to the process (all threads may use it) | ||
143 | + after the new thread starts in a joinable state | ||
144 | + i.e. pthread_create returns a usable pthread_t. | ||
145 | + | ||
146 | + (2) Ownership of PD is released to the new thread starting in a detached | ||
147 | + state. | ||
148 | + | ||
149 | + (3) Ownership of PD is dynamically released to a running thread via | ||
150 | + pthread_detach. | ||
151 | + | ||
152 | + (4) Ownership of PD is acquired by the thread which calls pthread_join. | ||
153 | + | ||
154 | + Implementation notes: | ||
155 | + | ||
156 | + The PD->stopped_start and thread_ran variables are used to determine | ||
157 | + exactly which of the four ownership states we are in and therefore | ||
158 | + what actions can be taken. For example after (2) we cannot read or | ||
159 | + write from PD anymore since the thread may no longer exist and the | ||
160 | + memory may be unmapped. The most complicated cases happen during | ||
161 | + thread startup: | ||
162 | + | ||
163 | + (a) If the created thread is in a detached (PTHREAD_CREATE_DETACHED), | ||
164 | + or joinable (default PTHREAD_CREATE_JOINABLE) state and | ||
165 | + STOPPED_START is true, then the creating thread has ownership of | ||
166 | + PD until the PD->lock is released by pthread_create. If any | ||
167 | + errors occur we are in states (c), (d), or (e) below. | ||
168 | + | ||
169 | + (b) If the created thread is in a detached state | ||
170 | + (PTHREAD_CREATED_DETACHED), and STOPPED_START is false, then the | ||
171 | + creating thread has ownership of PD until it invokes the OS | ||
172 | + kernel's thread creation routine. If this routine returns | ||
173 | + without error, then the created thread owns PD; otherwise, see | ||
174 | + (c) and (e) below. | ||
175 | + | ||
176 | + (c) If the detached thread setup failed and THREAD_RAN is true, then | ||
177 | + the creating thread releases ownership to the new thread by | ||
178 | + sending a cancellation signal. All threads set THREAD_RAN to | ||
179 | + true as quickly as possible after returning from the OS kernel's | ||
180 | + thread creation routine. | ||
181 | + | ||
182 | + (d) If the joinable thread setup failed and THREAD_RAN is true, then | ||
183 | + then the creating thread retains ownership of PD and must cleanup | ||
184 | + state. Ownership cannot be released to the process via the | ||
185 | + return of pthread_create since a non-zero result entails PD is | ||
186 | + undefined and therefore cannot be joined to free the resources. | ||
187 | + We privately call pthread_join on the thread to finish handling | ||
188 | + the resource shutdown (Or at least we should, see bug 19511). | ||
189 | + | ||
190 | + (e) If the thread creation failed and THREAD_RAN is false, then the | ||
191 | + creating thread retains ownership of PD and must cleanup state. | ||
192 | + No waiting for the new thread is required because it never | ||
193 | + started. | ||
194 | + | ||
195 | + The nptl_db interface: | ||
196 | + | ||
197 | + The interface with nptl_db requires that we enqueue PD into a linked | ||
198 | + list and then call a function which the debugger will trap. The PD | ||
199 | + will then be dequeued and control returned to the thread. The caller | ||
200 | + at the time must have ownership of PD and such ownership remains | ||
201 | + after control returns to thread. The enqueued PD is removed from the | ||
202 | + linked list by the nptl_db callback td_thr_event_getmsg. The debugger | ||
203 | + must ensure that the thread does not resume execution, otherwise | ||
204 | + ownership of PD may be lost and examining PD will not be possible. | ||
205 | + | ||
206 | + Note that the GNU Debugger as of (December 10th 2015) commit | ||
207 | + c2c2a31fdb228d41ce3db62b268efea04bd39c18 no longer uses | ||
208 | + td_thr_event_getmsg and several other related nptl_db interfaces. The | ||
209 | + principal reason for this is that nptl_db does not support non-stop | ||
210 | + mode where other threads can run concurrently and modify runtime | ||
211 | + structures currently in use by the debugger and the nptl_db | ||
212 | + interface. | ||
213 | + | ||
214 | + Axioms: | ||
215 | + | ||
216 | + * The create_thread function can never set stopped_start to false. | ||
217 | + * The created thread can read stopped_start but never write to it. | ||
218 | + * The variable thread_ran is set some time after the OS thread | ||
219 | + creation routine returns, how much time after the thread is created | ||
220 | + is unspecified, but it should be as quickly as possible. | ||
221 | + | ||
222 | +*/ | ||
223 | + | ||
224 | +/* CREATE THREAD NOTES: | ||
225 | + | ||
226 | + createthread.c defines the create_thread function, and two macros: | ||
227 | START_THREAD_DEFN and START_THREAD_SELF (see below). | ||
228 | |||
229 | - create_thread is obliged to initialize PD->stopped_start. It | ||
230 | - should be true if the STOPPED_START parameter is true, or if | ||
231 | - create_thread needs the new thread to synchronize at startup for | ||
232 | - some other implementation reason. If PD->stopped_start will be | ||
233 | - true, then create_thread is obliged to perform the operation | ||
234 | - "lll_lock (PD->lock, LLL_PRIVATE)" before starting the thread. | ||
235 | + create_thread must initialize PD->stopped_start. It should be true | ||
236 | + if the STOPPED_START parameter is true, or if create_thread needs the | ||
237 | + new thread to synchronize at startup for some other implementation | ||
238 | + reason. If STOPPED_START will be true, then create_thread is obliged | ||
239 | + to lock PD->lock before starting the thread. Then pthread_create | ||
240 | + unlocks PD->lock which synchronizes-with START_THREAD_DEFN in the | ||
241 | + child thread which does an acquire/release of PD->lock as the last | ||
242 | + action before calling the user entry point. The goal of all of this | ||
243 | + is to ensure that the required initial thread attributes are applied | ||
244 | + (by the creating thread) before the new thread runs user code. Note | ||
245 | + that the the functions pthread_getschedparam, pthread_setschedparam, | ||
246 | + pthread_setschedprio, __pthread_tpp_change_priority, and | ||
247 | + __pthread_current_priority reuse the same lock, PD->lock, for a | ||
248 | + similar purpose e.g. synchronizing the setting of similar thread | ||
249 | + attributes. These functions are never called before the thread is | ||
250 | + created, so don't participate in startup syncronization, but given | ||
251 | + that the lock is present already and in the unlocked state, reusing | ||
252 | + it saves space. | ||
253 | |||
254 | The return value is zero for success or an errno code for failure. | ||
255 | If the return value is ENOMEM, that will be translated to EAGAIN, | ||
256 | so create_thread need not do that. On failure, *THREAD_RAN should | ||
257 | be set to true iff the thread actually started up and then got | ||
258 | - cancelled before calling user code (*PD->start_routine), in which | ||
259 | - case it is responsible for doing its own cleanup. */ | ||
260 | - | ||
261 | + canceled before calling user code (*PD->start_routine). */ | ||
262 | static int create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
263 | - bool stopped_start, STACK_VARIABLES_PARMS, | ||
264 | + bool *stopped_start, STACK_VARIABLES_PARMS, | ||
265 | bool *thread_ran); | ||
266 | |||
267 | #include <createthread.c> | ||
268 | @@ -314,12 +430,19 @@ START_THREAD_DEFN | ||
269 | /* Store the new cleanup handler info. */ | ||
270 | THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); | ||
271 | |||
272 | + /* We are either in (a) or (b), and in either case we either own | ||
273 | + PD already (2) or are about to own PD (1), and so our only | ||
274 | + restriction would be that we can't free PD until we know we | ||
275 | + have ownership (see CONCURRENCY NOTES above). */ | ||
276 | if (__glibc_unlikely (pd->stopped_start)) | ||
277 | { | ||
278 | int oldtype = CANCEL_ASYNC (); | ||
279 | |||
280 | /* Get the lock the parent locked to force synchronization. */ | ||
281 | lll_lock (pd->lock, LLL_PRIVATE); | ||
282 | + | ||
283 | + /* We have ownership of PD now. */ | ||
284 | + | ||
285 | /* And give it up right away. */ | ||
286 | lll_unlock (pd->lock, LLL_PRIVATE); | ||
287 | |||
288 | @@ -378,7 +501,8 @@ START_THREAD_DEFN | ||
289 | pd, pd->nextevent)); | ||
290 | } | ||
291 | |||
292 | - /* Now call the function to signal the event. */ | ||
293 | + /* Now call the function which signals the event. See | ||
294 | + CONCURRENCY NOTES for the nptl_db interface comments. */ | ||
295 | __nptl_death_event (); | ||
296 | } | ||
297 | } | ||
298 | @@ -642,19 +766,28 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, | ||
299 | that cares whether the thread count is correct. */ | ||
300 | atomic_increment (&__nptl_nthreads); | ||
301 | |||
302 | - bool thread_ran = false; | ||
303 | + /* Our local value of stopped_start and thread_ran can be accessed at | ||
304 | + any time. The PD->stopped_start may only be accessed if we have | ||
305 | + ownership of PD (see CONCURRENCY NOTES above). */ | ||
306 | + bool stopped_start = false; bool thread_ran = false; | ||
307 | |||
308 | /* Start the thread. */ | ||
309 | if (__glibc_unlikely (report_thread_creation (pd))) | ||
310 | { | ||
311 | - /* Create the thread. We always create the thread stopped | ||
312 | - so that it does not get far before we tell the debugger. */ | ||
313 | - retval = create_thread (pd, iattr, true, STACK_VARIABLES_ARGS, | ||
314 | - &thread_ran); | ||
315 | + stopped_start = true; | ||
316 | + | ||
317 | + /* We always create the thread stopped at startup so we can | ||
318 | + notify the debugger. */ | ||
319 | + retval = create_thread (pd, iattr, &stopped_start, | ||
320 | + STACK_VARIABLES_ARGS, &thread_ran); | ||
321 | if (retval == 0) | ||
322 | { | ||
323 | - /* create_thread should have set this so that the logic below can | ||
324 | - test it. */ | ||
325 | + /* We retain ownership of PD until (a) (see CONCURRENCY NOTES | ||
326 | + above). */ | ||
327 | + | ||
328 | + /* Assert stopped_start is true in both our local copy and the | ||
329 | + PD copy. */ | ||
330 | + assert (stopped_start); | ||
331 | assert (pd->stopped_start); | ||
332 | |||
333 | /* Now fill in the information about the new thread in | ||
334 | @@ -671,26 +804,30 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, | ||
335 | pd, pd->nextevent) | ||
336 | != 0); | ||
337 | |||
338 | - /* Now call the function which signals the event. */ | ||
339 | + /* Now call the function which signals the event. See | ||
340 | + CONCURRENCY NOTES for the nptl_db interface comments. */ | ||
341 | __nptl_create_event (); | ||
342 | } | ||
343 | } | ||
344 | else | ||
345 | - retval = create_thread (pd, iattr, false, STACK_VARIABLES_ARGS, | ||
346 | - &thread_ran); | ||
347 | + retval = create_thread (pd, iattr, &stopped_start, | ||
348 | + STACK_VARIABLES_ARGS, &thread_ran); | ||
349 | |||
350 | if (__glibc_unlikely (retval != 0)) | ||
351 | { | ||
352 | - /* If thread creation "failed", that might mean that the thread got | ||
353 | - created and ran a little--short of running user code--but then | ||
354 | - create_thread cancelled it. In that case, the thread will do all | ||
355 | - its own cleanup just like a normal thread exit after a successful | ||
356 | - creation would do. */ | ||
357 | - | ||
358 | if (thread_ran) | ||
359 | - assert (pd->stopped_start); | ||
360 | + /* State (c) or (d) and we may not have PD ownership (see | ||
361 | + CONCURRENCY NOTES above). We can assert that STOPPED_START | ||
362 | + must have been true because thread creation didn't fail, but | ||
363 | + thread attribute setting did. */ | ||
364 | + /* See bug 19511 which explains why doing nothing here is a | ||
365 | + resource leak for a joinable thread. */ | ||
366 | + assert (stopped_start); | ||
367 | else | ||
368 | { | ||
369 | + /* State (e) and we have ownership of PD (see CONCURRENCY | ||
370 | + NOTES above). */ | ||
371 | + | ||
372 | /* Oops, we lied for a second. */ | ||
373 | atomic_decrement (&__nptl_nthreads); | ||
374 | |||
375 | @@ -710,10 +847,14 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | - if (pd->stopped_start) | ||
380 | - /* The thread blocked on this lock either because we're doing TD_CREATE | ||
381 | - event reporting, or for some other reason that create_thread chose. | ||
382 | - Now let it run free. */ | ||
383 | + /* We don't know if we have PD ownership. Once we check the local | ||
384 | + stopped_start we'll know if we're in state (a) or (b) (see | ||
385 | + CONCURRENCY NOTES above). */ | ||
386 | + if (stopped_start) | ||
387 | + /* State (a), we own PD. The thread blocked on this lock either | ||
388 | + because we're doing TD_CREATE event reporting, or for some | ||
389 | + other reason that create_thread chose. Now let it run | ||
390 | + free. */ | ||
391 | lll_unlock (pd->lock, LLL_PRIVATE); | ||
392 | |||
393 | /* We now have for sure more than one thread. The main thread might | ||
394 | diff --git a/nptl/pthread_getschedparam.c b/nptl/pthread_getschedparam.c | ||
395 | index b887881baf..de71171a08 100644 | ||
396 | --- a/nptl/pthread_getschedparam.c | ||
397 | +++ b/nptl/pthread_getschedparam.c | ||
398 | @@ -35,6 +35,7 @@ __pthread_getschedparam (pthread_t threadid, int *policy, | ||
399 | |||
400 | int result = 0; | ||
401 | |||
402 | + /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ | ||
403 | lll_lock (pd->lock, LLL_PRIVATE); | ||
404 | |||
405 | /* The library is responsible for maintaining the values at all | ||
406 | diff --git a/nptl/pthread_setschedparam.c b/nptl/pthread_setschedparam.c | ||
407 | index dfb52b9dbf..dcb520f1c8 100644 | ||
408 | --- a/nptl/pthread_setschedparam.c | ||
409 | +++ b/nptl/pthread_setschedparam.c | ||
410 | @@ -36,6 +36,7 @@ __pthread_setschedparam (pthread_t threadid, int policy, | ||
411 | |||
412 | int result = 0; | ||
413 | |||
414 | + /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ | ||
415 | lll_lock (pd->lock, LLL_PRIVATE); | ||
416 | |||
417 | struct sched_param p; | ||
418 | diff --git a/nptl/pthread_setschedprio.c b/nptl/pthread_setschedprio.c | ||
419 | index cefc6481d6..8134b50560 100644 | ||
420 | --- a/nptl/pthread_setschedprio.c | ||
421 | +++ b/nptl/pthread_setschedprio.c | ||
422 | @@ -38,6 +38,7 @@ pthread_setschedprio (pthread_t threadid, int prio) | ||
423 | struct sched_param param; | ||
424 | param.sched_priority = prio; | ||
425 | |||
426 | + /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ | ||
427 | lll_lock (pd->lock, LLL_PRIVATE); | ||
428 | |||
429 | /* If the thread should have higher priority because of some | ||
430 | diff --git a/nptl/tpp.c b/nptl/tpp.c | ||
431 | index e175bf4d53..223bd6bbee 100644 | ||
432 | --- a/nptl/tpp.c | ||
433 | +++ b/nptl/tpp.c | ||
434 | @@ -114,6 +114,7 @@ __pthread_tpp_change_priority (int previous_prio, int new_prio) | ||
435 | if (priomax == newpriomax) | ||
436 | return 0; | ||
437 | |||
438 | + /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ | ||
439 | lll_lock (self->lock, LLL_PRIVATE); | ||
440 | |||
441 | tpp->priomax = newpriomax; | ||
442 | @@ -165,6 +166,7 @@ __pthread_current_priority (void) | ||
443 | |||
444 | int result = 0; | ||
445 | |||
446 | + /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ | ||
447 | lll_lock (self->lock, LLL_PRIVATE); | ||
448 | |||
449 | if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) | ||
450 | diff --git a/nptl/tst-create-detached.c b/nptl/tst-create-detached.c | ||
451 | new file mode 100644 | ||
452 | index 0000000000..ea93e441c7 | ||
453 | --- /dev/null | ||
454 | +++ b/nptl/tst-create-detached.c | ||
455 | @@ -0,0 +1,137 @@ | ||
456 | +/* Bug 20116: Test rapid creation of detached threads. | ||
457 | + Copyright (C) 2017 Free Software Foundation, Inc. | ||
458 | + This file is part of the GNU C Library. | ||
459 | + | ||
460 | + The GNU C Library is free software; you can redistribute it and/or | ||
461 | + modify it under the terms of the GNU Lesser General Public | ||
462 | + License as published by the Free Software Foundation; either | ||
463 | + version 2.1 of the License, or (at your option) any later version. | ||
464 | + | ||
465 | + The GNU C Library is distributed in the hope that it will be useful, | ||
466 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
467 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
468 | + Lesser General Public License for more details. | ||
469 | + | ||
470 | + You should have received a copy of the GNU Lesser General Public | ||
471 | + License along with the GNU C Library; see the file COPYING.LIB. If | ||
472 | + not, see <http://www.gnu.org/licenses/>. */ | ||
473 | + | ||
474 | +/* The goal of the test is to trigger a failure if the parent touches | ||
475 | + any part of the thread descriptor after the detached thread has | ||
476 | + exited. We test this by creating many detached threads with large | ||
477 | + stacks. The stacks quickly fill the the stack cache and subsequent | ||
478 | + threads will start to cause the thread stacks to be immediately | ||
479 | + unmapped to satisfy the stack cache max. With the stacks being | ||
480 | + unmapped the parent's read of any part of the thread descriptor will | ||
481 | + trigger a segfault. That segfault is what we are trying to cause, | ||
482 | + since any segfault is a defect in the implementation. */ | ||
483 | + | ||
484 | +#include <pthread.h> | ||
485 | +#include <stdio.h> | ||
486 | +#include <errno.h> | ||
487 | +#include <unistd.h> | ||
488 | +#include <stdbool.h> | ||
489 | +#include <sys/resource.h> | ||
490 | +#include <support/xthread.h> | ||
491 | + | ||
492 | +/* Number of threads to create. */ | ||
493 | +enum { threads_to_create = 100000 }; | ||
494 | + | ||
495 | +/* Number of threads which should spawn other threads. */ | ||
496 | +enum { creator_threads = 2 }; | ||
497 | + | ||
498 | +/* Counter of threads created so far. This is incremented by all the | ||
499 | + running creator threads. */ | ||
500 | +static unsigned threads_created; | ||
501 | + | ||
502 | +/* Thread callback which does nothing, so that the thread exits | ||
503 | + immediatedly. */ | ||
504 | +static void * | ||
505 | +do_nothing (void *arg) | ||
506 | +{ | ||
507 | + return NULL; | ||
508 | +} | ||
509 | + | ||
510 | +/* Attribute indicating that the thread should be created in a detached | ||
511 | + fashion. */ | ||
512 | +static pthread_attr_t detached; | ||
513 | + | ||
514 | +/* Barrier to synchronize initialization. */ | ||
515 | +static pthread_barrier_t barrier; | ||
516 | + | ||
517 | +static void * | ||
518 | +creator_thread (void *arg) | ||
519 | +{ | ||
520 | + int ret; | ||
521 | + xpthread_barrier_wait (&barrier); | ||
522 | + | ||
523 | + while (true) | ||
524 | + { | ||
525 | + pthread_t thr; | ||
526 | + /* Thread creation will fail if the kernel does not free old | ||
527 | + threads quickly enough, so we do not report errors. */ | ||
528 | + ret = pthread_create (&thr, &detached, do_nothing, NULL); | ||
529 | + if (ret == 0 && __atomic_add_fetch (&threads_created, 1, __ATOMIC_SEQ_CST) | ||
530 | + >= threads_to_create) | ||
531 | + break; | ||
532 | + } | ||
533 | + | ||
534 | + return NULL; | ||
535 | +} | ||
536 | + | ||
537 | +static int | ||
538 | +do_test (void) | ||
539 | +{ | ||
540 | + /* Limit the size of the process, so that memory allocation will | ||
541 | + fail without impacting the entire system. */ | ||
542 | + { | ||
543 | + struct rlimit limit; | ||
544 | + if (getrlimit (RLIMIT_AS, &limit) != 0) | ||
545 | + { | ||
546 | + printf ("FAIL: getrlimit (RLIMIT_AS) failed: %m\n"); | ||
547 | + return 1; | ||
548 | + } | ||
549 | + /* This limit, 800MB, is just a heuristic. Any value can be | ||
550 | + picked. */ | ||
551 | + long target = 800 * 1024 * 1024; | ||
552 | + if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target) | ||
553 | + { | ||
554 | + limit.rlim_cur = target; | ||
555 | + if (setrlimit (RLIMIT_AS, &limit) != 0) | ||
556 | + { | ||
557 | + printf ("FAIL: setrlimit (RLIMIT_AS) failed: %m\n"); | ||
558 | + return 1; | ||
559 | + } | ||
560 | + } | ||
561 | + } | ||
562 | + | ||
563 | + xpthread_attr_init (&detached); | ||
564 | + | ||
565 | + xpthread_attr_setdetachstate (&detached, PTHREAD_CREATE_DETACHED); | ||
566 | + | ||
567 | + /* A large thread stack seems beneficial for reproducing a race | ||
568 | + condition in detached thread creation. The goal is to reach the | ||
569 | + limit of the runtime thread stack cache such that the detached | ||
570 | + thread's stack is unmapped after exit and causes a segfault when | ||
571 | + the parent reads the thread descriptor data stored on the the | ||
572 | + unmapped stack. */ | ||
573 | + xpthread_attr_setstacksize (&detached, 16 * 1024 * 1024); | ||
574 | + | ||
575 | + xpthread_barrier_init (&barrier, NULL, creator_threads); | ||
576 | + | ||
577 | + pthread_t threads[creator_threads]; | ||
578 | + | ||
579 | + for (int i = 0; i < creator_threads; ++i) | ||
580 | + threads[i] = xpthread_create (NULL, creator_thread, NULL); | ||
581 | + | ||
582 | + for (int i = 0; i < creator_threads; ++i) | ||
583 | + xpthread_join (threads[i]); | ||
584 | + | ||
585 | + xpthread_attr_destroy (&detached); | ||
586 | + | ||
587 | + xpthread_barrier_destroy (&barrier); | ||
588 | + | ||
589 | + return 0; | ||
590 | +} | ||
591 | + | ||
592 | +#include <support/test-driver.c> | ||
593 | diff --git a/sysdeps/nacl/createthread.c b/sysdeps/nacl/createthread.c | ||
594 | index 7b571c34e2..5465558cc1 100644 | ||
595 | --- a/sysdeps/nacl/createthread.c | ||
596 | +++ b/sysdeps/nacl/createthread.c | ||
597 | @@ -32,15 +32,13 @@ static void start_thread (void) __attribute__ ((noreturn)); | ||
598 | |||
599 | static int | ||
600 | create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
601 | - bool stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) | ||
602 | + bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) | ||
603 | { | ||
604 | pd->tid = __nacl_get_tid (pd); | ||
605 | |||
606 | - pd->stopped_start = stopped_start; | ||
607 | - if (__glibc_unlikely (stopped_start)) | ||
608 | - /* We make sure the thread does not run far by forcing it to get a | ||
609 | - lock. We lock it here too so that the new thread cannot continue | ||
610 | - until we tell it to. */ | ||
611 | + pd->stopped_start = *stopped_start; | ||
612 | + if (__glibc_unlikely (*stopped_start)) | ||
613 | + /* See CONCURRENCY NOTES in nptl/pthread_create.c. */ | ||
614 | lll_lock (pd->lock, LLL_PRIVATE); | ||
615 | |||
616 | TLS_DEFINE_INIT_TP (tp, pd); | ||
617 | diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c | ||
618 | index 6d32cece48..66ddae61d4 100644 | ||
619 | --- a/sysdeps/unix/sysv/linux/createthread.c | ||
620 | +++ b/sysdeps/unix/sysv/linux/createthread.c | ||
621 | @@ -46,7 +46,7 @@ static int start_thread (void *arg) __attribute__ ((noreturn)); | ||
622 | |||
623 | static int | ||
624 | create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
625 | - bool stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) | ||
626 | + bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) | ||
627 | { | ||
628 | /* Determine whether the newly created threads has to be started | ||
629 | stopped since we have to set the scheduling parameters or set the | ||
630 | @@ -54,13 +54,11 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
631 | if (attr != NULL | ||
632 | && (__glibc_unlikely (attr->cpuset != NULL) | ||
633 | || __glibc_unlikely ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))) | ||
634 | - stopped_start = true; | ||
635 | + *stopped_start = true; | ||
636 | |||
637 | - pd->stopped_start = stopped_start; | ||
638 | - if (__glibc_unlikely (stopped_start)) | ||
639 | - /* We make sure the thread does not run far by forcing it to get a | ||
640 | - lock. We lock it here too so that the new thread cannot continue | ||
641 | - until we tell it to. */ | ||
642 | + pd->stopped_start = *stopped_start; | ||
643 | + if (__glibc_unlikely (*stopped_start)) | ||
644 | + /* See CONCURRENCY NOTES in nptl/pthread_creat.c. */ | ||
645 | lll_lock (pd->lock, LLL_PRIVATE); | ||
646 | |||
647 | /* We rely heavily on various flags the CLONE function understands: | ||
648 | @@ -117,7 +115,7 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
649 | /* Set the affinity mask if necessary. */ | ||
650 | if (attr->cpuset != NULL) | ||
651 | { | ||
652 | - assert (stopped_start); | ||
653 | + assert (*stopped_start); | ||
654 | |||
655 | res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, | ||
656 | attr->cpusetsize, attr->cpuset); | ||
657 | @@ -140,7 +138,7 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, | ||
658 | /* Set the scheduling parameters. */ | ||
659 | if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0) | ||
660 | { | ||
661 | - assert (stopped_start); | ||
662 | + assert (*stopped_start); | ||
663 | |||
664 | res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid, | ||
665 | pd->schedpolicy, &pd->schedparam); | ||
666 | -- | ||
667 | 2.11.0 | ||
668 | |||
diff --git a/meta/recipes-core/glibc/glibc_2.24.bb b/meta/recipes-core/glibc/glibc_2.24.bb index f5a21b258d..b60b692723 100644 --- a/meta/recipes-core/glibc/glibc_2.24.bb +++ b/meta/recipes-core/glibc/glibc_2.24.bb | |||
@@ -37,6 +37,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ | |||
37 | file://0024-eglibc-Forward-port-cross-locale-generation-support.patch \ | 37 | file://0024-eglibc-Forward-port-cross-locale-generation-support.patch \ |
38 | file://0025-Define-DUMMY_LOCALE_T-if-not-defined.patch \ | 38 | file://0025-Define-DUMMY_LOCALE_T-if-not-defined.patch \ |
39 | file://0026-build_local_scope.patch \ | 39 | file://0026-build_local_scope.patch \ |
40 | file://0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch \ | ||
40 | " | 41 | " |
41 | 42 | ||
42 | SRC_URI += "\ | 43 | SRC_URI += "\ |