diff options
-rw-r--r-- | meta-agl-bsp/meta-core/recipes-core/glibc/files/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch | 637 | ||||
-rw-r--r-- | meta-agl-bsp/meta-core/recipes-core/glibc/glibc_2.24.bbappend | 4 |
2 files changed, 641 insertions, 0 deletions
diff --git a/meta-agl-bsp/meta-core/recipes-core/glibc/files/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch b/meta-agl-bsp/meta-core/recipes-core/glibc/files/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch new file mode 100644 index 000000000..f06f85c62 --- /dev/null +++ b/meta-agl-bsp/meta-core/recipes-core/glibc/files/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch @@ -0,0 +1,637 @@ +From e7ba24f05d86acf7072e066ea6d7b235a106688c Mon Sep 17 00:00:00 2001 +From: Carlos O'Donell <carlos@redhat.com> +Date: Sat, 28 Jan 2017 19:13:34 -0500 +Subject: [PATCH] Bug 20116: Fix use after free in pthread_create() + +The commit documents the ownership rules around 'struct pthread' and +when a thread can read or write to the descriptor. With those ownership +rules in place it becomes obvious that pd->stopped_start should not be +touched in several of the paths during thread startup, particularly so +for detached threads. In the case of detached threads, between the time +the thread is created by the OS kernel and the creating thread checks +pd->stopped_start, the detached thread might have already exited and the +memory for pd unmapped. As a regression test we add a simple test which +exercises this exact case by quickly creating detached threads with +large enough stacks to ensure the thread stack cache is bypassed and the +stacks are unmapped. Before the fix the testcase segfaults, after the +fix it works correctly and completes without issue. + +For a detailed discussion see: +https://www.sourceware.org/ml/libc-alpha/2017-01/msg00505.html + +(cherry-picked from commit f8bf15febcaf137bbec5a61101e88cd5a9d56ca8) + +Upstream-Status: Backport [master] +Signed-off-by: Yuanjie Huang <yuanjie.huang@windriver.com> +--- + ChangeLog | 23 ++++ + nptl/Makefile | 3 +- + nptl/createthread.c | 10 +- + nptl/pthread_create.c | 207 +++++++++++++++++++++++++++------ + nptl/pthread_getschedparam.c | 1 + + nptl/pthread_setschedparam.c | 1 + + nptl/pthread_setschedprio.c | 1 + + nptl/tpp.c | 2 + + nptl/tst-create-detached.c | 137 ++++++++++++++++++++++ + sysdeps/nacl/createthread.c | 10 +- + sysdeps/unix/sysv/linux/createthread.c | 16 ++- + 11 files changed, 356 insertions(+), 55 deletions(-) + create mode 100644 nptl/tst-create-detached.c + +diff --git a/nptl/Makefile b/nptl/Makefile +index 0d8aadebed..7dec4edb53 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -290,7 +290,8 @@ tests = tst-typesizes \ + tst-initializers1 $(addprefix tst-initializers1-,\ + c89 gnu89 c99 gnu99 c11 gnu11) \ + tst-bad-schedattr \ +- tst-thread_local1 tst-mutex-errorcheck tst-robust10 ++ tst-thread_local1 tst-mutex-errorcheck tst-robust10 \ ++ tst-create-detached \ + xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ + tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 + test-srcs = tst-oddstacklimit +diff --git a/nptl/createthread.c b/nptl/createthread.c +index ba2f9c7167..328f85865d 100644 +--- a/nptl/createthread.c ++++ b/nptl/createthread.c +@@ -25,16 +25,14 @@ + + static int + create_thread (struct pthread *pd, const struct pthread_attr *attr, +- bool stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) ++ bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) + { + /* If the implementation needs to do some tweaks to the thread after + it has been created at the OS level, it can set STOPPED_START here. */ + +- pd->stopped_start = stopped_start; +- if (__glibc_unlikely (stopped_start)) +- /* We make sure the thread does not run far by forcing it to get a +- lock. We lock it here too so that the new thread cannot continue +- until we tell it to. */ ++ pd->stopped_start = *stopped_start; ++ if (__glibc_unlikely (*stopped_start)) ++ /* See CONCURRENCY NOTES in nptl/pthread_create.c. */ + lll_lock (pd->lock, LLL_PRIVATE); + + return ENOSYS; +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index a834063ad5..44b17bec86 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -54,25 +54,141 @@ unsigned int __nptl_nthreads = 1; + /* Code to allocate and deallocate a stack. */ + #include "allocatestack.c" + +-/* createthread.c defines this function, and two macros: ++/* CONCURRENCY NOTES: ++ ++ Understanding who is the owner of the 'struct pthread' or 'PD' ++ (refers to the value of the 'struct pthread *pd' function argument) ++ is critically important in determining exactly which operations are ++ allowed and which are not and when, particularly when it comes to the ++ implementation of pthread_create, pthread_join, pthread_detach, and ++ other functions which all operate on PD. ++ ++ The owner of PD is responsible for freeing the final resources ++ associated with PD, and may examine the memory underlying PD at any ++ point in time until it frees it back to the OS or to reuse by the ++ runtime. ++ ++ The thread which calls pthread_create is called the creating thread. ++ The creating thread begins as the owner of PD. ++ ++ During startup the new thread may examine PD in coordination with the ++ owner thread (which may be itself). ++ ++ The four cases of ownership transfer are: ++ ++ (1) Ownership of PD is released to the process (all threads may use it) ++ after the new thread starts in a joinable state ++ i.e. pthread_create returns a usable pthread_t. ++ ++ (2) Ownership of PD is released to the new thread starting in a detached ++ state. ++ ++ (3) Ownership of PD is dynamically released to a running thread via ++ pthread_detach. ++ ++ (4) Ownership of PD is acquired by the thread which calls pthread_join. ++ ++ Implementation notes: ++ ++ The PD->stopped_start and thread_ran variables are used to determine ++ exactly which of the four ownership states we are in and therefore ++ what actions can be taken. For example after (2) we cannot read or ++ write from PD anymore since the thread may no longer exist and the ++ memory may be unmapped. The most complicated cases happen during ++ thread startup: ++ ++ (a) If the created thread is in a detached (PTHREAD_CREATE_DETACHED), ++ or joinable (default PTHREAD_CREATE_JOINABLE) state and ++ STOPPED_START is true, then the creating thread has ownership of ++ PD until the PD->lock is released by pthread_create. If any ++ errors occur we are in states (c), (d), or (e) below. ++ ++ (b) If the created thread is in a detached state ++ (PTHREAD_CREATED_DETACHED), and STOPPED_START is false, then the ++ creating thread has ownership of PD until it invokes the OS ++ kernel's thread creation routine. If this routine returns ++ without error, then the created thread owns PD; otherwise, see ++ (c) and (e) below. ++ ++ (c) If the detached thread setup failed and THREAD_RAN is true, then ++ the creating thread releases ownership to the new thread by ++ sending a cancellation signal. All threads set THREAD_RAN to ++ true as quickly as possible after returning from the OS kernel's ++ thread creation routine. ++ ++ (d) If the joinable thread setup failed and THREAD_RAN is true, then ++ then the creating thread retains ownership of PD and must cleanup ++ state. Ownership cannot be released to the process via the ++ return of pthread_create since a non-zero result entails PD is ++ undefined and therefore cannot be joined to free the resources. ++ We privately call pthread_join on the thread to finish handling ++ the resource shutdown (Or at least we should, see bug 19511). ++ ++ (e) If the thread creation failed and THREAD_RAN is false, then the ++ creating thread retains ownership of PD and must cleanup state. ++ No waiting for the new thread is required because it never ++ started. ++ ++ The nptl_db interface: ++ ++ The interface with nptl_db requires that we enqueue PD into a linked ++ list and then call a function which the debugger will trap. The PD ++ will then be dequeued and control returned to the thread. The caller ++ at the time must have ownership of PD and such ownership remains ++ after control returns to thread. The enqueued PD is removed from the ++ linked list by the nptl_db callback td_thr_event_getmsg. The debugger ++ must ensure that the thread does not resume execution, otherwise ++ ownership of PD may be lost and examining PD will not be possible. ++ ++ Note that the GNU Debugger as of (December 10th 2015) commit ++ c2c2a31fdb228d41ce3db62b268efea04bd39c18 no longer uses ++ td_thr_event_getmsg and several other related nptl_db interfaces. The ++ principal reason for this is that nptl_db does not support non-stop ++ mode where other threads can run concurrently and modify runtime ++ structures currently in use by the debugger and the nptl_db ++ interface. ++ ++ Axioms: ++ ++ * The create_thread function can never set stopped_start to false. ++ * The created thread can read stopped_start but never write to it. ++ * The variable thread_ran is set some time after the OS thread ++ creation routine returns, how much time after the thread is created ++ is unspecified, but it should be as quickly as possible. ++ ++*/ ++ ++/* CREATE THREAD NOTES: ++ ++ createthread.c defines the create_thread function, and two macros: + START_THREAD_DEFN and START_THREAD_SELF (see below). + +- create_thread is obliged to initialize PD->stopped_start. It +- should be true if the STOPPED_START parameter is true, or if +- create_thread needs the new thread to synchronize at startup for +- some other implementation reason. If PD->stopped_start will be +- true, then create_thread is obliged to perform the operation +- "lll_lock (PD->lock, LLL_PRIVATE)" before starting the thread. ++ create_thread must initialize PD->stopped_start. It should be true ++ if the STOPPED_START parameter is true, or if create_thread needs the ++ new thread to synchronize at startup for some other implementation ++ reason. If STOPPED_START will be true, then create_thread is obliged ++ to lock PD->lock before starting the thread. Then pthread_create ++ unlocks PD->lock which synchronizes-with START_THREAD_DEFN in the ++ child thread which does an acquire/release of PD->lock as the last ++ action before calling the user entry point. The goal of all of this ++ is to ensure that the required initial thread attributes are applied ++ (by the creating thread) before the new thread runs user code. Note ++ that the the functions pthread_getschedparam, pthread_setschedparam, ++ pthread_setschedprio, __pthread_tpp_change_priority, and ++ __pthread_current_priority reuse the same lock, PD->lock, for a ++ similar purpose e.g. synchronizing the setting of similar thread ++ attributes. These functions are never called before the thread is ++ created, so don't participate in startup syncronization, but given ++ that the lock is present already and in the unlocked state, reusing ++ it saves space. + + The return value is zero for success or an errno code for failure. + If the return value is ENOMEM, that will be translated to EAGAIN, + so create_thread need not do that. On failure, *THREAD_RAN should + be set to true iff the thread actually started up and then got +- cancelled before calling user code (*PD->start_routine), in which +- case it is responsible for doing its own cleanup. */ +- ++ canceled before calling user code (*PD->start_routine). */ + static int create_thread (struct pthread *pd, const struct pthread_attr *attr, +- bool stopped_start, STACK_VARIABLES_PARMS, ++ bool *stopped_start, STACK_VARIABLES_PARMS, + bool *thread_ran); + + #include <createthread.c> +@@ -314,12 +430,19 @@ START_THREAD_DEFN + /* Store the new cleanup handler info. */ + THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + ++ /* We are either in (a) or (b), and in either case we either own ++ PD already (2) or are about to own PD (1), and so our only ++ restriction would be that we can't free PD until we know we ++ have ownership (see CONCURRENCY NOTES above). */ + if (__glibc_unlikely (pd->stopped_start)) + { + int oldtype = CANCEL_ASYNC (); + + /* Get the lock the parent locked to force synchronization. */ + lll_lock (pd->lock, LLL_PRIVATE); ++ ++ /* We have ownership of PD now. */ ++ + /* And give it up right away. */ + lll_unlock (pd->lock, LLL_PRIVATE); + +@@ -378,7 +501,8 @@ START_THREAD_DEFN + pd, pd->nextevent)); + } + +- /* Now call the function to signal the event. */ ++ /* Now call the function which signals the event. See ++ CONCURRENCY NOTES for the nptl_db interface comments. */ + __nptl_death_event (); + } + } +@@ -642,19 +766,28 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, + that cares whether the thread count is correct. */ + atomic_increment (&__nptl_nthreads); + +- bool thread_ran = false; ++ /* Our local value of stopped_start and thread_ran can be accessed at ++ any time. The PD->stopped_start may only be accessed if we have ++ ownership of PD (see CONCURRENCY NOTES above). */ ++ bool stopped_start = false; bool thread_ran = false; + + /* Start the thread. */ + if (__glibc_unlikely (report_thread_creation (pd))) + { +- /* Create the thread. We always create the thread stopped +- so that it does not get far before we tell the debugger. */ +- retval = create_thread (pd, iattr, true, STACK_VARIABLES_ARGS, +- &thread_ran); ++ stopped_start = true; ++ ++ /* We always create the thread stopped at startup so we can ++ notify the debugger. */ ++ retval = create_thread (pd, iattr, &stopped_start, ++ STACK_VARIABLES_ARGS, &thread_ran); + if (retval == 0) + { +- /* create_thread should have set this so that the logic below can +- test it. */ ++ /* We retain ownership of PD until (a) (see CONCURRENCY NOTES ++ above). */ ++ ++ /* Assert stopped_start is true in both our local copy and the ++ PD copy. */ ++ assert (stopped_start); + assert (pd->stopped_start); + + /* Now fill in the information about the new thread in +@@ -671,26 +804,30 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, + pd, pd->nextevent) + != 0); + +- /* Now call the function which signals the event. */ ++ /* Now call the function which signals the event. See ++ CONCURRENCY NOTES for the nptl_db interface comments. */ + __nptl_create_event (); + } + } + else +- retval = create_thread (pd, iattr, false, STACK_VARIABLES_ARGS, +- &thread_ran); ++ retval = create_thread (pd, iattr, &stopped_start, ++ STACK_VARIABLES_ARGS, &thread_ran); + + if (__glibc_unlikely (retval != 0)) + { +- /* If thread creation "failed", that might mean that the thread got +- created and ran a little--short of running user code--but then +- create_thread cancelled it. In that case, the thread will do all +- its own cleanup just like a normal thread exit after a successful +- creation would do. */ +- + if (thread_ran) +- assert (pd->stopped_start); ++ /* State (c) or (d) and we may not have PD ownership (see ++ CONCURRENCY NOTES above). We can assert that STOPPED_START ++ must have been true because thread creation didn't fail, but ++ thread attribute setting did. */ ++ /* See bug 19511 which explains why doing nothing here is a ++ resource leak for a joinable thread. */ ++ assert (stopped_start); + else + { ++ /* State (e) and we have ownership of PD (see CONCURRENCY ++ NOTES above). */ ++ + /* Oops, we lied for a second. */ + atomic_decrement (&__nptl_nthreads); + +@@ -710,10 +847,14 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, + } + else + { +- if (pd->stopped_start) +- /* The thread blocked on this lock either because we're doing TD_CREATE +- event reporting, or for some other reason that create_thread chose. +- Now let it run free. */ ++ /* We don't know if we have PD ownership. Once we check the local ++ stopped_start we'll know if we're in state (a) or (b) (see ++ CONCURRENCY NOTES above). */ ++ if (stopped_start) ++ /* State (a), we own PD. The thread blocked on this lock either ++ because we're doing TD_CREATE event reporting, or for some ++ other reason that create_thread chose. Now let it run ++ free. */ + lll_unlock (pd->lock, LLL_PRIVATE); + + /* We now have for sure more than one thread. The main thread might +diff --git a/nptl/pthread_getschedparam.c b/nptl/pthread_getschedparam.c +index b887881baf..de71171a08 100644 +--- a/nptl/pthread_getschedparam.c ++++ b/nptl/pthread_getschedparam.c +@@ -35,6 +35,7 @@ __pthread_getschedparam (pthread_t threadid, int *policy, + + int result = 0; + ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ + lll_lock (pd->lock, LLL_PRIVATE); + + /* The library is responsible for maintaining the values at all +diff --git a/nptl/pthread_setschedparam.c b/nptl/pthread_setschedparam.c +index dfb52b9dbf..dcb520f1c8 100644 +--- a/nptl/pthread_setschedparam.c ++++ b/nptl/pthread_setschedparam.c +@@ -36,6 +36,7 @@ __pthread_setschedparam (pthread_t threadid, int policy, + + int result = 0; + ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ + lll_lock (pd->lock, LLL_PRIVATE); + + struct sched_param p; +diff --git a/nptl/pthread_setschedprio.c b/nptl/pthread_setschedprio.c +index cefc6481d6..8134b50560 100644 +--- a/nptl/pthread_setschedprio.c ++++ b/nptl/pthread_setschedprio.c +@@ -38,6 +38,7 @@ pthread_setschedprio (pthread_t threadid, int prio) + struct sched_param param; + param.sched_priority = prio; + ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ + lll_lock (pd->lock, LLL_PRIVATE); + + /* If the thread should have higher priority because of some +diff --git a/nptl/tpp.c b/nptl/tpp.c +index e175bf4d53..223bd6bbee 100644 +--- a/nptl/tpp.c ++++ b/nptl/tpp.c +@@ -114,6 +114,7 @@ __pthread_tpp_change_priority (int previous_prio, int new_prio) + if (priomax == newpriomax) + return 0; + ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ + lll_lock (self->lock, LLL_PRIVATE); + + tpp->priomax = newpriomax; +@@ -165,6 +166,7 @@ __pthread_current_priority (void) + + int result = 0; + ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ + lll_lock (self->lock, LLL_PRIVATE); + + if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) +diff --git a/nptl/tst-create-detached.c b/nptl/tst-create-detached.c +new file mode 100644 +index 0000000000..ea93e441c7 +--- /dev/null ++++ b/nptl/tst-create-detached.c +@@ -0,0 +1,137 @@ ++/* Bug 20116: Test rapid creation of detached threads. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see <http://www.gnu.org/licenses/>. */ ++ ++/* The goal of the test is to trigger a failure if the parent touches ++ any part of the thread descriptor after the detached thread has ++ exited. We test this by creating many detached threads with large ++ stacks. The stacks quickly fill the the stack cache and subsequent ++ threads will start to cause the thread stacks to be immediately ++ unmapped to satisfy the stack cache max. With the stacks being ++ unmapped the parent's read of any part of the thread descriptor will ++ trigger a segfault. That segfault is what we are trying to cause, ++ since any segfault is a defect in the implementation. */ ++ ++#include <pthread.h> ++#include <stdio.h> ++#include <errno.h> ++#include <unistd.h> ++#include <stdbool.h> ++#include <sys/resource.h> ++#include <support/xthread.h> ++ ++/* Number of threads to create. */ ++enum { threads_to_create = 100000 }; ++ ++/* Number of threads which should spawn other threads. */ ++enum { creator_threads = 2 }; ++ ++/* Counter of threads created so far. This is incremented by all the ++ running creator threads. */ ++static unsigned threads_created; ++ ++/* Thread callback which does nothing, so that the thread exits ++ immediatedly. */ ++static void * ++do_nothing (void *arg) ++{ ++ return NULL; ++} ++ ++/* Attribute indicating that the thread should be created in a detached ++ fashion. */ ++static pthread_attr_t detached; ++ ++/* Barrier to synchronize initialization. */ ++static pthread_barrier_t barrier; ++ ++static void * ++creator_thread (void *arg) ++{ ++ int ret; ++ xpthread_barrier_wait (&barrier); ++ ++ while (true) ++ { ++ pthread_t thr; ++ /* Thread creation will fail if the kernel does not free old ++ threads quickly enough, so we do not report errors. */ ++ ret = pthread_create (&thr, &detached, do_nothing, NULL); ++ if (ret == 0 && __atomic_add_fetch (&threads_created, 1, __ATOMIC_SEQ_CST) ++ >= threads_to_create) ++ break; ++ } ++ ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ /* Limit the size of the process, so that memory allocation will ++ fail without impacting the entire system. */ ++ { ++ struct rlimit limit; ++ if (getrlimit (RLIMIT_AS, &limit) != 0) ++ { ++ printf ("FAIL: getrlimit (RLIMIT_AS) failed: %m\n"); ++ return 1; ++ } ++ /* This limit, 800MB, is just a heuristic. Any value can be ++ picked. */ ++ long target = 800 * 1024 * 1024; ++ if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target) ++ { ++ limit.rlim_cur = target; ++ if (setrlimit (RLIMIT_AS, &limit) != 0) ++ { ++ printf ("FAIL: setrlimit (RLIMIT_AS) failed: %m\n"); ++ return 1; ++ } ++ } ++ } ++ ++ xpthread_attr_init (&detached); ++ ++ xpthread_attr_setdetachstate (&detached, PTHREAD_CREATE_DETACHED); ++ ++ /* A large thread stack seems beneficial for reproducing a race ++ condition in detached thread creation. The goal is to reach the ++ limit of the runtime thread stack cache such that the detached ++ thread's stack is unmapped after exit and causes a segfault when ++ the parent reads the thread descriptor data stored on the the ++ unmapped stack. */ ++ xpthread_attr_setstacksize (&detached, 16 * 1024 * 1024); ++ ++ xpthread_barrier_init (&barrier, NULL, creator_threads); ++ ++ pthread_t threads[creator_threads]; ++ ++ for (int i = 0; i < creator_threads; ++i) ++ threads[i] = xpthread_create (NULL, creator_thread, NULL); ++ ++ for (int i = 0; i < creator_threads; ++i) ++ xpthread_join (threads[i]); ++ ++ xpthread_attr_destroy (&detached); ++ ++ xpthread_barrier_destroy (&barrier); ++ ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/sysdeps/nacl/createthread.c b/sysdeps/nacl/createthread.c +index 7b571c34e2..5465558cc1 100644 +--- a/sysdeps/nacl/createthread.c ++++ b/sysdeps/nacl/createthread.c +@@ -32,15 +32,13 @@ static void start_thread (void) __attribute__ ((noreturn)); + + static int + create_thread (struct pthread *pd, const struct pthread_attr *attr, +- bool stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) ++ bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) + { + pd->tid = __nacl_get_tid (pd); + +- pd->stopped_start = stopped_start; +- if (__glibc_unlikely (stopped_start)) +- /* We make sure the thread does not run far by forcing it to get a +- lock. We lock it here too so that the new thread cannot continue +- until we tell it to. */ ++ pd->stopped_start = *stopped_start; ++ if (__glibc_unlikely (*stopped_start)) ++ /* See CONCURRENCY NOTES in nptl/pthread_create.c. */ + lll_lock (pd->lock, LLL_PRIVATE); + + TLS_DEFINE_INIT_TP (tp, pd); +diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c +index 6d32cece48..66ddae61d4 100644 +--- a/sysdeps/unix/sysv/linux/createthread.c ++++ b/sysdeps/unix/sysv/linux/createthread.c +@@ -46,7 +46,7 @@ static int start_thread (void *arg) __attribute__ ((noreturn)); + + static int + create_thread (struct pthread *pd, const struct pthread_attr *attr, +- bool stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) ++ bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) + { + /* Determine whether the newly created threads has to be started + stopped since we have to set the scheduling parameters or set the +@@ -54,13 +54,11 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, + if (attr != NULL + && (__glibc_unlikely (attr->cpuset != NULL) + || __glibc_unlikely ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))) +- stopped_start = true; ++ *stopped_start = true; + +- pd->stopped_start = stopped_start; +- if (__glibc_unlikely (stopped_start)) +- /* We make sure the thread does not run far by forcing it to get a +- lock. We lock it here too so that the new thread cannot continue +- until we tell it to. */ ++ pd->stopped_start = *stopped_start; ++ if (__glibc_unlikely (*stopped_start)) ++ /* See CONCURRENCY NOTES in nptl/pthread_creat.c. */ + lll_lock (pd->lock, LLL_PRIVATE); + + /* We rely heavily on various flags the CLONE function understands: +@@ -117,7 +115,7 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, + /* Set the affinity mask if necessary. */ + if (attr->cpuset != NULL) + { +- assert (stopped_start); ++ assert (*stopped_start); + + res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, + attr->cpusetsize, attr->cpuset); +@@ -140,7 +138,7 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, + /* Set the scheduling parameters. */ + if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0) + { +- assert (stopped_start); ++ assert (*stopped_start); + + res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid, + pd->schedpolicy, &pd->schedparam); +-- +2.11.0 + diff --git a/meta-agl-bsp/meta-core/recipes-core/glibc/glibc_2.24.bbappend b/meta-agl-bsp/meta-core/recipes-core/glibc/glibc_2.24.bbappend new file mode 100644 index 000000000..a9f2a238d --- /dev/null +++ b/meta-agl-bsp/meta-core/recipes-core/glibc/glibc_2.24.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +# include fix for CVE-2017-1000366 +SRCREV = "86ac4a78a9218d1e1dcfbacc6f7d09957c1fe3a4"
\ No newline at end of file |