summaryrefslogtreecommitdiffstats
path: root/meta-agl-bsp/meta-core
diff options
context:
space:
mode:
Diffstat (limited to 'meta-agl-bsp/meta-core')
-rw-r--r--meta-agl-bsp/meta-core/recipes-core/glibc/files/0028-Bug-20116-Fix-use-after-free-in-pthread_create.patch637
-rw-r--r--meta-agl-bsp/meta-core/recipes-core/glibc/glibc_2.24.bbappend4
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