diff --git a/SOURCES/glibc-rh1032435.patch b/SOURCES/glibc-rh1032435.patch
index ed5cc92..694bec2 100644
--- a/SOURCES/glibc-rh1032435.patch
+++ b/SOURCES/glibc-rh1032435.patch
@@ -17,11 +17,30 @@ Date:   Wed Oct 30 16:13:37 2013 +0530
     wrap around fgets that calls it multiple times with int sizes if
     necessary.
 
-diff --git glibc-2.17-c758a686/nss/nss_files/files-XXX.c glibc-2.17-c758a686/nss/nss_files/files-XXX.c
-index 082d1ea..b62208c 100644
---- glibc-2.17-c758a686/nss/nss_files/files-XXX.c
-+++ glibc-2.17-c758a686/nss/nss_files/files-XXX.c
-@@ -179,8 +179,51 @@ CONCAT(_nss_files_end,ENTNAME) (void)
+(The previous commit fixes upstream bug 16071.)
+
+commit ac60763eac3d43b7234dd21286ad3ec3f17957fc
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Mon Jun 23 10:24:45 2014 +0200
+
+    Don't ignore too long lines in nss_files (BZ #17079)
+
+commit e07aabba73ea62e7dfa0512507c92efb851fbdbe
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Sep 22 13:20:18 2015 +0200
+
+    Add test case for bug 18287
+
+commit 90fa42a1d7b78de0d75f7e3af362275b2abe807f
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Sep 22 13:40:17 2015 +0200
+
+    Test in commit e07aabba73ea62e7dfa0512507c92efb851fbdbe is for bug 17079
+
+diff -u b/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c
+--- b/nss/nss_files/files-XXX.c
++++ b/nss/nss_files/files-XXX.c
+@@ -179,8 +179,53 @@
    return NSS_STATUS_SUCCESS;
  }
  
@@ -45,10 +64,12 @@ index 082d1ea..b62208c 100644
 +    {
 +      int curlen = ((remaining_len > (size_t) INT_MAX) ? INT_MAX
 +		    : remaining_len);
-+      char *p = fgets_unlocked (curbuf, curlen, stream);
 +
++      /* Terminate the line so that we can test for overflow.  */
 +      ((unsigned char *) curbuf)[curlen - 1] = 0xff;
 +
++      char *p = fgets_unlocked (curbuf, curlen, stream);
++
 +      /* EOF or read error.  */
 +      if (p == NULL)
 +        return gcr_error;
@@ -74,7 +95,7 @@ index 082d1ea..b62208c 100644
  static enum nss_status
  internal_getent (struct STRUCTURE *result,
  		 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
-@@ -188,7 +231,7 @@ internal_getent (struct STRUCTURE *result,
+@@ -188,7 +233,7 @@
  {
    char *p;
    struct parser_data *data = (void *) buffer;
@@ -83,7 +104,7 @@ index 082d1ea..b62208c 100644
    int parse_result;
  
    if (buflen < sizeof *data + 2)
-@@ -200,17 +243,16 @@ internal_getent (struct STRUCTURE *result,
+@@ -200,17 +245,16 @@
  
    do
      {
@@ -105,7 +126,7 @@ index 082d1ea..b62208c 100644
  	{
  	  /* The line is too long.  Give the user the opportunity to
  	     enlarge the buffer.  */
-@@ -219,7 +261,8 @@ internal_getent (struct STRUCTURE *result,
+@@ -219,7 +263,8 @@
  	  return NSS_STATUS_TRYAGAIN;
  	}
  
@@ -115,3 +136,255 @@ index 082d1ea..b62208c 100644
        while (isspace (*p))
  	++p;
      }
+
+diff a/nss/bug17079.c b/nss/bug17079.c
+--- /dev/null
++++ b/nss/bug17079.c
+@@ -0,0 +1,236 @@
++/* Test for bug 17079: heap overflow in NSS with small buffers.
++   Copyright (C) 2015 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; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <pwd.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++/* Check if two passwd structs contain the same data.  */
++static bool
++equal (const struct passwd *a, const struct passwd *b)
++{
++  return strcmp (a->pw_name, b->pw_name) == 0
++    && strcmp (a->pw_passwd, b->pw_passwd) == 0
++    && a->pw_uid == b->pw_uid
++    && a->pw_gid == b->pw_gid
++    && strcmp (a->pw_gecos, b->pw_gecos) == 0
++    && strcmp (a->pw_dir, b->pw_dir) == 0
++    && strcmp (a->pw_shell, b->pw_shell) == 0;
++}
++
++enum { MAX_TEST_ITEMS = 10 };
++static struct passwd test_items[MAX_TEST_ITEMS];
++static int test_count;
++
++/* Initialize test_items and test_count above, with data from the
++   passwd database.  */
++static bool
++init_test_items (void)
++{
++  setpwent ();
++  do
++    {
++      struct passwd *pwd = getpwent ();
++      if (pwd == NULL)
++        break;
++      struct passwd *target = test_items + test_count;
++      target->pw_name = strdup (pwd->pw_name);
++      target->pw_passwd = strdup (pwd->pw_passwd);
++      target->pw_uid = pwd->pw_uid;
++      target->pw_gid = pwd->pw_gid;
++      target->pw_gecos = strdup (pwd->pw_gecos);
++      target->pw_dir = strdup (pwd->pw_dir);
++      target->pw_shell = strdup (pwd->pw_shell);
++    }
++  while (++test_count < MAX_TEST_ITEMS);
++  endpwent ();
++
++  /* Filter out those test items which cannot be looked up by name or
++     UID.  */
++  bool found = false;
++  for (int i = 0; i < test_count; ++i)
++    {
++      struct passwd *pwd1 = getpwnam (test_items[i].pw_name);
++      struct passwd *pwd2 = getpwuid (test_items[i].pw_uid);
++      if (pwd1 == NULL || !equal (pwd1, test_items + i)
++          || pwd2 == NULL || !equal (pwd2, test_items + i))
++        test_items[i].pw_name = NULL;
++      else
++        found = true;
++    }
++
++  if (!found)
++    puts ("error: no accounts found which can be looked up by name and UID.");
++  return found;
++}
++
++/* Set to true if an error is encountered.  */
++static bool errors;
++
++/* Return true if the padding has not been tampered with.  */
++static bool
++check_padding (char *buffer, size_t size, char pad)
++{
++  char *end = buffer + size;
++  while (buffer < end)
++    {
++      if (*buffer != pad)
++        return false;
++      ++buffer;
++    }
++  return true;
++}
++
++/* Test one buffer size and padding combination.  */
++static void
++test_one (const struct passwd *item, size_t buffer_size,
++           char pad, size_t padding_size)
++{
++  char *buffer = malloc (buffer_size + padding_size);
++  if (buffer == NULL)
++    {
++      puts ("error: malloc failure");
++      errors = true;
++      return;
++    }
++
++  struct passwd pwd;
++  struct passwd *result;
++  int ret;
++
++  /* Test getpwname_r.  */
++  memset (buffer, pad, buffer_size + padding_size);
++  pwd = (struct passwd) {};
++  ret = getpwnam_r (item->pw_name, &pwd, buffer, buffer_size, &result);
++  if (!check_padding (buffer + buffer_size, padding_size, pad))
++    {
++      printf ("error: padding change: "
++              "name \"%s\", buffer size %zu, padding size %zu, pad 0x%02x\n",
++              item->pw_name, buffer_size, padding_size, (unsigned char) pad);
++      errors = true;
++    }
++  if (ret == 0)
++    {
++      if (result == NULL)
++        {
++          printf ("error: no data: name \"%s\", buffer size %zu\n",
++                  item->pw_name, buffer_size);
++          errors = true;
++        }
++      else if (!equal (item, result))
++        {
++          printf ("error: lookup mismatch: name \"%s\", buffer size %zu\n",
++                  item->pw_name, buffer_size);
++          errors = true;
++        }
++    }
++  else if (ret != ERANGE)
++    {
++      errno = ret;
++      printf ("error: lookup failure for name \"%s\": %m (%d)\n",
++              item->pw_name, ret);
++      errors = true;
++    }
++
++  /* Test getpwuid_r.  */
++  memset (buffer, pad, buffer_size + padding_size);
++  pwd = (struct passwd) {};
++  ret = getpwuid_r (item->pw_uid, &pwd, buffer, buffer_size, &result);
++  if (!check_padding (buffer + buffer_size, padding_size, pad))
++    {
++      printf ("error: padding change: "
++              "UID %ld, buffer size %zu, padding size %zu, pad 0x%02x\n",
++              (long) item->pw_uid, buffer_size, padding_size,
++              (unsigned char) pad);
++      errors = true;
++    }
++  if (ret == 0)
++    {
++      if (result == NULL)
++        {
++          printf ("error: no data: UID %ld, buffer size %zu\n",
++                  (long) item->pw_uid, buffer_size);
++          errors = true;
++        }
++      else if (!equal (item, result))
++        {
++          printf ("error: lookup mismatch: UID %ld, buffer size %zu\n",
++                  (long) item->pw_uid, buffer_size);
++          errors = true;
++        }
++    }
++  else if (ret != ERANGE)
++    {
++      errno = ret;
++      printf ("error: lookup failure for UID \"%ld\": %m (%d)\n",
++              (long) item->pw_uid, ret);
++      errors = true;
++    }
++
++  free (buffer);
++}
++
++/* Test one buffer size with different paddings.  */
++static void
++test_buffer_size (size_t buffer_size)
++{
++  for (int i = 0; i < test_count; ++i)
++    for (size_t padding_size = 0; padding_size < 3; ++padding_size)
++      {
++        test_one (test_items + i, buffer_size, '\0', padding_size);
++        if (padding_size > 0)
++          {
++            test_one (test_items + i, buffer_size, ':', padding_size);
++            test_one (test_items + i, buffer_size, '\n', padding_size);
++            test_one (test_items + i, buffer_size, '\xff', padding_size);
++            test_one (test_items + i, buffer_size, '@', padding_size);
++          }
++      }
++}
++
++int
++do_test (void)
++{
++  if (!init_test_items ())
++    return 1;
++  printf ("info: %d test items\n", test_count);
++
++  for (size_t buffer_size = 0; buffer_size <= 65; ++buffer_size)
++    test_buffer_size (buffer_size);
++  for (size_t buffer_size = 64 + 4; buffer_size < 256; buffer_size += 4)
++    test_buffer_size (buffer_size);
++  test_buffer_size (255);
++  test_buffer_size (257);
++  for (size_t buffer_size = 256; buffer_size < 512; buffer_size += 8)
++    test_buffer_size (buffer_size);
++  test_buffer_size (511);
++  test_buffer_size (513);
++  test_buffer_size (1024);
++  test_buffer_size (2048);
++
++  if (errors)
++    return 1;
++  else
++    return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff a/nss/Makefile b/nss/Makefile
+--- a/nss/Makefile
++++ b/nss/Makefile
+@@ -39,6 +39,6 @@
+ extra-objs		+= $(makedb-modules:=.o)
+ 
+-tests			= test-netdb tst-nss-test1
++tests			= test-netdb tst-nss-test1 bug17079
+ xtests			= bug-erange
+ 
+ include ../Makeconfig
diff --git a/SOURCES/glibc-rh1165192.patch b/SOURCES/glibc-rh1165192.patch
index 41e2591..488ac49 100644
--- a/SOURCES/glibc-rh1165192.patch
+++ b/SOURCES/glibc-rh1165192.patch
@@ -16,8 +16,8 @@ diff -up glibc-2.17-c758a686/nss/Makefile.rh1165192 glibc-2.17-c758a686/nss/Make
  makedb-modules = xmalloc hash-string
  extra-objs		+= $(makedb-modules:=.o)
  
--tests			= test-netdb tst-nss-test1
-+tests			= test-netdb tst-nss-test1 tst-nss-getpwent
+-tests			= test-netdb tst-nss-test1 bug17079
++tests			= test-netdb tst-nss-test1 bug17079 tst-nss-getpwent
  xtests			= bug-erange
  
  include ../Makeconfig
diff --git a/SOURCES/glibc-rh1183545.patch b/SOURCES/glibc-rh1183545.patch
index dbd87ab..a9ec106 100644
--- a/SOURCES/glibc-rh1183545.patch
+++ b/SOURCES/glibc-rh1183545.patch
@@ -12,8 +12,8 @@ index 449a258..553eafa 100644
  makedb-modules = xmalloc hash-string
  extra-objs		+= $(makedb-modules:=.o)
  
--tests			= test-netdb tst-nss-test1 tst-nss-getpwent
-+tests			= test-netdb tst-nss-test1 tst-nss-getpwent \
+-tests			= test-netdb tst-nss-test1 bug17079 tst-nss-getpwent
++tests			= test-netdb tst-nss-test1 bug17079 tst-nss-getpwent \
 +			 test-digits-dots
  xtests			= bug-erange
  
diff --git a/SOURCES/glibc-rh1249102.patch b/SOURCES/glibc-rh1249102.patch
new file mode 100644
index 0000000..eb83b2e
--- /dev/null
+++ b/SOURCES/glibc-rh1249102.patch
@@ -0,0 +1,26 @@
+commit a53fbd8e6cd2f69bdfa3431d616a5f332aea6664
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date:   Tue Jul 29 13:56:44 2014 -0500
+
+    PowerPC: Fix gprof entry point for LE
+    
+    This patch fixes the ELFv2 gprof entry point since the ABI
+    does not define function descriptors.  It fixes BZ#17213.
+diff --git a/sysdeps/powerpc/powerpc64/entry.h b/sysdeps/powerpc/powerpc64/entry.h
+index 76ead1d..30553c1 100644
+--- a/sysdeps/powerpc/powerpc64/entry.h
++++ b/sysdeps/powerpc/powerpc64/entry.h
+@@ -23,6 +23,7 @@ extern void _start (void);
+ 
+ #define ENTRY_POINT _start
+ 
++#if _CALL_ELF != 2
+ /* We have to provide a special declaration.  */
+ #define ENTRY_POINT_DECL(class) class void _start (void);
+ 
+@@ -33,3 +34,4 @@ extern void _start (void);
+ #define TEXT_START \
+   ({ extern unsigned long int _start_as_data[] asm ("_start");  \
+      _start_as_data[0]; })
++#endif
+
diff --git a/SOURCES/glibc-rh1284959-1.patch b/SOURCES/glibc-rh1284959-1.patch
new file mode 100644
index 0000000..cdb1585
--- /dev/null
+++ b/SOURCES/glibc-rh1284959-1.patch
@@ -0,0 +1,238 @@
+Description: Makes trimming work consistently across arenas.
+Author: Mel Gorman <mgorman@suse.de>
+Origin: git://sourceware.org/git/glibc.git
+Bug-RHEL: N/A
+Bug-Fedora: N/A
+Bug-Upstream: #17195
+Upstream status: committed
+
+Part of commit 8a35c3fe122d49ba76dff815b3537affb5a50b45 is also included
+to allow the use of ALIGN_UP within malloc/arena.c.
+
+commit c26efef9798914e208329c0e8c3c73bb1135d9e3
+Author: Mel Gorman <mgorman@suse.de>
+Date:   Thu Apr 2 12:14:14 2015 +0530
+
+    malloc: Consistently apply trim_threshold to all heaps [BZ #17195]
+    
+    Trimming heaps is a balance between saving memory and the system overhead
+    required to update page tables and discard allocated pages. The malloc
+    option M_TRIM_THRESHOLD is a tunable that users are meant to use to decide
+    where this balance point is but it is only applied to the main arena.
+    
+    For scalability reasons, glibc malloc has per-thread heaps but these are
+    shrunk with madvise() if there is one page free at the top of the heap.
+    In some circumstances this can lead to high system overhead if a thread
+    has a control flow like
+    
+        while (data_to_process) {
+            buf = malloc(large_size);
+            do_stuff();
+            free(buf);
+        }
+    
+    For a large size, the free() will call madvise (pagetable teardown, page
+    free and TLB flush) every time followed immediately by a malloc (fault,
+    kernel page alloc, zeroing and charge accounting). The kernel overhead
+    can dominate such a workload.
+    
+    This patch allows the user to tune when madvise gets called by applying
+    the trim threshold to the per-thread heaps and using similar logic to the
+    main arena when deciding whether to shrink. Alternatively if the dynamic
+    brk/mmap threshold gets adjusted then the new values will be obeyed by
+    the per-thread heaps.
+    
+    Bug 17195 was a test case motivated by a problem encountered in scientific
+    applications written in python that performance badly due to high page fault
+    overhead. The basic operation of such a program was posted by Julian Taylor
+    https://sourceware.org/ml/libc-alpha/2015-02/msg00373.html
+    
+    With this patch applied, the overhead is eliminated. All numbers in this
+    report are in seconds and were recorded by running Julian's program 30
+    times.
+    
+    pyarray
+                                     glibc               madvise
+                                      2.21                    v2
+    System  min             1.81 (  0.00%)        0.00 (100.00%)
+    System  mean            1.93 (  0.00%)        0.02 ( 99.20%)
+    System  stddev          0.06 (  0.00%)        0.01 ( 88.99%)
+    System  max             2.06 (  0.00%)        0.03 ( 98.54%)
+    Elapsed min             3.26 (  0.00%)        2.37 ( 27.30%)
+    Elapsed mean            3.39 (  0.00%)        2.41 ( 28.84%)
+    Elapsed stddev          0.14 (  0.00%)        0.02 ( 82.73%)
+    Elapsed max             4.05 (  0.00%)        2.47 ( 39.01%)
+    
+                   glibc     madvise
+                    2.21          v2
+    User          141.86      142.28
+    System         57.94        0.60
+    Elapsed       102.02       72.66
+    
+    Note that almost a minutes worth of system time is eliminted and the
+    program completes 28% faster on average.
+    
+    To illustrate the problem without python this is a basic test-case for
+    the worst case scenario where every free is a madvise followed by a an alloc
+    
+    /* gcc bench-free.c -lpthread -o bench-free */
+    static int num = 1024;
+    
+    void __attribute__((noinline,noclone)) dostuff (void *p)
+    {
+    }
+    
+    void *worker (void *data)
+    {
+      int i;
+    
+      for (i = num; i--;)
+        {
+          void *m = malloc (48*4096);
+          dostuff (m);
+          free (m);
+        }
+    
+      return NULL;
+    }
+    
+    int main()
+    {
+      int i;
+      pthread_t t;
+      void *ret;
+      if (pthread_create (&t, NULL, worker, NULL))
+        exit (2);
+      if (pthread_join (t, &ret))
+        exit (3);
+      return 0;
+    }
+    
+    Before the patch, this resulted in 1024 calls to madvise. With the patch applied,
+    madvise is called twice because the default trim threshold is high enough to avoid
+    this.
+    
+    This a more complex case where there is a mix of frees. It's simply a different worker
+    function for the test case above
+    
+    void *worker (void *data)
+    {
+      int i;
+      int j = 0;
+      void *free_index[num];
+    
+      for (i = num; i--;)
+        {
+          void *m = malloc ((i % 58) *4096);
+          dostuff (m);
+          if (i % 2 == 0) {
+            free (m);
+          } else {
+            free_index[j++] = m;
+          }
+        }
+      for (; j >= 0; j--)
+        {
+          free(free_index[j]);
+        }
+    
+      return NULL;
+    }
+    
+    glibc 2.21 calls malloc 90305 times but with the patch applied, it's
+    called 13438. Increasing the trim threshold will decrease the number of
+    times it's called with the option of eliminating the overhead.
+    
+    ebizzy is meant to generate a workload resembling common web application
+    server workloads. It is threaded with a large working set that at its core
+    has an allocation, do_stuff, free loop that also hits this case. The primary
+    metric of the benchmark is records processed per second. This is running on
+    my desktop which is a single socket machine with an I7-4770 and 8 cores.
+    Each thread count was run for 30 seconds. It was only run once as the
+    performance difference is so high that the variation is insignificant.
+    
+                    glibc 2.21              patch
+    threads 1            10230              44114
+    threads 2            19153              84925
+    threads 4            34295             134569
+    threads 8            51007             183387
+    
+    Note that the saving happens to be a concidence as the size allocated
+    by ebizzy was less than the default threshold. If a different number of
+    chunks were specified then it may also be necessary to tune the threshold
+    to compensate
+    
+    This is roughly quadrupling the performance of this benchmark. The difference in
+    system CPU usage illustrates why.
+    
+    ebizzy running 1 thread with glibc 2.21
+    10230 records/s 306904
+    real 30.00 s
+    user  7.47 s
+    sys  22.49 s
+    
+    22.49 seconds was spent in the kernel for a workload runinng 30 seconds. With the
+    patch applied
+    
+    ebizzy running 1 thread with patch applied
+    44126 records/s 1323792
+    real 30.00 s
+    user 29.97 s
+    sys   0.00 s
+    
+    system CPU usage was zero with the patch applied. strace shows that glibc
+    running this workload calls madvise approximately 9000 times a second. With
+    the patch applied madvise was called twice during the workload (or 0.06
+    times per second).
+    
+    2015-02-10  Mel Gorman  <mgorman@suse.de>
+    
+      [BZ #17195]
+      * malloc/arena.c (free): Apply trim threshold to per-thread heaps
+        as well as the main arena.
+
+Index: glibc-2.17-c758a686/malloc/arena.c
+===================================================================
+--- glibc-2.17-c758a686.orig/malloc/arena.c
++++ glibc-2.17-c758a686/malloc/arena.c
+@@ -661,7 +661,7 @@ heap_trim(heap_info *heap, size_t pad)
+   unsigned long pagesz = GLRO(dl_pagesize);
+   mchunkptr top_chunk = top(ar_ptr), p, bck, fwd;
+   heap_info *prev_heap;
+-  long new_size, top_size, extra, prev_size, misalign;
++  long new_size, top_size, top_area, extra, prev_size, misalign;
+ 
+   /* Can this heap go away completely? */
+   while(top_chunk == chunk_at_offset(heap, sizeof(*heap))) {
+@@ -695,9 +695,16 @@ heap_trim(heap_info *heap, size_t pad)
+     set_head(top_chunk, new_size | PREV_INUSE);
+     /*check_chunk(ar_ptr, top_chunk);*/
+   }
++
++  /* Uses similar logic for per-thread arenas as the main arena with systrim
++     by preserving the top pad and at least a page.  */
+   top_size = chunksize(top_chunk);
+-  extra = (top_size - pad - MINSIZE - 1) & ~(pagesz - 1);
+-  if(extra < (long)pagesz)
++  top_area = top_size - MINSIZE - 1;
++  if (top_area <= pad)
++    return 0;
++
++  extra = ALIGN_DOWN(top_area - pad, pagesz);
++  if ((unsigned long) extra < mp_.trim_threshold)
+     return 0;
+   /* Try to shrink. */
+   if(shrink_heap(heap, extra) != 0)
+Index: glibc-2.17-c758a686/malloc/malloc.c
+===================================================================
+--- glibc-2.17-c758a686.orig/malloc/malloc.c
++++ glibc-2.17-c758a686/malloc/malloc.c
+@@ -236,6 +236,8 @@
+ /* For va_arg, va_start, va_end.  */
+ #include <stdarg.h>
+ 
++/* For ALIGN_UP.  */
++#include <libc-internal.h>
+ 
+ /*
+   Debugging:
diff --git a/SOURCES/glibc-rh1284959-2.patch b/SOURCES/glibc-rh1284959-2.patch
new file mode 100644
index 0000000..9d45fb4
--- /dev/null
+++ b/SOURCES/glibc-rh1284959-2.patch
@@ -0,0 +1,63 @@
+Description: Make trimming logic consistent.
+Author: Carlos O'Donell
+Origin: git://sourceware.org/git/glibc.git
+Bug-RHEL: N/A
+Bug-Fedora: N/A
+Bug-Upstream: #17195
+Upstream status: committed
+
+commit e4bc326dbbf7328775fe7dd39de1178821363e0a
+Author: Carlos O'Donell <carlos@systemhalted.org>
+Date:   Wed Oct 7 22:21:36 2015 -0400
+
+    malloc: Consistently apply trim_threshold to all heaps (Bug 17195)
+    
+    In the per-thread arenas we apply trim_threshold-based checks
+    to the extra space between the pad and the top_area. This isn't
+    quite accurate and instead we should be harmonizing with the way
+    in which trim_treshold is applied everywhere else like sysrtim
+    and _int_free. The trimming check should be based on the size of
+    the top chunk and only the size of the top chunk. The following
+    patch harmonizes the trimming and make it consistent for the main
+    arena and thread arenas.
+    
+    In the old code a large padding request might have meant that
+    trimming was not triggered. Now trimming is considered first based
+    on the chunk, then the pad is subtracted, and the remainder trimmed.
+    This is how all the other trimmings operate. I didn't measure the
+    performance difference of this change because it corrects what I
+    consider to be a behavioural anomaly. We'll need some profile driven
+    optimization to make this code better, and even there Ondrej and
+    others have better ideas on how to speedup malloc.
+    
+    Tested on x86_64 with no regressions. Already reviewed by Siddhesh
+    Poyarekar and Mel Gorman here and discussed here:
+    https://sourceware.org/ml/libc-alpha/2015-05/msg00002.html
+
+Index: glibc-2.17-c758a686/malloc/arena.c
+===================================================================
+--- glibc-2.17-c758a686.orig/malloc/arena.c
++++ glibc-2.17-c758a686/malloc/arena.c
+@@ -697,14 +697,20 @@ heap_trim(heap_info *heap, size_t pad)
+   }
+ 
+   /* Uses similar logic for per-thread arenas as the main arena with systrim
+-     by preserving the top pad and at least a page.  */
++     and _int_free by preserving the top pad and rounding down to the nearest
++     page.  */
+   top_size = chunksize(top_chunk);
++  if ((unsigned long)(top_size) <
++      (unsigned long)(mp_.trim_threshold))
++    return 0;
++
+   top_area = top_size - MINSIZE - 1;
+   if (top_area <= pad)
+     return 0;
+ 
++  /* Release in pagesize units and round down to the nearest page.  */
+   extra = ALIGN_DOWN(top_area - pad, pagesz);
+-  if ((unsigned long) extra < mp_.trim_threshold)
++  if (extra == 0)
+     return 0;
+   /* Try to shrink. */
+   if(shrink_heap(heap, extra) != 0)
diff --git a/SOURCES/glibc-rh1284959-3.patch b/SOURCES/glibc-rh1284959-3.patch
new file mode 100644
index 0000000..4de0130
--- /dev/null
+++ b/SOURCES/glibc-rh1284959-3.patch
@@ -0,0 +1,52 @@
+Short description: Don't corrupt heap if top chunk is MINSIZE.
+Author(s): Mel Gorman <mgorman@suse.de>
+Origin: git://sourceware.org/git/glibc.git
+Bug-RHEL: N/A
+Bug-Fedora: N/A
+Bug-Upstream: #18502
+Upstream status: committed
+
+commit f8ef472c0ff4644445ec716036d31430b4fa4bab
+Author: Mel Gorman <mgorman@suse.de>
+Date:   Mon Jun 8 13:36:13 2015 +0100
+
+    malloc: Do not corrupt the top of a threaded heap if top chunk is MINSIZE [BZ #18502]
+    
+    mksquashfs was reported in openSUSE to be causing segmentation faults when
+    creating installation images. Testing showed that mksquashfs sometimes
+    failed and could be reproduced within 10 attempts. The core dump looked
+    like the heap top was corrupted and was pointing to an unmapped area. In
+    other cases, this has been due to an application corrupting glibc structures
+    but mksquashfs appears to be fine in this regard.
+    
+    The problem is that heap_trim is "growing" the top into unmapped space.
+    If the top chunk == MINSIZE then top_area is -1 and this check does not
+    behave as expected due to a signed/unsigned comparison
+    
+      if (top_area <= pad)
+        return 0;
+    
+    The next calculation extra = ALIGN_DOWN(top_area - pad, pagesz) calculates
+    extra as a negative number which also is unnoticed due to a signed/unsigned
+    comparison. We then call shrink_heap(heap, negative_number) which crashes
+    later. This patch adds a simple check against MINSIZE to make sure extra
+    does not become negative. It adds a cast to hint to the reader that this
+    is a signed vs unsigned issue.
+    
+    Without the patch, mksquash fails within 10 attempts. With it applied, it
+    completed 1000 times without error. The standard test suite "make check"
+    showed no changes in the summary of test results.
+
+Index: glibc-2.17-c758a686/malloc/arena.c
+===================================================================
+--- glibc-2.17-c758a686.orig/malloc/arena.c
++++ glibc-2.17-c758a686/malloc/arena.c
+@@ -705,7 +705,7 @@ heap_trim(heap_info *heap, size_t pad)
+     return 0;
+ 
+   top_area = top_size - MINSIZE - 1;
+-  if (top_area <= pad)
++  if (top_area < 0 || (size_t) top_area <= pad)
+     return 0;
+ 
+   /* Release in pagesize units and round down to the nearest page.  */
diff --git a/SOURCES/glibc-rh1293976-2.patch b/SOURCES/glibc-rh1293976-2.patch
new file mode 100644
index 0000000..e5656b7
--- /dev/null
+++ b/SOURCES/glibc-rh1293976-2.patch
@@ -0,0 +1,557 @@
+Short description: malloc: Test various special cases related to allocation failures
+Author(s): Florian Weimer <fweimer@redhat.com>
+Origin: git://sourceware.org/git/glibc.git
+Bug-RHEL: #1296453 (rhel-7.2.z),  #1293976 (rhel-7.3), #1256285 (SRT)
+Bug-Fedora: NA
+Bug-Upstream: NA
+Upstream status: committed
+#
+# commit 1bd5483e104c8bde6e61dc5e3f8a848bc861872d
+# Author: Florian Weimer <fweimer@redhat.com>
+# Date:   Tue Dec 29 20:32:35 2015 +0100
+# 
+#     malloc: Test various special cases related to allocation failures
+#     
+#     This test case exercises unusual code paths in allocation functions,
+#     related to allocation failures.  Specifically, the test can reveal
+#     the following bugs:
+#     
+#     (a) calloc returns non-zero memory on fallback to sysmalloc.
+#     (b) calloc can self-deadlock because it fails to release
+#         the arena lock on certain allocation failures.
+#     (c) pvalloc can dereference a NULL arena pointer.
+#     
+#     (a) and (b) appear specific to a faulty downstream backport.
+#     (c) was fixed as part of commit 10ad46bc6526edc5c7afcc57112da96917ff3629.
+#     
+#     The test for (a) was inspired by a reproducer supplied by Jeff Layton.
+# 
+Index: glibc-2.17-c758a686/malloc/Makefile
+===================================================================
+--- glibc-2.17-c758a686.orig/malloc/Makefile
++++ glibc-2.17-c758a686/malloc/Makefile
+@@ -20,13 +20,16 @@
+ #
+ subdir	:= malloc
+ 
++include ../Makeconfig
++
+ all:
+ 
+ dist-headers := malloc.h
+ headers := $(dist-headers) obstack.h mcheck.h
+ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+ 	 tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
+-	 tst-malloc-usable tst-malloc-backtrace
++	 tst-malloc-usable tst-malloc-backtrace \
++	 tst-malloc-thread-fail
+ test-srcs = tst-mtrace
+ 
+ routines = malloc morecore mcheck mtrace obstack
+@@ -43,6 +46,8 @@ libmemusage-inhibit-o = $(filter-out .os
+ 
+ $(objpfx)tst-malloc-backtrace: $(common-objpfx)nptl/libpthread.so \
+ 			       $(common-objpfx)nptl/libpthread_nonshared.a
++$(objpfx)tst-malloc-thread-fail: $(common-objpfx)nptl/libpthread.so \
++			       $(common-objpfx)nptl/libpthread_nonshared.a
+ 
+ # These should be removed by `make clean'.
+ extra-objs = mcheck-init.o libmcheck.a
+@@ -50,8 +55,6 @@ extra-objs = mcheck-init.o libmcheck.a
+ # Include the cleanup handler.
+ aux := set-freeres thread-freeres
+ 
+-include ../Makeconfig
+-
+ CPPFLAGS-memusagestat = -DNOT_IN_libc
+ 
+ # The Perl script to analyze the output of the mtrace functions.
+Index: glibc-2.17-c758a686/malloc/tst-malloc-thread-fail.c
+===================================================================
+--- /dev/null
++++ glibc-2.17-c758a686/malloc/tst-malloc-thread-fail.c
+@@ -0,0 +1,468 @@
++/* Test allocation function behavior on allocation failure.
++   Copyright (C) 2015 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/>.  */
++
++/* This test case attempts to trigger various unusual conditions
++   related to allocation failures, notably switching to a different
++   arena, and falling back to mmap (via sysmalloc).  */
++
++#include <errno.h>
++#include <malloc.h>
++#include <pthread.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/resource.h>
++#include <sys/wait.h>
++#include <unistd.h>
++#include <stddef.h>
++
++/* This mirrors the C11 max_align_t type provided by GCC, but it is
++   also available in C99 mode.  The aligned attributes are required
++   because some ABIs have reduced alignment requirements for struct
++   and union members.  */
++typedef struct {
++  long long ll __attribute__ ((__aligned__ (__alignof__ (long long))));
++  long double ld __attribute__ ((__aligned__ (__alignof__ (long double))));
++} libc_max_align_t;
++
++/* Wrapper for calloc with an optimization barrier.  */
++static void *
++__attribute__ ((noinline, noclone))
++allocate_zeroed (size_t a, size_t b)
++{
++  return calloc (a, b);
++}
++
++/* System page size, as determined by sysconf (_SC_PAGE_SIZE).  */
++static unsigned long page_size;
++
++/* Test parameters. */
++static size_t allocation_size;
++static size_t alignment;
++static enum {
++  with_malloc,
++  with_realloc,
++  with_aligned_alloc,
++  with_memalign,
++  with_posix_memalign,
++  with_valloc,
++  with_pvalloc,
++  with_calloc,
++  last_allocation_function = with_calloc
++} allocation_function;
++
++/* True if an allocation function uses the alignment test
++   parameter.  */
++const static bool alignment_sensitive[last_allocation_function + 1] =
++  {
++    [with_aligned_alloc] = true,
++    [with_memalign] = true,
++    [with_posix_memalign] = true,
++  };
++
++/* Combined pointer/expected alignment result of an allocation
++   function.  */
++struct allocate_result {
++  void *pointer;
++  size_t alignment;
++};
++
++/* Call the allocation function specified by allocation_function, with
++   allocation_size and alignment (if applicable) as arguments.  No
++   alignment check.  */
++static struct allocate_result
++allocate_1 (void)
++{
++  switch (allocation_function)
++    {
++    case with_malloc:
++      return (struct allocate_result)
++        {malloc (allocation_size), __alignof__ (libc_max_align_t)};
++    case with_realloc:
++      {
++        void *p = realloc (NULL, 16);
++        void *q;
++        if (p == NULL)
++          q = NULL;
++        else
++          {
++            q = realloc (p, allocation_size);
++            if (q == NULL)
++              free (p);
++          }
++        return (struct allocate_result) {q, __alignof__ (libc_max_align_t)};
++      }
++    case with_aligned_alloc:
++      {
++        void *p = aligned_alloc (alignment, allocation_size);
++        return (struct allocate_result) {p, alignment};
++      }
++    case with_memalign:
++      {
++        void *p = memalign (alignment, allocation_size);
++        return (struct allocate_result) {p, alignment};
++      }
++    case with_posix_memalign:
++      {
++        void *p;
++        if (posix_memalign (&p, alignment, allocation_size))
++          {
++            if (errno == ENOMEM)
++              p = NULL;
++            else
++              {
++                printf ("error: posix_memalign (p, %zu, %zu): %m\n",
++                        alignment, allocation_size);
++                abort ();
++              }
++          }
++        return (struct allocate_result) {p, alignment};
++      }
++    case with_valloc:
++      {
++        void *p = valloc (allocation_size);
++        return (struct allocate_result) {p, page_size};
++      }
++    case with_pvalloc:
++      {
++        void *p = pvalloc (allocation_size);
++        return (struct allocate_result) {p, page_size};
++      }
++    case with_calloc:
++      {
++        char *p = allocate_zeroed (1, allocation_size);
++        /* Check for non-zero bytes.  */
++        if (p != NULL)
++          for (size_t i = 0; i < allocation_size; ++i)
++            if (p[i] != 0)
++              {
++                printf ("error: non-zero byte at offset %zu\n", i);
++                abort ();
++              }
++        return (struct allocate_result) {p, __alignof__ (libc_max_align_t)};
++      }
++    }
++  abort ();
++}
++
++/* Call allocate_1 and perform the alignment check on the result.  */
++static void *
++allocate (void)
++{
++  struct allocate_result r = allocate_1 ();
++#if __powerpc__ == 1 && __powerpc64__ == 0
++  /* Sourceware bug 6527 on 32-bit POWER.
++     Ignore 16-byte alignment requirement when using malloc, realloc, or
++     calloc, since these functions are known not to provide enough
++     alignment.  */
++  if ((((uintptr_t) r.pointer) & (r.alignment - 1)) != 0
++      && !(r.alignment == 16
++	   && (allocation_function == with_malloc
++	       || allocation_function == with_realloc
++	       || allocation_function == with_calloc)))
++#else
++  if ((((uintptr_t) r.pointer) & (r.alignment - 1)) != 0)
++#endif
++    {
++      printf ("error: allocation function %d, size %zu not aligned to %zu\n",
++              (int) allocation_function, allocation_size, r.alignment);
++      abort ();
++    }
++  return r.pointer;
++}
++
++/* Barriers to synchronize thread creation and termination.  */
++static pthread_barrier_t start_barrier;
++static pthread_barrier_t end_barrier;
++
++/* Thread function which performs the allocation test.  Called by
++   pthread_create and from the main thread.  */
++static void *
++allocate_thread (void *closure)
++{
++  /* Wait for the creation of all threads.  */
++  {
++    int ret = pthread_barrier_wait (&start_barrier);
++    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
++      {
++        errno = ret;
++        printf ("error: pthread_barrier_wait: %m\n");
++        abort ();
++      }
++  }
++
++  /* Allocate until we run out of memory, creating a single-linked
++     list.  */
++  struct list {
++    struct list *next;
++  };
++  struct list *head = NULL;
++  while (true)
++    {
++      struct list *e = allocate ();
++      if (e == NULL)
++        break;
++
++      e->next = head;
++      head = e;
++    }
++
++  /* Wait for the allocation of all available memory.  */
++  {
++    int ret = pthread_barrier_wait (&end_barrier);
++    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
++      {
++        errno = ret;
++        printf ("error: pthread_barrier_wait: %m\n");
++        abort ();
++      }
++  }
++
++  /* Free the allocated memory.  */
++  while (head != NULL)
++    {
++      struct list *next = head->next;
++      free (head);
++      head = next;
++    }
++
++  return NULL;
++}
++
++/* Number of threads (plus the main thread.  */
++enum { thread_count = 8 };
++
++/* Thread attribute to request creation of threads with a non-default
++   stack size which is rather small.  This avoids interfering with the
++   configured address space limit.  */
++static pthread_attr_t small_stack;
++
++/* Runs one test in multiple threads, all in a subprocess so that
++   subsequent tests do not interfere with each other.  */
++static void
++run_one (void)
++{
++  /* Isolate the tests in a subprocess, so that we can start over
++     from scratch.  */
++  pid_t pid = fork ();
++  if (pid == 0)
++    {
++      /* In the child process.  Create the allocation threads.  */
++      pthread_t threads[thread_count];
++
++      for (unsigned i = 0; i < thread_count; ++i)
++        {
++          int ret = pthread_create (threads + i, &small_stack, allocate_thread, NULL);
++          if (ret != 0)
++            {
++              errno = ret;
++              printf ("error: pthread_create: %m\n");
++              abort ();
++            }
++        }
++
++      /* Also run the test on the main thread.  */
++      allocate_thread (NULL);
++
++      for (unsigned i = 0; i < thread_count; ++i)
++        {
++          int ret = pthread_join (threads[i], NULL);
++          if (ret != 0)
++            {
++              errno = ret;
++              printf ("error: pthread_join: %m\n");
++              abort ();
++            }
++        }
++      _exit (0);
++    }
++  else if (pid < 0)
++    {
++      printf ("error: fork: %m\n");
++      abort ();
++    }
++
++  /* In the parent process.  Wait for the child process to exit.  */
++  int status;
++  if (waitpid (pid, &status, 0) < 0)
++    {
++      printf ("error: waitpid: %m\n");
++      abort ();
++    }
++  if (status != 0)
++    {
++      printf ("error: exit status %d from child process\n", status);
++      exit (1);
++    }
++}
++
++/* Run all applicable allocation functions for the current test
++   parameters.  */
++static void
++run_allocation_functions (void)
++{
++  for (int af = 0; af <= last_allocation_function; ++af)
++    {
++      /* Run alignment-sensitive functions for non-default
++         alignments.  */
++      if (alignment_sensitive[af] != (alignment != 0))
++        continue;
++      allocation_function = af;
++      run_one ();
++    }
++}
++
++int
++do_test (void)
++{
++  /* Limit the number of malloc arenas.  We use a very low number so
++     that despute the address space limit configured below, all
++     requested arenas a can be created.  */
++  if (mallopt (M_ARENA_MAX, 2) == 0)
++    {
++      printf ("error: mallopt (M_ARENA_MAX) failed\n");
++      return 1;
++    }
++
++  /* Determine the page size.  */
++  {
++    long ret = sysconf (_SC_PAGE_SIZE);
++    if (ret < 0)
++      {
++        printf ("error: sysconf (_SC_PAGE_SIZE): %m\n");
++        return 1;
++      }
++    page_size = ret;
++  }
++
++  /* Limit the size of the process, so that memory allocation in
++     allocate_thread will eventually fail, without impacting the
++     entire system.  */
++  {
++    struct rlimit limit;
++    if (getrlimit (RLIMIT_AS, &limit) != 0)
++      {
++        printf ("getrlimit (RLIMIT_AS) failed: %m\n");
++        return 1;
++      }
++    long target = 200 * 1024 * 1024;
++    if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
++      {
++        limit.rlim_cur = target;
++        if (setrlimit (RLIMIT_AS, &limit) != 0)
++          {
++            printf ("setrlimit (RLIMIT_AS) failed: %m\n");
++            return 1;
++          }
++      }
++  }
++
++  /* Initialize thread attribute with a reduced stack size.  */
++  {
++    int ret = pthread_attr_init (&small_stack);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_attr_init: %m\n");
++        abort ();
++      }
++    unsigned long stack_size = ((256 * 1024) / page_size) * page_size;
++    if (stack_size < 4 * page_size)
++      stack_size = 8 * page_size;
++    ret = pthread_attr_setstacksize (&small_stack, stack_size);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_attr_setstacksize: %m\n");
++        abort ();
++      }
++  }
++
++  /* Initialize the barriers.  We run thread_count threads, plus 1 for
++     the main thread.  */
++  {
++    int ret = pthread_barrier_init (&start_barrier, NULL, thread_count + 1);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_barrier_init: %m\n");
++        abort ();
++      }
++
++    ret = pthread_barrier_init (&end_barrier, NULL, thread_count + 1);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_barrier_init: %m\n");
++        abort ();
++      }
++  }
++
++  allocation_size = 144;
++  run_allocation_functions ();
++  allocation_size = page_size;
++  run_allocation_functions ();
++
++  alignment = 128;
++  allocation_size = 512;
++  run_allocation_functions ();
++
++  allocation_size = page_size;
++  run_allocation_functions ();
++
++  allocation_size = 17 * page_size;
++  run_allocation_functions ();
++
++  /* Deallocation the barriers and the thread attribute.  */
++  {
++    int ret = pthread_barrier_destroy (&end_barrier);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_barrier_destroy: %m\n");
++        return 1;
++      }
++    ret = pthread_barrier_destroy (&start_barrier);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_barrier_destroy: %m\n");
++        return 1;
++      }
++    ret = pthread_attr_destroy (&small_stack);
++    if (ret != 0)
++      {
++        errno = ret;
++        printf ("error: pthread_attr_destroy: %m\n");
++        return 1;
++      }
++  }
++
++  return 0;
++}
++
++/* The repeated allocations take some time on slow machines.  */
++#define TIMEOUT 20
++
++/* No malloc perturbation should be used. We are testing that
++   default 0 perturbation values work.  */
++#define MALLOC_PERTURB 0
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+Index: glibc-2.17-c758a686/test-skeleton.c
+===================================================================
+--- glibc-2.17-c758a686.orig/test-skeleton.c
++++ glibc-2.17-c758a686/test-skeleton.c
+@@ -233,7 +233,10 @@ main (int argc, char *argv[])
+   pid_t termpid;
+ 
+   /* Make uses of freed and uninitialized memory known.  */
+-  mallopt (M_PERTURB, 42);
++#ifndef MALLOC_PERTURB
++# define MALLOC_PERTURB 42
++#endif
++  mallopt (M_PERTURB, MALLOC_PERTURB);
+ 
+ #ifdef STDOUT_UNBUFFERED
+   setbuf (stdout, NULL);
diff --git a/SOURCES/glibc-rh1293976.patch b/SOURCES/glibc-rh1293976.patch
new file mode 100644
index 0000000..11331bb
--- /dev/null
+++ b/SOURCES/glibc-rh1293976.patch
@@ -0,0 +1,140 @@
+Short description: CVE-2015-5220: calloc() returns non-zeroed memory.
+Author(s): Ondrej Bilka
+Origin: git://sourceware.org/git/glibc.git
+Bug-RHEL: #1296453 (rhel-7.2.z),  #1293976 (rhel-7.3), #1256285 (SRT)
+Bug-Fedora: NA
+Bug-Upstream: NA
+Upstream status: committed
+#
+# commit e8349efd466cfedc0aa98be61d88ca8795c9e565
+# Author: Ondřej Bílka <neleai@seznam.cz>
+# Date:   Mon Dec 9 17:25:19 2013 +0100
+#
+#    Simplify perturb_byte logic.
+#
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 4821deb..ac8c3f6 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1870,8 +1870,20 @@ static int check_action = DEFAULT_CHECK_ACTION;
+ 
+ static int perturb_byte;
+ 
+-#define alloc_perturb(p, n) memset (p, (perturb_byte ^ 0xff) & 0xff, n)
+-#define free_perturb(p, n) memset (p, perturb_byte & 0xff, n)
++static inline void
++alloc_perturb (char *p, size_t n)
++{
++  if (__glibc_unlikely (perturb_byte))
++    memset (p, perturb_byte ^ 0xff, n);
++}
++
++static inline void
++free_perturb (char *p, size_t n)
++{
++  if (__glibc_unlikely (perturb_byte))
++    memset (p, perturb_byte, n);
++}
++
+ 
+ 
+ #include <stap-probe.h>
+@@ -3287,8 +3299,7 @@ _int_malloc(mstate av, size_t bytes)
+ 	}
+       check_remalloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-	alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+     }
+   }
+@@ -3323,8 +3334,7 @@ _int_malloc(mstate av, size_t bytes)
+ 	  victim->size |= NON_MAIN_ARENA;
+ 	check_malloced_chunk(av, victim, nb);
+ 	void *p = chunk2mem(victim);
+-	if (__builtin_expect (perturb_byte, 0))
+-	  alloc_perturb (p, bytes);
++	alloc_perturb (p, bytes);
+ 	return p;
+       }
+     }
+@@ -3403,8 +3413,7 @@ _int_malloc(mstate av, size_t bytes)
+ 
+ 	check_malloced_chunk(av, victim, nb);
+ 	void *p = chunk2mem(victim);
+-	if (__builtin_expect (perturb_byte, 0))
+-	  alloc_perturb (p, bytes);
++	alloc_perturb (p, bytes);
+ 	return p;
+       }
+ 
+@@ -3420,8 +3429,7 @@ _int_malloc(mstate av, size_t bytes)
+ 	  victim->size |= NON_MAIN_ARENA;
+ 	check_malloced_chunk(av, victim, nb);
+ 	void *p = chunk2mem(victim);
+-	if (__builtin_expect (perturb_byte, 0))
+-	  alloc_perturb (p, bytes);
++	alloc_perturb (p, bytes);
+ 	return p;
+       }
+ 
+@@ -3545,8 +3553,7 @@ _int_malloc(mstate av, size_t bytes)
+ 	}
+ 	check_malloced_chunk(av, victim, nb);
+ 	void *p = chunk2mem(victim);
+-	if (__builtin_expect (perturb_byte, 0))
+-	  alloc_perturb (p, bytes);
++	alloc_perturb (p, bytes);
+ 	return p;
+       }
+     }
+@@ -3649,8 +3656,7 @@ _int_malloc(mstate av, size_t bytes)
+ 	}
+ 	check_malloced_chunk(av, victim, nb);
+ 	void *p = chunk2mem(victim);
+-	if (__builtin_expect (perturb_byte, 0))
+-	  alloc_perturb (p, bytes);
++	alloc_perturb (p, bytes);
+ 	return p;
+       }
+     }
+@@ -3684,8 +3690,7 @@ _int_malloc(mstate av, size_t bytes)
+ 
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-	alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+     }
+ 
+@@ -3705,7 +3710,7 @@ _int_malloc(mstate av, size_t bytes)
+     */
+     else {
+       void *p = sysmalloc(nb, av);
+-      if (p != NULL && __builtin_expect (perturb_byte, 0))
++      if (p != NULL)
+ 	alloc_perturb (p, bytes);
+       return p;
+     }
+@@ -3798,8 +3803,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
+ 	  }
+       }
+ 
+-    if (__builtin_expect (perturb_byte, 0))
+-      free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
++    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+ 
+     set_fastchunks(av);
+     unsigned int idx = fastbin_index(size);
+@@ -3881,8 +3885,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
+ 	goto errout;
+       }
+ 
+-    if (__builtin_expect (perturb_byte, 0))
+-      free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
++    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+ 
+     /* consolidate backward */
+     if (!prev_inuse(p)) {
diff --git a/SOURCES/glibc-rh1296031-0.patch b/SOURCES/glibc-rh1296031-0.patch
new file mode 100644
index 0000000..ed88f03
--- /dev/null
+++ b/SOURCES/glibc-rh1296031-0.patch
@@ -0,0 +1,461 @@
+Sourceware bug 16574
+
+commit d668061994a7486a3ba9c7d5e7882d85a2883707
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Thu Feb 13 11:01:57 2014 +0100
+
+    Fix memory leak in _nss_dns_gethostbyname4_r with big DNS answer
+
+commit ab7ac0f2cf8731fe4c3f3aea6088a7c0127b5725
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date:   Sun Feb 16 12:59:23 2014 +0100
+
+    Deduplicate resolv/nss_dns/dns-host.c
+    
+    In resolv/nss_dns/dns-host.c one of code path duplicated code after
+    that. We merge these paths.
+
+commit ab09bf616ad527b249aca5f2a4956fd526f0712f
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Tue Feb 18 10:57:25 2014 +0100
+
+    Properly fix memory leak in _nss_dns_gethostbyname4_r with big DNS answer
+    
+    Instead of trying to guess whether the second buffer needs to be freed
+    set a flag at the place it is allocated
+
+Index: glibc-2.17-c758a686/include/resolv.h
+===================================================================
+--- glibc-2.17-c758a686.orig/include/resolv.h
++++ glibc-2.17-c758a686/include/resolv.h
+@@ -56,11 +56,11 @@ libc_hidden_proto (__res_randomid)
+ libc_hidden_proto (__res_state)
+ 
+ int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
+-		       u_char **, u_char **, int *, int *);
++		       u_char **, u_char **, int *, int *, int *);
+ int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
+-			u_char **, u_char **, int *, int *);
++			u_char **, u_char **, int *, int *, int *);
+ int __libc_res_nsend (res_state, const u_char *, int, const u_char *, int,
+-		      u_char *, int, u_char **, u_char **, int *, int *)
++		      u_char *, int, u_char **, u_char **, int *, int *, int *)
+   attribute_hidden;
+ 
+ libresolv_hidden_proto (_sethtent)
+Index: glibc-2.17-c758a686/resolv/gethnamaddr.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/gethnamaddr.c
++++ glibc-2.17-c758a686/resolv/gethnamaddr.c
+@@ -616,7 +616,7 @@ gethostbyname2(name, af)
+ 	buf.buf = origbuf = (querybuf *) alloca (1024);
+ 
+ 	if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
+-				    &buf.ptr, NULL, NULL, NULL)) < 0) {
++				    &buf.ptr, NULL, NULL, NULL, NULL)) < 0) {
+ 		if (buf.buf != origbuf)
+ 			free (buf.buf);
+ 		Dprintf("res_nsearch failed (%d)\n", n);
+@@ -711,12 +711,12 @@ gethostbyaddr(addr, len, af)
+ 	buf.buf = orig_buf = (querybuf *) alloca (1024);
+ 
+ 	n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
+-			      &buf.ptr, NULL, NULL, NULL);
++			      &buf.ptr, NULL, NULL, NULL, NULL);
+ 	if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
+ 		strcpy(qp, "ip6.int");
+ 		n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
+ 				      buf.buf != orig_buf ? MAXPACKET : 1024,
+-				      &buf.ptr, NULL, NULL, NULL);
++				      &buf.ptr, NULL, NULL, NULL, NULL);
+ 	}
+ 	if (n < 0) {
+ 		if (buf.buf != orig_buf)
+Index: glibc-2.17-c758a686/resolv/nss_dns/dns-canon.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/nss_dns/dns-canon.c
++++ glibc-2.17-c758a686/resolv/nss_dns/dns-canon.c
+@@ -61,7 +61,7 @@ _nss_dns_getcanonname_r (const char *nam
+     {
+       int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
+ 				 buf, sizeof (buf), &ansp.ptr, NULL, NULL,
+-				 NULL);
++				 NULL, NULL);
+       if (r > 0)
+ 	{
+ 	  /* We need to decode the response.  Just one question record.
+Index: glibc-2.17-c758a686/resolv/nss_dns/dns-host.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/nss_dns/dns-host.c
++++ glibc-2.17-c758a686/resolv/nss_dns/dns-host.c
+@@ -190,7 +190,7 @@ _nss_dns_gethostbyname3_r (const char *n
+   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+ 
+   n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
+-			  1024, &host_buffer.ptr, NULL, NULL, NULL);
++			  1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (n < 0)
+     {
+       switch (errno)
+@@ -225,7 +225,7 @@ _nss_dns_gethostbyname3_r (const char *n
+ 	n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
+ 				host_buffer.buf != orig_host_buffer
+ 				? MAXPACKET : 1024, &host_buffer.ptr,
+-				NULL, NULL, NULL);
++				NULL, NULL, NULL, NULL);
+ 
+       if (n < 0)
+ 	{
+@@ -308,13 +308,20 @@ _nss_dns_gethostbyname4_r (const char *n
+   u_char *ans2p = NULL;
+   int nans2p = 0;
+   int resplen2 = 0;
++  int ans2p_malloced = 0;
+ 
+   int olderr = errno;
+   enum nss_status status;
+   int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
+ 			      host_buffer.buf->buf, 2048, &host_buffer.ptr,
+-			      &ans2p, &nans2p, &resplen2);
+-  if (n < 0)
++			      &ans2p, &nans2p, &resplen2, &ans2p_malloced);
++  if (n >= 0)
++    {
++      status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
++			       resplen2, name, pat, buffer, buflen,
++			       errnop, herrnop, ttlp);
++    }
++  else
+     {
+       switch (errno)
+ 	{
+@@ -341,16 +348,11 @@ _nss_dns_gethostbyname4_r (const char *n
+ 	*errnop = EAGAIN;
+       else
+ 	__set_errno (olderr);
+-
+-      if (host_buffer.buf != orig_host_buffer)
+-	free (host_buffer.buf);
+-
+-      return status;
+     }
+ 
+-  status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
+-			  resplen2, name, pat, buffer, buflen,
+-			  errnop, herrnop, ttlp);
++  /* Check whether ans2p was separately allocated.  */
++  if (ans2p_malloced)
++    free (ans2p);
+ 
+   if (host_buffer.buf != orig_host_buffer)
+     free (host_buffer.buf);
+@@ -460,7 +462,7 @@ _nss_dns_gethostbyaddr2_r (const void *a
+ 	  strcpy (qp, "].ip6.arpa");
+ 	  n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
+ 				 host_buffer.buf->buf, 1024, &host_buffer.ptr,
+-				 NULL, NULL, NULL);
++				 NULL, NULL, NULL, NULL);
+ 	  if (n >= 0)
+ 	    goto got_it_already;
+ 	}
+@@ -481,14 +483,14 @@ _nss_dns_gethostbyaddr2_r (const void *a
+     }
+ 
+   n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+-			 1024, &host_buffer.ptr, NULL, NULL, NULL);
++			 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
+     {
+       strcpy (qp, "ip6.int");
+       n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+ 			     host_buffer.buf != orig_host_buffer
+ 			     ? MAXPACKET : 1024, &host_buffer.ptr,
+-			     NULL, NULL, NULL);
++			     NULL, NULL, NULL, NULL);
+     }
+   if (n < 0)
+     {
+Index: glibc-2.17-c758a686/resolv/nss_dns/dns-network.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/nss_dns/dns-network.c
++++ glibc-2.17-c758a686/resolv/nss_dns/dns-network.c
+@@ -129,7 +129,7 @@ _nss_dns_getnetbyname_r (const char *nam
+   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+ 
+   anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+-			       1024, &net_buffer.ptr, NULL, NULL, NULL);
++			       1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (anslen < 0)
+     {
+       /* Nothing found.  */
+@@ -205,7 +205,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, i
+   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+ 
+   anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+-			      1024, &net_buffer.ptr, NULL, NULL, NULL);
++			      1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (anslen < 0)
+     {
+       /* Nothing found.  */
+Index: glibc-2.17-c758a686/resolv/res_query.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/res_query.c
++++ glibc-2.17-c758a686/resolv/res_query.c
+@@ -98,7 +98,7 @@ static int
+ __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
+ 			int class, int type, u_char *answer, int anslen,
+ 			u_char **answerp, u_char **answerp2, int *nanswerp2,
+-			int *resplen2);
++			int *resplen2, int *answerp2_malloced);
+ 
+ /*
+  * Formulate a normal query, send, and await answer.
+@@ -119,7 +119,8 @@ __libc_res_nquery(res_state statp,
+ 		  u_char **answerp,	/* if buffer needs to be enlarged */
+ 		  u_char **answerp2,
+ 		  int *nanswerp2,
+-		  int *resplen2)
++		  int *resplen2,
++		  int *answerp2_malloced)
+ {
+ 	HEADER *hp = (HEADER *) answer;
+ 	HEADER *hp2;
+@@ -224,7 +225,8 @@ __libc_res_nquery(res_state statp,
+ 	}
+ 	assert (answerp == NULL || (void *) *answerp == (void *) answer);
+ 	n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
+-			     anslen, answerp, answerp2, nanswerp2, resplen2);
++			     anslen, answerp, answerp2, nanswerp2, resplen2,
++			     answerp2_malloced);
+ 	if (use_malloc)
+ 		free (buf);
+ 	if (n < 0) {
+@@ -316,7 +318,7 @@ res_nquery(res_state statp,
+ 	   int anslen)		/* size of answer buffer */
+ {
+ 	return __libc_res_nquery(statp, name, class, type, answer, anslen,
+-				 NULL, NULL, NULL, NULL);
++				 NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nquery)
+ 
+@@ -335,7 +337,8 @@ __libc_res_nsearch(res_state statp,
+ 		   u_char **answerp,
+ 		   u_char **answerp2,
+ 		   int *nanswerp2,
+-		   int *resplen2)
++		   int *resplen2,
++		   int *answerp2_malloced)
+ {
+ 	const char *cp, * const *domain;
+ 	HEADER *hp = (HEADER *) answer;
+@@ -360,7 +363,7 @@ __libc_res_nsearch(res_state statp,
+ 	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+ 		return (__libc_res_nquery(statp, cp, class, type, answer,
+ 					  anslen, answerp, answerp2,
+-					  nanswerp2, resplen2));
++					  nanswerp2, resplen2, answerp2_malloced));
+ 
+ #ifdef DEBUG
+ 	if (statp->options & RES_DEBUG)
+@@ -377,7 +380,8 @@ __libc_res_nsearch(res_state statp,
+ 	if (dots >= statp->ndots || trailing_dot) {
+ 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+ 					      answer, anslen, answerp,
+-					      answerp2, nanswerp2, resplen2);
++					      answerp2, nanswerp2, resplen2,
++					      answerp2_malloced);
+ 		if (ret > 0 || trailing_dot
+ 		    /* If the second response is valid then we use that.  */
+ 		    || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
+@@ -388,11 +392,11 @@ __libc_res_nsearch(res_state statp,
+ 			answer = *answerp;
+ 			anslen = MAXPACKET;
+ 		}
+-		if (answerp2
+-		    && (*answerp2 < answer || *answerp2 >= answer + anslen))
++		if (answerp2 && *answerp2_malloced)
+ 		  {
+ 		    free (*answerp2);
+ 		    *answerp2 = NULL;
++		    *answerp2_malloced = 0;
+ 		  }
+ 	}
+ 
+@@ -419,7 +423,7 @@ __libc_res_nsearch(res_state statp,
+ 						      class, type,
+ 						      answer, anslen, answerp,
+ 						      answerp2, nanswerp2,
+-						      resplen2);
++						      resplen2, answerp2_malloced);
+ 			if (ret > 0 || (ret == 0 && resplen2 != NULL
+ 					&& *resplen2 > 0))
+ 				return (ret);
+@@ -428,12 +432,11 @@ __libc_res_nsearch(res_state statp,
+ 				answer = *answerp;
+ 				anslen = MAXPACKET;
+ 			}
+-			if (answerp2
+-			    && (*answerp2 < answer
+-				|| *answerp2 >= answer + anslen))
++			if (answerp2 && *answerp2_malloced)
+ 			  {
+ 			    free (*answerp2);
+ 			    *answerp2 = NULL;
++			    *answerp2_malloced = 0;
+ 			  }
+ 
+ 			/*
+@@ -489,7 +492,8 @@ __libc_res_nsearch(res_state statp,
+ 	    && !(tried_as_is || root_on_list)) {
+ 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+ 					      answer, anslen, answerp,
+-					      answerp2, nanswerp2, resplen2);
++					      answerp2, nanswerp2, resplen2,
++					      answerp2_malloced);
+ 		if (ret > 0 || (ret == 0 && resplen2 != NULL
+ 				&& *resplen2 > 0))
+ 			return (ret);
+@@ -502,10 +506,11 @@ __libc_res_nsearch(res_state statp,
+ 	 * else send back meaningless H_ERRNO, that being the one from
+ 	 * the last DNSRCH we did.
+ 	 */
+-	if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
++	if (answerp2 && *answerp2_malloced)
+ 	  {
+ 	    free (*answerp2);
+ 	    *answerp2 = NULL;
++	    *answerp2_malloced = 0;
+ 	  }
+ 	if (saved_herrno != -1)
+ 		RES_SET_H_ERRNO(statp, saved_herrno);
+@@ -525,7 +530,7 @@ res_nsearch(res_state statp,
+ 	    int anslen)		/* size of answer */
+ {
+ 	return __libc_res_nsearch(statp, name, class, type, answer,
+-				  anslen, NULL, NULL, NULL, NULL);
++				  anslen, NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nsearch)
+ 
+@@ -543,7 +548,8 @@ __libc_res_nquerydomain(res_state statp,
+ 			u_char **answerp,
+ 			u_char **answerp2,
+ 			int *nanswerp2,
+-			int *resplen2)
++			int *resplen2,
++			int *answerp2_malloced)
+ {
+ 	char nbuf[MAXDNAME];
+ 	const char *longname = nbuf;
+@@ -585,7 +591,7 @@ __libc_res_nquerydomain(res_state statp,
+ 	}
+ 	return (__libc_res_nquery(statp, longname, class, type, answer,
+ 				  anslen, answerp, answerp2, nanswerp2,
+-				  resplen2));
++				  resplen2, answerp2_malloced));
+ }
+ 
+ int
+@@ -597,7 +603,8 @@ res_nquerydomain(res_state statp,
+ 	    int anslen)		/* size of answer */
+ {
+ 	return __libc_res_nquerydomain(statp, name, domain, class, type,
+-				       answer, anslen, NULL, NULL, NULL, NULL);
++				       answer, anslen, NULL, NULL, NULL, NULL,
++				       NULL);
+ }
+ libresolv_hidden_def (res_nquerydomain)
+ 
+Index: glibc-2.17-c758a686/resolv/res_send.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/res_send.c
++++ glibc-2.17-c758a686/resolv/res_send.c
+@@ -186,12 +186,12 @@ evNowTime(struct timespec *res) {
+ static int		send_vc(res_state, const u_char *, int,
+ 				const u_char *, int,
+ 				u_char **, int *, int *, int, u_char **,
+-				u_char **, int *, int *);
++				u_char **, int *, int *, int *);
+ static int		send_dg(res_state, const u_char *, int,
+ 				const u_char *, int,
+ 				u_char **, int *, int *, int,
+ 				int *, int *, u_char **,
+-				u_char **, int *, int *);
++				u_char **, int *, int *, int *);
+ #ifdef DEBUG
+ static void		Aerror(const res_state, FILE *, const char *, int,
+ 			       const struct sockaddr *);
+@@ -343,7 +343,7 @@ int
+ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
+ 		 const u_char *buf2, int buflen2,
+ 		 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
+-		 int *nansp2, int *resplen2)
++		 int *nansp2, int *resplen2, int *ansp2_malloced)
+ {
+   int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+ 
+@@ -546,7 +546,8 @@ __libc_res_nsend(res_state statp, const
+ 			try = statp->retry;
+ 			n = send_vc(statp, buf, buflen, buf2, buflen2,
+ 				    &ans, &anssiz, &terrno,
+-				    ns, ansp, ansp2, nansp2, resplen2);
++				    ns, ansp, ansp2, nansp2, resplen2,
++				    ansp2_malloced);
+ 			if (n < 0)
+ 				return (-1);
+ 			if (n == 0 && (buf2 == NULL || *resplen2 == 0))
+@@ -556,7 +557,7 @@ __libc_res_nsend(res_state statp, const
+ 			n = send_dg(statp, buf, buflen, buf2, buflen2,
+ 				    &ans, &anssiz, &terrno,
+ 				    ns, &v_circuit, &gotsomewhere, ansp,
+-				    ansp2, nansp2, resplen2);
++				    ansp2, nansp2, resplen2, ansp2_malloced);
+ 			if (n < 0)
+ 				return (-1);
+ 			if (n == 0 && (buf2 == NULL || *resplen2 == 0))
+@@ -646,7 +647,7 @@ res_nsend(res_state statp,
+ 	  const u_char *buf, int buflen, u_char *ans, int anssiz)
+ {
+   return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
+-			  NULL, NULL, NULL, NULL);
++			  NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nsend)
+ 
+@@ -657,7 +658,7 @@ send_vc(res_state statp,
+ 	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+ 	u_char **ansp, int *anssizp,
+ 	int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
+-	int *resplen2)
++	int *resplen2, int *ansp2_malloced)
+ {
+ 	const HEADER *hp = (HEADER *) buf;
+ 	const HEADER *hp2 = (HEADER *) buf2;
+@@ -823,6 +824,8 @@ send_vc(res_state statp,
+ 			}
+ 			*thisanssizp = MAXPACKET;
+ 			*thisansp = newp;
++			if (thisansp == ansp2)
++			  *ansp2_malloced = 1;
+ 			anhp = (HEADER *) newp;
+ 			len = rlen;
+ 		} else {
+@@ -992,7 +995,7 @@ send_dg(res_state statp,
+ 	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+ 	u_char **ansp, int *anssizp,
+ 	int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
+-	u_char **ansp2, int *anssizp2, int *resplen2)
++	u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced)
+ {
+ 	const HEADER *hp = (HEADER *) buf;
+ 	const HEADER *hp2 = (HEADER *) buf2;
+@@ -1235,6 +1238,8 @@ send_dg(res_state statp,
+ 			if (newp != NULL) {
+ 				*anssizp = MAXPACKET;
+ 				*thisansp = ans = newp;
++				if (thisansp == ansp2)
++				  *ansp2_malloced = 1;
+ 			}
+ 		}
+ 		HEADER *anhp = (HEADER *) *thisansp;
diff --git a/SOURCES/glibc-rh1296031-2.patch b/SOURCES/glibc-rh1296031-2.patch
new file mode 100644
index 0000000..c46d6bd
--- /dev/null
+++ b/SOURCES/glibc-rh1296031-2.patch
@@ -0,0 +1,38 @@
+commit 6b142b3a1d007d7e6f50c26710de7177bc4aca74
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Mon Jun 8 15:21:18 2015 +0200
+
+    Record TTL also for DNS PTR queries (bug 18513)
+    
+    This allows nscd to manage proper TTL for GETHOSTBYADDR[v6] requests.
+
+2015-06-22  Andreas Schwab  <schwab@suse.de>
+
+	[BZ #18513]
+	* resolv/nss_dns/dns-host.c (getanswer_r): Record TTL also for
+	PTR queries.
+
+Index: glibc-2.17-c758a686/resolv/nss_dns/dns-host.c
+===================================================================
+--- glibc-2.17-c758a686.orig/resolv/nss_dns/dns-host.c
++++ glibc-2.17-c758a686/resolv/nss_dns/dns-host.c
+@@ -800,6 +800,10 @@ getanswer_r (const querybuf *answer, int
+ 
+       if (qtype == T_PTR && type == T_CNAME)
+ 	{
++	  /* A CNAME could also have a TTL entry.  */
++	  if (ttlp != NULL && ttl < *ttlp)
++	      *ttlp = ttl;
++
+ 	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+ 	  if (__builtin_expect (n < 0 || res_dnok (tbuf) == 0, 0))
+ 	    {
+@@ -863,6 +867,8 @@ getanswer_r (const querybuf *answer, int
+ 	      ++had_error;
+ 	      break;
+ 	    }
++	  if (ttlp != NULL && ttl < *ttlp)
++	      *ttlp = ttl;
+ #if MULTI_PTRS_ARE_ALIASES
+ 	  cp += n;
+ 	  if (haveanswer == 0)
diff --git a/SOURCES/glibc-rh1296031.patch b/SOURCES/glibc-rh1296031.patch
new file mode 100644
index 0000000..06726e2
--- /dev/null
+++ b/SOURCES/glibc-rh1296031.patch
@@ -0,0 +1,546 @@
+Index: b/resolv/nss_dns/dns-host.c
+===================================================================
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -1051,7 +1051,10 @@ gaih_getanswer_slice (const querybuf *an
+   int h_namelen = 0;
+ 
+   if (ancount == 0)
+-    return NSS_STATUS_NOTFOUND;
++    {
++      *h_errnop = HOST_NOT_FOUND;
++      return NSS_STATUS_NOTFOUND;
++    }
+ 
+   while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+     {
+@@ -1228,7 +1231,14 @@ gaih_getanswer_slice (const querybuf *an
+   /* Special case here: if the resolver sent a result but it only
+      contains a CNAME while we are looking for a T_A or T_AAAA record,
+      we fail with NOTFOUND instead of TRYAGAIN.  */
+-  return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
++  if (canon != NULL)
++    {
++      *h_errnop = HOST_NOT_FOUND;
++      return NSS_STATUS_NOTFOUND;
++    }
++
++  *h_errnop = NETDB_INTERNAL;
++  return NSS_STATUS_TRYAGAIN;
+ }
+ 
+ 
+@@ -1242,11 +1252,101 @@ gaih_getanswer (const querybuf *answer1,
+ 
+   enum nss_status status = NSS_STATUS_NOTFOUND;
+ 
++  /* Combining the NSS status of two distinct queries requires some
++     compromise and attention to symmetry (A or AAAA queries can be
++     returned in any order).  What follows is a breakdown of how this
++     code is expected to work and why. We discuss only SUCCESS,
++     TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
++     that apply (though RETURN and MERGE exist).  We make a distinction
++     between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
++     A recoverable TRYAGAIN is almost always due to buffer size issues
++     and returns ERANGE in errno and the caller is expected to retry
++     with a larger buffer.
++
++     Lastly, you may be tempted to make significant changes to the
++     conditions in this code to bring about symmetry between responses.
++     Please don't change anything without due consideration for
++     expected application behaviour.  Some of the synthesized responses
++     aren't very well thought out and sometimes appear to imply that
++     IPv4 responses are always answer 1, and IPv6 responses are always
++     answer 2, but that's not true (see the implemetnation of send_dg
++     and send_vc to see response can arrive in any order, particlarly
++     for UDP). However, we expect it holds roughly enough of the time
++     that this code works, but certainly needs to be fixed to make this
++     a more robust implementation.
++
++     ----------------------------------------------
++     | Answer 1 Status /   | Synthesized | Reason |
++     | Answer 2 Status     | Status      |        |
++     |--------------------------------------------|
++     | SUCCESS/SUCCESS     | SUCCESS     | [1]    |
++     | SUCCESS/TRYAGAIN    | TRYAGAIN    | [5]    |
++     | SUCCESS/TRYAGAIN'   | SUCCESS     | [1]    |
++     | SUCCESS/NOTFOUND    | SUCCESS     | [1]    |
++     | SUCCESS/UNAVAIL     | SUCCESS     | [1]    |
++     | TRYAGAIN/SUCCESS    | TRYAGAIN    | [2]    |
++     | TRYAGAIN/TRYAGAIN   | TRYAGAIN    | [2]    |
++     | TRYAGAIN/TRYAGAIN'  | TRYAGAIN    | [2]    |
++     | TRYAGAIN/NOTFOUND   | TRYAGAIN    | [2]    |
++     | TRYAGAIN/UNAVAIL    | TRYAGAIN    | [2]    |
++     | TRYAGAIN'/SUCCESS   | SUCCESS     | [3]    |
++     | TRYAGAIN'/TRYAGAIN  | TRYAGAIN    | [3]    |
++     | TRYAGAIN'/TRYAGAIN' | TRYAGAIN'   | [3]    |
++     | TRYAGAIN'/NOTFOUND  | TRYAGAIN'   | [3]    |
++     | TRYAGAIN'/UNAVAIL   | UNAVAIL     | [3]    |
++     | NOTFOUND/SUCCESS    | SUCCESS     | [3]    |
++     | NOTFOUND/TRYAGAIN   | TRYAGAIN    | [3]    |
++     | NOTFOUND/TRYAGAIN'  | TRYAGAIN'   | [3]    |
++     | NOTFOUND/NOTFOUND   | NOTFOUND    | [3]    |
++     | NOTFOUND/UNAVAIL    | UNAVAIL     | [3]    |
++     | UNAVAIL/SUCCESS     | UNAVAIL     | [4]    |
++     | UNAVAIL/TRYAGAIN    | UNAVAIL     | [4]    |
++     | UNAVAIL/TRYAGAIN'   | UNAVAIL     | [4]    |
++     | UNAVAIL/NOTFOUND    | UNAVAIL     | [4]    |
++     | UNAVAIL/UNAVAIL     | UNAVAIL     | [4]    |
++     ----------------------------------------------
++
++     [1] If the first response is a success we return success.
++         This ignores the state of the second answer and in fact
++         incorrectly sets errno and h_errno to that of the second
++	 answer.  However because the response is a success we ignore
++	 *errnop and *h_errnop (though that means you touched errno on
++         success).  We are being conservative here and returning the
++         likely IPv4 response in the first answer as a success.
++
++     [2] If the first response is a recoverable TRYAGAIN we return
++	 that instead of looking at the second response.  The
++	 expectation here is that we have failed to get an IPv4 response
++	 and should retry both queries.
++
++     [3] If the first response was not a SUCCESS and the second
++	 response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
++	 or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
++	 result from the second response, otherwise the first responses
++	 status is used.  Again we have some odd side-effects when the
++	 second response is NOTFOUND because we overwrite *errnop and
++	 *h_errnop that means that a first answer of NOTFOUND might see
++	 its *errnop and *h_errnop values altered.  Whether it matters
++	 in practice that a first response NOTFOUND has the wrong
++	 *errnop and *h_errnop is undecided.
++
++     [4] If the first response is UNAVAIL we return that instead of
++	 looking at the second response.  The expectation here is that
++	 it will have failed similarly e.g. configuration failure.
++
++     [5] Testing this code is complicated by the fact that truncated
++	 second response buffers might be returned as SUCCESS if the
++	 first answer is a SUCCESS.  To fix this we add symmetry to
++	 TRYAGAIN with the second response.  If the second response
++	 is a recoverable error we now return TRYAGIN even if the first
++	 response was SUCCESS.  */
++
+   if (anslen1 > 0)
+     status = gaih_getanswer_slice(answer1, anslen1, qname,
+ 				  &pat, &buffer, &buflen,
+ 				  errnop, h_errnop, ttlp,
+ 				  &first);
++
+   if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
+        || (status == NSS_STATUS_TRYAGAIN
+ 	   /* We want to look at the second answer in case of an
+@@ -1262,8 +1362,15 @@ gaih_getanswer (const querybuf *answer1,
+ 						     &pat, &buffer, &buflen,
+ 						     errnop, h_errnop, ttlp,
+ 						     &first);
++      /* Use the second response status in some cases.  */
+       if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
+ 	status = status2;
++      /* Do not return a truncated second response (unless it was
++         unavoidable e.g. unrecoverable TRYAGAIN).  */
++      if (status == NSS_STATUS_SUCCESS
++	  && (status2 == NSS_STATUS_TRYAGAIN
++	      && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
++	status = NSS_STATUS_TRYAGAIN;
+     }
+ 
+   return status;
+Index: b/resolv/res_query.c
+===================================================================
+--- a/resolv/res_query.c
++++ b/resolv/res_query.c
+@@ -396,6 +396,7 @@ __libc_res_nsearch(res_state statp,
+ 		  {
+ 		    free (*answerp2);
+ 		    *answerp2 = NULL;
++		    *nanswerp2 = 0;
+ 		    *answerp2_malloced = 0;
+ 		  }
+ 	}
+@@ -436,6 +437,7 @@ __libc_res_nsearch(res_state statp,
+ 			  {
+ 			    free (*answerp2);
+ 			    *answerp2 = NULL;
++			    *nanswerp2 = 0;
+ 			    *answerp2_malloced = 0;
+ 			  }
+ 
+@@ -510,6 +512,7 @@ __libc_res_nsearch(res_state statp,
+ 	  {
+ 	    free (*answerp2);
+ 	    *answerp2 = NULL;
++	    *nanswerp2 = 0;
+ 	    *answerp2_malloced = 0;
+ 	  }
+ 	if (saved_herrno != -1)
+Index: b/resolv/res_send.c
+===================================================================
+--- a/resolv/res_send.c
++++ b/resolv/res_send.c
+@@ -1,3 +1,20 @@
++/* Copyright (C) 2016 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; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
+ /*
+  * Copyright (c) 1985, 1989, 1993
+  *    The Regents of the University of California.  All rights reserved.
+@@ -360,6 +377,8 @@ __libc_res_nsend(res_state statp, const
+ #ifdef USE_HOOKS
+ 	if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
+ 		if (anssiz < MAXPACKET && ansp) {
++			/* Always allocate MAXPACKET, callers expect
++			   this specific size.  */
+ 			u_char *buf = malloc (MAXPACKET);
+ 			if (buf == NULL)
+ 				return (-1);
+@@ -653,6 +672,77 @@ libresolv_hidden_def (res_nsend)
+ 
+ /* Private */
+ 
++/* The send_vc function is responsible for sending a DNS query over TCP
++   to the nameserver numbered NS from the res_state STATP i.e.
++   EXT(statp).nssocks[ns].  The function supports sending both IPv4 and
++   IPv6 queries at the same serially on the same socket.
++
++   Please note that for TCP there is no way to disable sending both
++   queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
++   and sends the queries serially and waits for the result after each
++   sent query.  This implemetnation should be corrected to honour these
++   options.
++
++   Please also note that for TCP we send both queries over the same
++   socket one after another.  This technically violates best practice
++   since the server is allowed to read the first query, respond, and
++   then close the socket (to service another client).  If the server
++   does this, then the remaining second query in the socket data buffer
++   will cause the server to send the client an RST which will arrive
++   asynchronously and the client's OS will likely tear down the socket
++   receive buffer resulting in a potentially short read and lost
++   response data.  This will force the client to retry the query again,
++   and this process may repeat until all servers and connection resets
++   are exhausted and then the query will fail.  It's not known if this
++   happens with any frequency in real DNS server implementations.  This
++   implementation should be corrected to use two sockets by default for
++   parallel queries.
++
++   The query stored in BUF of BUFLEN length is sent first followed by
++   the query stored in BUF2 of BUFLEN2 length.  Queries are sent
++   serially on the same socket.
++
++   Answers to the query are stored firstly in *ANSP up to a max of
++   *ANSSIZP bytes.  If more than *ANSSIZP bytes are needed and ANSCP
++   is non-NULL (to indicate that modifying the answer buffer is allowed)
++   then malloc is used to allocate a new response buffer and ANSCP and
++   ANSP will both point to the new buffer.  If more than *ANSSIZP bytes
++   are needed but ANSCP is NULL, then as much of the response as
++   possible is read into the buffer, but the results will be truncated.
++   When truncation happens because of a small answer buffer the DNS
++   packets header feild TC will bet set to 1, indicating a truncated
++   message and the rest of the socket data will be read and discarded.
++
++   Answers to the query are stored secondly in *ANSP2 up to a max of
++   *ANSSIZP2 bytes, with the actual response length stored in
++   *RESPLEN2.  If more than *ANSSIZP bytes are needed and ANSP2
++   is non-NULL (required for a second query) then malloc is used to
++   allocate a new response buffer, *ANSSIZP2 is set to the new buffer
++   size and *ANSP2_MALLOCED is set to 1.
++
++   The ANSP2_MALLOCED argument will eventually be removed as the
++   change in buffer pointer can be used to detect the buffer has
++   changed and that the caller should use free on the new buffer.
++
++   Note that the answers may arrive in any order from the server and
++   therefore the first and second answer buffers may not correspond to
++   the first and second queries.
++
++   It is not supported to call this function with a non-NULL ANSP2
++   but a NULL ANSCP.  Put another way, you can call send_vc with a
++   single unmodifiable buffer or two modifiable buffers, but no other
++   combination is supported.
++
++   It is the caller's responsibility to free the malloc allocated
++   buffers by detecting that the pointers have changed from their
++   original values i.e. *ANSCP or *ANSP2 has changed.
++
++   If errors are encountered then *TERRNO is set to an appropriate
++   errno value and a zero result is returned for a recoverable error,
++   and a less-than zero result is returned for a non-recoverable error.
++
++   If no errors are encountered then *TERRNO is left unmodified and
++   a the length of the first response in bytes is returned.  */
+ static int
+ send_vc(res_state statp,
+ 	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+@@ -662,11 +752,7 @@ send_vc(res_state statp,
+ {
+ 	const HEADER *hp = (HEADER *) buf;
+ 	const HEADER *hp2 = (HEADER *) buf2;
+-	u_char *ans = *ansp;
+-	int orig_anssizp = *anssizp;
+-	// XXX REMOVE
+-	// int anssiz = *anssizp;
+-	HEADER *anhp = (HEADER *) ans;
++	HEADER *anhp = (HEADER *) *ansp;
+ 	struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
+ 	int truncating, connreset, resplen, n;
+ 	struct iovec iov[4];
+@@ -742,6 +828,8 @@ send_vc(res_state statp,
+ 	 * Receive length & response
+ 	 */
+ 	int recvresp1 = 0;
++	/* Skip the second response if there is no second query.
++           To do that we mark the second response as received.  */
+ 	int recvresp2 = buf2 == NULL;
+ 	uint16_t rlen16;
+  read_len:
+@@ -778,33 +866,14 @@ send_vc(res_state statp,
+ 	u_char **thisansp;
+ 	int *thisresplenp;
+ 	if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
++		/* We have not received any responses
++		   yet or we only have one response to
++		   receive.  */
+ 		thisanssizp = anssizp;
+ 		thisansp = anscp ?: ansp;
+ 		assert (anscp != NULL || ansp2 == NULL);
+ 		thisresplenp = &resplen;
+ 	} else {
+-		if (*anssizp != MAXPACKET) {
+-			/* No buffer allocated for the first
+-			   reply.  We can try to use the rest
+-			   of the user-provided buffer.  */
+-#ifdef _STRING_ARCH_unaligned
+-			*anssizp2 = orig_anssizp - resplen;
+-			*ansp2 = *ansp + resplen;
+-#else
+-			int aligned_resplen
+-			  = ((resplen + __alignof__ (HEADER) - 1)
+-			     & ~(__alignof__ (HEADER) - 1));
+-			*anssizp2 = orig_anssizp - aligned_resplen;
+-			*ansp2 = *ansp + aligned_resplen;
+-#endif
+-		} else {
+-			/* The first reply did not fit into the
+-			   user-provided buffer.  Maybe the second
+-			   answer will.  */
+-			*anssizp2 = orig_anssizp;
+-			*ansp2 = *ansp;
+-		}
+-
+ 		thisanssizp = anssizp2;
+ 		thisansp = ansp2;
+ 		thisresplenp = resplen2;
+@@ -812,10 +881,14 @@ send_vc(res_state statp,
+ 	anhp = (HEADER *) *thisansp;
+ 
+ 	*thisresplenp = rlen;
+-	if (rlen > *thisanssizp) {
+-		/* Yes, we test ANSCP here.  If we have two buffers
+-		   both will be allocatable.  */
+-		if (__builtin_expect (anscp != NULL, 1)) {
++	/* Is the answer buffer too small?  */
++	if (*thisanssizp < rlen) {
++		/* If the current buffer is non-NULL and it's not
++		   pointing at the static user-supplied buffer then
++		   we can reallocate it.  */
++		if (thisansp != NULL && thisansp != ansp) {
++			/* Always allocate MAXPACKET, callers expect
++			   this specific size.  */
+ 			u_char *newp = malloc (MAXPACKET);
+ 			if (newp == NULL) {
+ 				*terrno = ENOMEM;
+@@ -827,6 +900,9 @@ send_vc(res_state statp,
+ 			if (thisansp == ansp2)
+ 			  *ansp2_malloced = 1;
+ 			anhp = (HEADER *) newp;
++			/* A uint16_t can't be larger than MAXPACKET
++			   thus it's safe to allocate MAXPACKET but
++			   read RLEN bytes instead.  */
+ 			len = rlen;
+ 		} else {
+ 			Dprint(statp->options & RES_DEBUG,
+@@ -990,6 +1066,66 @@ reopen (res_state statp, int *terrno, in
+ 	return 1;
+ }
+ 
++/* The send_dg function is responsible for sending a DNS query over UDP
++   to the nameserver numbered NS from the res_state STATP i.e.
++   EXT(statp).nssocks[ns].  The function supports IPv4 and IPv6 queries
++   along with the ability to send the query in parallel for both stacks
++   (default) or serially (RES_SINGLKUP).  It also supports serial lookup
++   with a close and reopen of the socket used to talk to the server
++   (RES_SNGLKUPREOP) to work around broken name servers.
++
++   The query stored in BUF of BUFLEN length is sent first followed by
++   the query stored in BUF2 of BUFLEN2 length.  Queries are sent
++   in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
++
++   Answers to the query are stored firstly in *ANSP up to a max of
++   *ANSSIZP bytes.  If more than *ANSSIZP bytes are needed and ANSCP
++   is non-NULL (to indicate that modifying the answer buffer is allowed)
++   then malloc is used to allocate a new response buffer and ANSCP and
++   ANSP will both point to the new buffer.  If more than *ANSSIZP bytes
++   are needed but ANSCP is NULL, then as much of the response as
++   possible is read into the buffer, but the results will be truncated.
++   When truncation happens because of a small answer buffer the DNS
++   packets header feild TC will bet set to 1, indicating a truncated
++   message, while the rest of the UDP packet is discarded.
++
++   Answers to the query are stored secondly in *ANSP2 up to a max of
++   *ANSSIZP2 bytes, with the actual response length stored in
++   *RESPLEN2.  If more than *ANSSIZP bytes are needed and ANSP2
++   is non-NULL (required for a second query) then malloc is used to
++   allocate a new response buffer, *ANSSIZP2 is set to the new buffer
++   size and *ANSP2_MALLOCED is set to 1.
++
++   The ANSP2_MALLOCED argument will eventually be removed as the
++   change in buffer pointer can be used to detect the buffer has
++   changed and that the caller should use free on the new buffer.
++
++   Note that the answers may arrive in any order from the server and
++   therefore the first and second answer buffers may not correspond to
++   the first and second queries.
++
++   It is not supported to call this function with a non-NULL ANSP2
++   but a NULL ANSCP.  Put another way, you can call send_vc with a
++   single unmodifiable buffer or two modifiable buffers, but no other
++   combination is supported.
++
++   It is the caller's responsibility to free the malloc allocated
++   buffers by detecting that the pointers have changed from their
++   original values i.e. *ANSCP or *ANSP2 has changed.
++
++   If an answer is truncated because of UDP datagram DNS limits then
++   *V_CIRCUIT is set to 1 and the return value non-zero to indicate to
++   the caller to retry with TCP.  The value *GOTSOMEWHERE is set to 1
++   if any progress was made reading a response from the nameserver and
++   is used by the caller to distinguish between ECONNREFUSED and
++   ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
++
++   If errors are encountered then *TERRNO is set to an appropriate
++   errno value and a zero result is returned for a recoverable error,
++   and a less-than zero result is returned for a non-recoverable error.
++
++   If no errors are encountered then *TERRNO is left unmodified and
++   a the length of the first response in bytes is returned.  */
+ static int
+ send_dg(res_state statp,
+ 	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+@@ -999,8 +1135,6 @@ send_dg(res_state statp,
+ {
+ 	const HEADER *hp = (HEADER *) buf;
+ 	const HEADER *hp2 = (HEADER *) buf2;
+-	u_char *ans = *ansp;
+-	int orig_anssizp = *anssizp;
+ 	struct timespec now, timeout, finish;
+ 	struct pollfd pfd[1];
+ 	int ptimeout;
+@@ -1033,6 +1167,8 @@ send_dg(res_state statp,
+ 	int need_recompute = 0;
+ 	int nwritten = 0;
+ 	int recvresp1 = 0;
++	/* Skip the second response if there is no second query.
++           To do that we mark the second response as received.  */
+ 	int recvresp2 = buf2 == NULL;
+ 	pfd[0].fd = EXT(statp).nssocks[ns];
+ 	pfd[0].events = POLLOUT;
+@@ -1196,52 +1332,54 @@ send_dg(res_state statp,
+ 		int *thisresplenp;
+ 
+ 		if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
++			/* We have not received any responses
++			   yet or we only have one response to
++			   receive.  */
+ 			thisanssizp = anssizp;
+ 			thisansp = anscp ?: ansp;
+ 			assert (anscp != NULL || ansp2 == NULL);
+ 			thisresplenp = &resplen;
+ 		} else {
+-			if (*anssizp != MAXPACKET) {
+-				/* No buffer allocated for the first
+-				   reply.  We can try to use the rest
+-				   of the user-provided buffer.  */
+-#ifdef _STRING_ARCH_unaligned
+-				*anssizp2 = orig_anssizp - resplen;
+-				*ansp2 = *ansp + resplen;
+-#else
+-				int aligned_resplen
+-				  = ((resplen + __alignof__ (HEADER) - 1)
+-				     & ~(__alignof__ (HEADER) - 1));
+-				*anssizp2 = orig_anssizp - aligned_resplen;
+-				*ansp2 = *ansp + aligned_resplen;
+-#endif
+-			} else {
+-				/* The first reply did not fit into the
+-				   user-provided buffer.  Maybe the second
+-				   answer will.  */
+-				*anssizp2 = orig_anssizp;
+-				*ansp2 = *ansp;
+-			}
+-
+ 			thisanssizp = anssizp2;
+ 			thisansp = ansp2;
+ 			thisresplenp = resplen2;
+ 		}
+ 
+ 		if (*thisanssizp < MAXPACKET
+-		    /* Yes, we test ANSCP here.  If we have two buffers
+-		       both will be allocatable.  */
+-		    && anscp
++		    /* If the current buffer is non-NULL and it's not
++		       pointing at the static user-supplied buffer then
++		       we can reallocate it.  */
++		    && (thisansp != NULL && thisansp != ansp)
++		    /* Is the size too small?  */
+ 		    && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
+-			|| *thisanssizp < *thisresplenp)) {
++			|| *thisanssizp < *thisresplenp)
++		    ) {
++			/* Always allocate MAXPACKET, callers expect
++			   this specific size.  */
+ 			u_char *newp = malloc (MAXPACKET);
+ 			if (newp != NULL) {
+-				*anssizp = MAXPACKET;
+-				*thisansp = ans = newp;
++				*thisanssizp = MAXPACKET;
++				*thisansp = newp;
+ 				if (thisansp == ansp2)
+ 				  *ansp2_malloced = 1;
+ 			}
+ 		}
++		/* We could end up with truncation if anscp was NULL
++		   (not allowed to change caller's buffer) and the
++		   response buffer size is too small.  This isn't a
++		   reliable way to detect truncation because the ioctl
++		   may be an inaccurate report of the UDP message size.
++		   Therefore we use this only to issue debug output.
++		   To do truncation accurately with UDP we need
++		   MSG_TRUNC which is only available on Linux.  We
++		   can abstract out the Linux-specific feature in the
++		   future to detect truncation.  */
++		if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
++			Dprint(statp->options & RES_DEBUG,
++			       (stdout, ";; response may be truncated (UDP)\n")
++			);
++		}
++
+ 		HEADER *anhp = (HEADER *) *thisansp;
+ 		socklen_t fromlen = sizeof(struct sockaddr_in6);
+ 		assert (sizeof(from) <= fromlen);
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index 1aa0682..4f2ec5b 100644
--- a/SPECS/glibc.spec
+++ b/SPECS/glibc.spec
@@ -1,6 +1,6 @@
 %define glibcsrcdir glibc-2.17-c758a686
 %define glibcversion 2.17
-%define glibcrelease 105%{?dist}
+%define glibcrelease 106%{?dist}.4
 ##############################################################################
 # If run_glibc_tests is zero then tests are not run for the build.
 # You must always set run_glibc_tests to one for production builds.
@@ -88,8 +88,8 @@ URL: http://www.gnu.org/software/glibc/
 # We do not use usptream source tarballs as the start place for our package.
 # We should use upstream source tarballs for official releases though and
 # it will look like this:
-# Source0: http://ftp.gnu.org/gnu/glibc/%{glibcsrcdir}.tar.gz
-# Source1: %{glibcsrcdir}-releng.tar.gz
+# Source0: http://ftp.gnu.org/gnu/glibc/%%{glibcsrcdir}.tar.gz
+# Source1: %%{glibcsrcdir}-releng.tar.gz
 # TODO:
 # The Source1 URL will never reference an upstream URL. In fact the plan
 # should be to merge the entire release engineering tarball into upstream
@@ -201,6 +201,9 @@ Patch0063: glibc-rh1120490-int128.patch
 # Workaround to extend DTV_SURPLUS. Not to go upstream.
 Patch0066: glibc-rh1227699.patch
 
+# CVE-2015-7547
+Patch0067: glibc-rh1296031.patch
+
 ##############################################################################
 #
 # Patches from upstream
@@ -653,6 +656,23 @@ Patch1610: glibc-rh1234622.patch
 # Fix 32-bit POWER assembly to use only 32-bit instructions.
 Patch1611: glibc-rh1240796.patch
 
+# CVE-2015-5229 and regression test.
+Patch1612: glibc-rh1293976.patch
+Patch1613: glibc-rh1293976-2.patch
+
+# BZ #16574
+Patch1614: glibc-rh1296031-0.patch
+# BZ #13928
+Patch1616: glibc-rh1296031-2.patch
+
+# Malloc trim fixes: #17195, #18502.
+Patch1617: glibc-rh1284959-1.patch
+Patch1618: glibc-rh1284959-2.patch
+Patch1619: glibc-rh1284959-3.patch
+
+# ppc64le monstartup fix:
+Patch1620: glibc-rh1249102.patch
+
 ##############################################################################
 #
 # Patches submitted, but not yet approved upstream.
@@ -1291,6 +1311,15 @@ package or when debugging this package.
 %patch1611 -p1
 %patch1123 -p1
 %patch1124 -p1
+%patch1612 -p1
+%patch1613 -p1
+%patch1614 -p1
+%patch1616 -p1
+%patch0067 -p1
+%patch1617 -p1
+%patch1618 -p1
+%patch1619 -p1
+%patch1620 -p1
 
 ##############################################################################
 # %%prep - Additional prep required...
@@ -2360,6 +2389,24 @@ rm -f *.filelist*
 %endif
 
 %changelog
+* Fri Feb  5 2016 Florian Weimer <fweimer@redhat.com> - 2.17-106.4
+- Revert problematic libresolv change, not needed for the
+  CVE-2015-7547 fix (#1296030).
+
+* Fri Jan 15 2016 Carlos O'Donell <carlos@redhat.com> - 2.17-106.3
+- Fix CVE-2015-7547: getaddrinfo() stack-based buffer overflow (#1296030).
+- Fix madvise performance issues (#1298930).
+- Avoid "monstartup: out of memory" error on powerpc64le (#1298956).
+
+* Wed Jan 13 2016 Carlos O'Donell <carlos@redhat.com> - 2.17-106.2
+- Fix CVE-2015-5229: calloc() may return non-zero memory (#1296453).
+
+* Wed Oct 28 2015 Florian Weimer <fweimer@redhat.com> - 2.17-106.1
+- Rebuild with corrected release.
+
+* Wed Oct 28 2015 Florian Weimer <fweimer@redhat.com> - 2.17-106
+- Add fix for CVE-2015-5277 (#1275920).
+
 * Fri Aug 14 2015 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.17-105
 - Fix up test case for initial-exec fix (#1248208).