diff --git a/SOURCES/glibc-rh1918719-1.patch b/SOURCES/glibc-rh1918719-1.patch
new file mode 100644
index 0000000..622ced9
--- /dev/null
+++ b/SOURCES/glibc-rh1918719-1.patch
@@ -0,0 +1,453 @@
+From b9d83bf3eb57e1cf8ef785f1a58e13ddf162b6f3 Mon Sep 17 00:00:00 2001
+From: Raphael M Zinsly <rzinsly@linux.ibm.com>
+Date: Thu, 12 Nov 2020 13:12:24 -0300
+Subject: powerpc: Add optimized strncpy for POWER9
+
+Similar to the strcpy P9 optimization, this version uses VSX to improve
+performance.
+
+Reviewed-by: Matheus Castanho <msc@linux.ibm.com>
+Reviewed-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+
+diff --git a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S
+new file mode 100644
+index 0000000000..cbfc37bda3
+--- /dev/null
++++ b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S
+@@ -0,0 +1,344 @@
++/* Optimized strncpy implementation for POWER9 LE.
++   Copyright (C) 2020 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
++   <https://www.gnu.org/licenses/>.  */
++
++#include <sysdep.h>
++
++# ifndef STRNCPY
++#  define FUNC_NAME strncpy
++# else
++#  define FUNC_NAME STRNCPY
++# endif
++
++#ifndef MEMSET
++/* For builds without IFUNC support, local calls should be made to internal
++   GLIBC symbol (created by libc_hidden_builtin_def).  */
++# ifdef SHARED
++#  define MEMSET_is_local
++#  define MEMSET   __GI_memset
++# else
++#  define MEMSET   memset
++# endif
++#endif
++
++#define FRAMESIZE (FRAME_MIN_SIZE+8)
++
++/* Implements the function
++
++   char * [r3] strncpy (char *dest [r3], const char *src [r4], size_t n [r5])
++
++   The implementation can load bytes past a null terminator, but only
++   up to the next 16-byte aligned address, so it never crosses a page.  */
++
++.machine power9
++#ifdef MEMSET_is_local
++ENTRY_TOCLESS (FUNC_NAME, 4)
++#else
++ENTRY (FUNC_NAME, 4)
++#endif
++	CALL_MCOUNT 2
++
++	/* NULL string optimizations  */
++	cmpdi   r5, 0
++	beqlr
++
++	lbz	r0,0(r4)
++	stb	r0,0(r3)
++	addi	r11,r3,1
++	addi	r5,r5,-1
++	vspltisb v18,0		/* Zeroes in v18  */
++	cmpdi	r0,0
++	beq	L(zero_padding)
++
++	/* Empty/1-byte string optimization  */
++	cmpdi	r5,0
++	beqlr
++
++	addi	r4,r4,1
++	neg	r7,r4
++	rldicl	r9,r7,0,60	/* How many bytes to get source 16B aligned?  */
++
++	/* Get source 16B aligned  */
++	lvx	v0,0,r4
++	lvsr	v1,0,r4
++	vperm	v0,v18,v0,v1
++
++	vcmpequb v6,v0,v18	/* 0xff if byte is NULL, 0x00 otherwise  */
++	vctzlsbb r7,v6		/* Number of trailing zeroes  */
++	addi	r8,r7,1		/* Add null terminator  */
++
++	/* r8 = bytes including null
++	   r9 = bytes to get source 16B aligned
++	   if r8 > r9
++	      no null, copy r9 bytes
++	   else
++	      there is a null, copy r8 bytes and return.  */
++	cmpld	r8,r9
++	bgt	L(no_null)
++
++	cmpld	cr6,r8,r5	/* r8 <= n?  */
++	ble	cr6,L(null)
++
++	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
++	stxvl	32+v0,r11,r10	/* Partial store  */
++
++	blr
++
++L(null):
++	sldi	r10,r8,56	/* stxvl wants size in top 8 bits  */
++	stxvl	32+v0,r11,r10	/* Partial store  */
++
++	add	r11,r11,r8
++	sub	r5,r5,r8
++	b L(zero_padding)
++
++L(no_null):
++	cmpld	r9,r5		/* Check if length was reached.  */
++	bge	L(n_tail1)
++
++	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
++	stxvl	32+v0,r11,r10	/* Partial store  */
++
++	add	r4,r4,r9
++	add	r11,r11,r9
++	sub	r5,r5,r9
++
++L(loop):
++	cmpldi	cr6,r5,64	/* Check if length was reached.  */
++	ble	cr6,L(final_loop)
++
++	lxv	32+v0,0(r4)
++	vcmpequb. v6,v0,v18	/* Any zero bytes?  */
++	bne	cr6,L(prep_tail1)
++
++	lxv	32+v1,16(r4)
++	vcmpequb. v6,v1,v18	/* Any zero bytes?  */
++	bne	cr6,L(prep_tail2)
++
++	lxv	32+v2,32(r4)
++	vcmpequb. v6,v2,v18	/* Any zero bytes?  */
++	bne	cr6,L(prep_tail3)
++
++	lxv	32+v3,48(r4)
++	vcmpequb. v6,v3,v18	/* Any zero bytes?  */
++	bne	cr6,L(prep_tail4)
++
++	stxv	32+v0,0(r11)
++	stxv	32+v1,16(r11)
++	stxv	32+v2,32(r11)
++	stxv	32+v3,48(r11)
++
++	addi	r4,r4,64
++	addi	r11,r11,64
++	addi	r5,r5,-64
++
++	b	L(loop)
++
++L(final_loop):
++	cmpldi	cr5,r5,16
++	lxv	32+v0,0(r4)
++	vcmpequb. v6,v0,v18	/* Any zero bytes?  */
++	ble	cr5,L(prep_n_tail1)
++	bne	cr6,L(count_tail1)
++	addi	r5,r5,-16
++
++	cmpldi	cr5,r5,16
++	lxv	32+v1,16(r4)
++	vcmpequb. v6,v1,v18	/* Any zero bytes?  */
++	ble	cr5,L(prep_n_tail2)
++	bne	cr6,L(count_tail2)
++	addi	r5,r5,-16
++
++	cmpldi	cr5,r5,16
++	lxv	32+v2,32(r4)
++	vcmpequb. v6,v2,v18	/* Any zero bytes?  */
++	ble	cr5,L(prep_n_tail3)
++	bne	cr6,L(count_tail3)
++	addi	r5,r5,-16
++
++	lxv	32+v3,48(r4)
++	vcmpequb. v6,v3,v18	/* Any zero bytes?  */
++	beq	cr6,L(n_tail4)
++
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++	cmpld	r8,r5		/* r8 < n?  */
++	blt	L(tail4)
++
++L(n_tail4):
++	stxv	32+v0,0(r11)
++	stxv	32+v1,16(r11)
++	stxv	32+v2,32(r11)
++	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
++	addi	r11,r11,48	/* Offset */
++	stxvl	32+v3,r11,r10	/* Partial store  */
++	blr
++
++L(prep_n_tail1):
++	beq	cr6,L(n_tail1)	/* Any zero bytes?  */
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++	cmpld	r8,r5		/* r8 < n?  */
++	blt	L(tail1)
++
++L(n_tail1):
++	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
++	stxvl	32+v0,r11,r10	/* Partial store  */
++	blr
++
++L(prep_n_tail2):
++	beq	cr6,L(n_tail2)	/* Any zero bytes?  */
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++	cmpld	r8,r5		/* r8 < n?  */
++	blt	L(tail2)
++
++L(n_tail2):
++	stxv	32+v0,0(r11)
++	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
++	addi	r11,r11,16	/* offset */
++	stxvl	32+v1,r11,r10	/* Partial store  */
++	blr
++
++L(prep_n_tail3):
++	beq	cr6,L(n_tail3)	/* Any zero bytes?  */
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++	cmpld	r8,r5		/* r8 < n?  */
++	blt	L(tail3)
++
++L(n_tail3):
++	stxv	32+v0,0(r11)
++	stxv	32+v1,16(r11)
++	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
++	addi	r11,r11,32	/* Offset */
++	stxvl	32+v2,r11,r10	/* Partial store  */
++	blr
++
++L(prep_tail1):
++L(count_tail1):
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++L(tail1):
++	addi	r9,r8,1		/* Add null terminator  */
++	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
++	stxvl	32+v0,r11,r10	/* Partial store  */
++	add	r11,r11,r9
++	sub	r5,r5,r9
++	b L(zero_padding)
++
++L(prep_tail2):
++	addi	r5,r5,-16
++L(count_tail2):
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++L(tail2):
++	addi	r9,r8,1		/* Add null terminator  */
++	stxv	32+v0,0(r11)
++	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
++	addi	r11,r11,16	/* offset */
++	stxvl	32+v1,r11,r10	/* Partial store  */
++	add	r11,r11,r9
++	sub	r5,r5,r9
++	b L(zero_padding)
++
++L(prep_tail3):
++	addi	r5,r5,-32
++L(count_tail3):
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++L(tail3):
++	addi	r9,r8,1		/* Add null terminator  */
++	stxv	32+v0,0(r11)
++	stxv	32+v1,16(r11)
++	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
++	addi	r11,r11,32	/* offset */
++	stxvl	32+v2,r11,r10	/* Partial store  */
++	add	r11,r11,r9
++	sub	r5,r5,r9
++	b L(zero_padding)
++
++L(prep_tail4):
++	addi	r5,r5,-48
++	vctzlsbb r8,v6		/* Number of trailing zeroes  */
++L(tail4):
++	addi	r9,r8,1		/* Add null terminator  */
++	stxv	32+v0,0(r11)
++	stxv	32+v1,16(r11)
++	stxv	32+v2,32(r11)
++	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
++	addi	r11,r11,48	/* offset */
++	stxvl	32+v3,r11,r10	/* Partial store  */
++	add	r11,r11,r9
++	sub	r5,r5,r9
++
++/* This code pads the remainder of dest with NULL bytes.  For large numbers
++   memset gives a better performance, 255 was chosen through experimentation.
++   */
++L(zero_padding):
++	cmpldi	r5,255
++	bge	L(zero_padding_memset)
++
++L(zero_padding_loop):
++	cmpldi	cr6,r5,16	/* Check if length was reached.  */
++	ble	cr6,L(zero_padding_end)
++
++	stxv	v18,0(r11)
++	addi	r11,r11,16
++	addi	r5,r5,-16
++
++	b	L(zero_padding_loop)
++
++L(zero_padding_end):
++	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
++	stxvl	v18,r11,r10	/* Partial store  */
++	blr
++
++	.align	4
++L(zero_padding_memset):
++	std	r30,-8(r1)   /* Save r30 on the stack.  */
++	cfi_offset(r30, -8)
++	mr	r30,r3       /* Save the return value of strncpy.  */
++	/* Prepare the call to memset.  */
++	mr	r3,r11       /* Pointer to the area to be zero-filled.  */
++	li	r4,0         /* Byte to be written (zero).  */
++
++	/* We delayed the creation of the stack frame, as well as the saving of
++	   the link register, because only at this point, we are sure that
++	   doing so is actually needed.  */
++
++	/* Save the link register.  */
++	mflr	r0
++	std	r0,16(r1)
++
++	/* Create the stack frame.  */
++	stdu	r1,-FRAMESIZE(r1)
++	cfi_adjust_cfa_offset(FRAMESIZE)
++	cfi_offset(lr, 16)
++
++	bl	MEMSET
++#ifndef MEMSET_is_local
++	nop
++#endif
++
++	ld	r0,FRAMESIZE+16(r1)
++
++	mr	r3,r30       /* Restore the return value of strncpy, i.e.:
++				dest.  */
++	ld	r30,FRAMESIZE-8(r1) /* Restore r30.  */
++	/* Restore the stack frame.  */
++	addi	r1,r1,FRAMESIZE
++	cfi_adjust_cfa_offset(-FRAMESIZE)
++	/* Restore the link register.  */
++	mtlr	r0
++	cfi_restore(lr)
++	blr
++
++END (FUNC_NAME)
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
+index 19acb6c64a..cd2b47b403 100644
+--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
+@@ -33,7 +33,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
+ 
+ ifneq (,$(filter %le,$(config-machine)))
+ sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \
+-		   rawmemchr-power9 strlen-power9
++		   rawmemchr-power9 strlen-power9 strncpy-power9
+ endif
+ CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops
+ CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+index dd54e7d6bb..135326c97a 100644
+--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+@@ -301,6 +301,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+ 
+   /* Support sysdeps/powerpc/powerpc64/multiarch/strncpy.c.  */
+   IFUNC_IMPL (i, name, strncpy,
++#ifdef __LITTLE_ENDIAN__
++	      IFUNC_IMPL_ADD (array, i, strncpy,
++			      (hwcap2 & PPC_FEATURE2_ARCH_3_00)
++			      && (hwcap & PPC_FEATURE_HAS_VSX),
++			      __strncpy_power9)
++#endif
+ 	      IFUNC_IMPL_ADD (array, i, strncpy,
+ 			      hwcap2 & PPC_FEATURE2_ARCH_2_07,
+ 			      __strncpy_power8)
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncpy-power9.S b/sysdeps/powerpc/powerpc64/multiarch/strncpy-power9.S
+new file mode 100644
+index 0000000000..2b57c190f5
+--- /dev/null
++++ b/sysdeps/powerpc/powerpc64/multiarch/strncpy-power9.S
+@@ -0,0 +1,32 @@
++/* Optimized strncpy implementation for POWER9 LE.
++   Copyright (C) 2020 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
++   <https://www.gnu.org/licenses/>.  */
++
++#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
++# define STRNCPY __strncpy_power9
++
++# undef libc_hidden_builtin_def
++# define libc_hidden_builtin_def(name)
++
++/* memset is used to pad the end of the string.  */
++# define MEMSET __memset_power8
++# ifdef SHARED
++#  define MEMSET_is_local
++# endif
++
++# include <sysdeps/powerpc/powerpc64/le/power9/strncpy.S>
++#endif
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c
+index 7bacf28aca..af8b6cdd9c 100644
+--- a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c
++++ b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c
+@@ -28,11 +28,19 @@
+ extern __typeof (strncpy) __strncpy_ppc attribute_hidden;
+ extern __typeof (strncpy) __strncpy_power7 attribute_hidden;
+ extern __typeof (strncpy) __strncpy_power8 attribute_hidden;
++# ifdef __LITTLE_ENDIAN__
++extern __typeof (strncpy) __strncpy_power9 attribute_hidden;
++# endif
+ # undef strncpy
+ 
+ /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
+  ifunc symbol properly. */
+ libc_ifunc_redirected (__redirect_strncpy, strncpy,
++# ifdef __LITTLE_ENDIAN__
++		       (hwcap2 & PPC_FEATURE2_ARCH_3_00) &&
++		       (hwcap & PPC_FEATURE_HAS_VSX)
++		       ? __strncpy_power9 :
++# endif
+ 		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+ 		       ? __strncpy_power8
+ 		       : (hwcap & PPC_FEATURE_HAS_VSX)
diff --git a/SOURCES/glibc-rh1918719-2.patch b/SOURCES/glibc-rh1918719-2.patch
new file mode 100644
index 0000000..0a50fd5
--- /dev/null
+++ b/SOURCES/glibc-rh1918719-2.patch
@@ -0,0 +1,307 @@
+From 7beee7b39adeda657f45989b0635033dae25a1fd Mon Sep 17 00:00:00 2001
+From: Raphael M Zinsly <rzinsly@linux.ibm.com>
+Date: Thu, 12 Nov 2020 13:12:24 -0300
+Subject: powerpc: Add optimized stpncpy for POWER9
+
+Add stpncpy support into the POWER9 strncpy.
+
+Reviewed-by: Matheus Castanho <msc@linux.ibm.com>
+Reviewed-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+
+diff --git a/sysdeps/powerpc/powerpc64/le/power9/stpncpy.S b/sysdeps/powerpc/powerpc64/le/power9/stpncpy.S
+new file mode 100644
+index 0000000000..81d9673d8b
+--- /dev/null
++++ b/sysdeps/powerpc/powerpc64/le/power9/stpncpy.S
+@@ -0,0 +1,24 @@
++/* Optimized stpncpy implementation for POWER9 LE.
++   Copyright (C) 2020 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
++   <https://www.gnu.org/licenses/>.  */
++
++#define USE_AS_STPNCPY
++#include <sysdeps/powerpc/powerpc64/le/power9/strncpy.S>
++
++weak_alias (__stpncpy, stpncpy)
++libc_hidden_def (__stpncpy)
++libc_hidden_builtin_def (stpncpy)
+diff --git a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S
+index cbfc37bda3..b4ba428662 100644
+--- a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S
++++ b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S
+@@ -18,11 +18,19 @@
+ 
+ #include <sysdep.h>
+ 
++#ifdef USE_AS_STPNCPY
++# ifndef STPNCPY
++#   define FUNC_NAME __stpncpy
++# else
++#   define FUNC_NAME STPNCPY
++# endif
++#else
+ # ifndef STRNCPY
+ #  define FUNC_NAME strncpy
+ # else
+ #  define FUNC_NAME STRNCPY
+ # endif
++#endif  /* !USE_AS_STPNCPY  */
+ 
+ #ifndef MEMSET
+ /* For builds without IFUNC support, local calls should be made to internal
+@@ -41,6 +49,12 @@
+ 
+    char * [r3] strncpy (char *dest [r3], const char *src [r4], size_t n [r5])
+ 
++   or
++
++   char * [r3] stpncpy (char *dest [r3], const char *src [r4], size_t n [r5])
++
++   if USE_AS_STPNCPY is defined.
++
+    The implementation can load bytes past a null terminator, but only
+    up to the next 16-byte aligned address, so it never crosses a page.  */
+ 
+@@ -66,7 +80,15 @@ ENTRY (FUNC_NAME, 4)
+ 
+ 	/* Empty/1-byte string optimization  */
+ 	cmpdi	r5,0
++#ifdef USE_AS_STPNCPY
++	bgt	L(cont)
++	/* Compute pointer to last byte copied into dest.  */
++	addi	r3,r3,1
++	blr
++L(cont):
++#else
+ 	beqlr
++#endif
+ 
+ 	addi	r4,r4,1
+ 	neg	r7,r4
+@@ -96,12 +118,20 @@ ENTRY (FUNC_NAME, 4)
+ 	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
+ 	stxvl	32+v0,r11,r10	/* Partial store  */
+ 
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r5
++#endif
+ 	blr
+ 
+ L(null):
+ 	sldi	r10,r8,56	/* stxvl wants size in top 8 bits  */
+ 	stxvl	32+v0,r11,r10	/* Partial store  */
+ 
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r7
++#endif
+ 	add	r11,r11,r8
+ 	sub	r5,r5,r8
+ 	b L(zero_padding)
+@@ -185,6 +215,10 @@ L(n_tail4):
+ 	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
+ 	addi	r11,r11,48	/* Offset */
+ 	stxvl	32+v3,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r5
++#endif
+ 	blr
+ 
+ L(prep_n_tail1):
+@@ -196,6 +230,10 @@ L(prep_n_tail1):
+ L(n_tail1):
+ 	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
+ 	stxvl	32+v0,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r5
++#endif
+ 	blr
+ 
+ L(prep_n_tail2):
+@@ -209,6 +247,10 @@ L(n_tail2):
+ 	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
+ 	addi	r11,r11,16	/* offset */
+ 	stxvl	32+v1,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r5
++#endif
+ 	blr
+ 
+ L(prep_n_tail3):
+@@ -223,6 +265,10 @@ L(n_tail3):
+ 	sldi	r10,r5,56	/* stxvl wants size in top 8 bits  */
+ 	addi	r11,r11,32	/* Offset */
+ 	stxvl	32+v2,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r5
++#endif
+ 	blr
+ 
+ L(prep_tail1):
+@@ -232,6 +278,10 @@ L(tail1):
+ 	addi	r9,r8,1		/* Add null terminator  */
+ 	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
+ 	stxvl	32+v0,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r8
++#endif
+ 	add	r11,r11,r9
+ 	sub	r5,r5,r9
+ 	b L(zero_padding)
+@@ -246,6 +296,10 @@ L(tail2):
+ 	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
+ 	addi	r11,r11,16	/* offset */
+ 	stxvl	32+v1,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r8
++#endif
+ 	add	r11,r11,r9
+ 	sub	r5,r5,r9
+ 	b L(zero_padding)
+@@ -261,6 +315,10 @@ L(tail3):
+ 	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
+ 	addi	r11,r11,32	/* offset */
+ 	stxvl	32+v2,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r8
++#endif
+ 	add	r11,r11,r9
+ 	sub	r5,r5,r9
+ 	b L(zero_padding)
+@@ -276,6 +334,10 @@ L(tail4):
+ 	sldi	r10,r9,56	/* stxvl wants size in top 8 bits  */
+ 	addi	r11,r11,48	/* offset */
+ 	stxvl	32+v3,r11,r10	/* Partial store  */
++#ifdef USE_AS_STPNCPY
++	/* Compute pointer to last byte copied into dest.  */
++	add	r3,r11,r8
++#endif
+ 	add	r11,r11,r9
+ 	sub	r5,r5,r9
+ 
+@@ -331,7 +393,8 @@ L(zero_padding_memset):
+ 	ld	r0,FRAMESIZE+16(r1)
+ 
+ 	mr	r3,r30       /* Restore the return value of strncpy, i.e.:
+-				dest.  */
++				dest.  For stpncpy, the return value is the
++				same as return value of memset.  */
+ 	ld	r30,FRAMESIZE-8(r1) /* Restore r30.  */
+ 	/* Restore the stack frame.  */
+ 	addi	r1,r1,FRAMESIZE
+@@ -342,3 +405,6 @@ L(zero_padding_memset):
+ 	blr
+ 
+ END (FUNC_NAME)
++#ifndef USE_AS_STPNCPY
++libc_hidden_builtin_def (strncpy)
++#endif
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
+index cd2b47b403..f46bf50732 100644
+--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
+@@ -33,7 +33,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
+ 
+ ifneq (,$(filter %le,$(config-machine)))
+ sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \
+-		   rawmemchr-power9 strlen-power9 strncpy-power9
++		   rawmemchr-power9 strlen-power9 strncpy-power9 stpncpy-power9
+ endif
+ CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops
+ CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+index 135326c97a..8e19ebbf09 100644
+--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+@@ -318,6 +318,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+ 
+   /* Support sysdeps/powerpc/powerpc64/multiarch/stpncpy.c.  */
+   IFUNC_IMPL (i, name, stpncpy,
++#ifdef __LITTLE_ENDIAN__
++	      IFUNC_IMPL_ADD (array, i, stpncpy,
++			      (hwcap2 & PPC_FEATURE2_ARCH_3_00)
++			      && (hwcap & PPC_FEATURE_HAS_VSX),
++			      __stpncpy_power9)
++#endif
+ 	      IFUNC_IMPL_ADD (array, i, stpncpy,
+ 			      hwcap2 & PPC_FEATURE2_ARCH_2_07,
+ 			      __stpncpy_power8)
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy-power9.S b/sysdeps/powerpc/powerpc64/multiarch/stpncpy-power9.S
+new file mode 100644
+index 0000000000..1188bd0894
+--- /dev/null
++++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy-power9.S
+@@ -0,0 +1,29 @@
++/* Optimized stpncpy implementation for POWER9 LE.
++   Copyright (C) 2020 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
++   <https://www.gnu.org/licenses/>.  */
++
++#define STPNCPY __stpncpy_power9
++
++#undef libc_hidden_builtin_def
++#define libc_hidden_builtin_def(name)
++
++#define MEMSET __memset_power8
++#ifdef SHARED
++# define MEMSET_is_local
++#endif
++
++#include <sysdeps/powerpc/powerpc64/le/power9/stpncpy.S>
+diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c
+index 17df886431..3758f29ad1 100644
+--- a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c
++++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c
+@@ -26,10 +26,18 @@
+ extern __typeof (__stpncpy) __stpncpy_ppc attribute_hidden;
+ extern __typeof (__stpncpy) __stpncpy_power7 attribute_hidden;
+ extern __typeof (__stpncpy) __stpncpy_power8 attribute_hidden;
++# ifdef __LITTLE_ENDIAN__
++extern __typeof (__stpncpy) __stpncpy_power9 attribute_hidden;
++# endif
+ # undef stpncpy
+ # undef __stpncpy
+ 
+ libc_ifunc_redirected (__redirect___stpncpy, __stpncpy,
++# ifdef __LITTLE_ENDIAN__
++		     (hwcap2 & PPC_FEATURE2_ARCH_3_00) &&
++		     (hwcap & PPC_FEATURE_HAS_VSX)
++		     ? __stpncpy_power9 :
++# endif
+ 		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+ 		       ? __stpncpy_power8
+ 		       : (hwcap & PPC_FEATURE_HAS_VSX)
diff --git a/SOURCES/glibc-rh1918719-3.patch b/SOURCES/glibc-rh1918719-3.patch
new file mode 100644
index 0000000..3c061fe
--- /dev/null
+++ b/SOURCES/glibc-rh1918719-3.patch
@@ -0,0 +1,30 @@
+From 3322ecbfe29a16e74c4f584d661b0b8018bb4031 Mon Sep 17 00:00:00 2001
+From: Raphael Moreira Zinsly <rzinsly@linux.ibm.com>
+Date: Mon, 14 Sep 2020 11:59:24 -0300
+Subject: [PATCH] powerpc: Protect dl_powerpc_cpu_features on INIT_ARCH() [BZ
+ #26615]
+
+dl_powerpc_cpu_features also needs to be protected by __GLRO to check
+for the _rtld_global_ro realocation before accessing it.
+
+Reviewed-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+---
+ sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
+index 17ddfcf528..c8fa07fadc 100644
+--- a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
++++ b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
+@@ -38,7 +38,7 @@
+   unsigned long int hwcap = __GLRO(dl_hwcap); 			\
+   unsigned long int __attribute__((unused)) hwcap2 = __GLRO(dl_hwcap2); \
+   bool __attribute__((unused)) use_cached_memopt =		\
+-    GLRO(dl_powerpc_cpu_features).use_cached_memopt;		\
++    __GLRO(dl_powerpc_cpu_features.use_cached_memopt);		\
+   if (hwcap & PPC_FEATURE_ARCH_2_06)				\
+     hwcap |= PPC_FEATURE_ARCH_2_05 |				\
+ 	     PPC_FEATURE_POWER5_PLUS |				\
+-- 
+2.27.0
+
diff --git a/SOURCES/glibc-rh1934155-1.patch b/SOURCES/glibc-rh1934155-1.patch
new file mode 100644
index 0000000..e5d5af6
--- /dev/null
+++ b/SOURCES/glibc-rh1934155-1.patch
@@ -0,0 +1,20 @@
+support: Pass environ to child process
+
+Pass environ to posix_spawn so that the child process can inherit
+environment of the test.
+
+(cherry picked from commit e958490f8c74e660bd93c128b3bea746e268f3f6)
+
+diff --git a/support/support_subprocess.c b/support/support_subprocess.c
+index 12c79ff6b0859877..4573350d775ac4c8 100644
+--- a/support/support_subprocess.c
++++ b/support/support_subprocess.c
+@@ -84,7 +84,7 @@ support_subprogram (const char *file, char *const argv[])
+   xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
+   xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
+ 
+-  result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
++  result.pid = xposix_spawn (file, &fa, NULL, argv, environ);
+ 
+   xclose (result.stdout_pipe[1]);
+   xclose (result.stderr_pipe[1]);
diff --git a/SOURCES/glibc-rh1934155-2.patch b/SOURCES/glibc-rh1934155-2.patch
new file mode 100644
index 0000000..ca842ee
--- /dev/null
+++ b/SOURCES/glibc-rh1934155-2.patch
@@ -0,0 +1,51 @@
+support: Typo and formatting fixes
+
+- Add a newline to the end of error messages in transfer().
+- Fixed the name of support_subprocess_init().
+
+(cherry picked from commit 95c68080a3ded882789b1629f872c3ad531efda0)
+
+diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
+index c13b3e59ece0842e..c475e2004da3183e 100644
+--- a/support/support_capture_subprocess.c
++++ b/support/support_capture_subprocess.c
+@@ -36,7 +36,7 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+       if (ret < 0)
+         {
+           support_record_failure ();
+-          printf ("error: reading from subprocess %s: %m", what);
++          printf ("error: reading from subprocess %s: %m\n", what);
+           pfd->events = 0;
+           pfd->revents = 0;
+         }
+diff --git a/support/support_subprocess.c b/support/support_subprocess.c
+index 4573350d775ac4c8..af01827cac81d80c 100644
+--- a/support/support_subprocess.c
++++ b/support/support_subprocess.c
+@@ -27,7 +27,7 @@
+ #include <support/subprocess.h>
+ 
+ static struct support_subprocess
+-support_suprocess_init (void)
++support_subprocess_init (void)
+ {
+   struct support_subprocess result;
+ 
+@@ -48,7 +48,7 @@ support_suprocess_init (void)
+ struct support_subprocess
+ support_subprocess (void (*callback) (void *), void *closure)
+ {
+-  struct support_subprocess result = support_suprocess_init ();
++  struct support_subprocess result = support_subprocess_init ();
+ 
+   result.pid = xfork ();
+   if (result.pid == 0)
+@@ -71,7 +71,7 @@ support_subprocess (void (*callback) (void *), void *closure)
+ struct support_subprocess
+ support_subprogram (const char *file, char *const argv[])
+ {
+-  struct support_subprocess result = support_suprocess_init ();
++  struct support_subprocess result = support_subprocess_init ();
+ 
+   posix_spawn_file_actions_t fa;
+   /* posix_spawn_file_actions_init does not fail.  */
diff --git a/SOURCES/glibc-rh1934155-3.patch b/SOURCES/glibc-rh1934155-3.patch
new file mode 100644
index 0000000..97ca5dd
--- /dev/null
+++ b/SOURCES/glibc-rh1934155-3.patch
@@ -0,0 +1,447 @@
+support: Add capability to fork an sgid child
+
+Add a new function support_capture_subprogram_self_sgid that spawns an
+sgid child of the running program with its own image and returns the
+exit code of the child process.  This functionality is used by at
+least three tests in the testsuite at the moment, so it makes sense to
+consolidate.
+
+There is also a new function support_subprogram_wait which should
+provide simple system() like functionality that does not set up file
+actions.  This is useful in cases where only the return code of the
+spawned subprocess is interesting.
+
+This patch also ports tst-secure-getenv to this new function.  A
+subsequent patch will port other tests.  This also brings an important
+change to tst-secure-getenv behaviour.  Now instead of succeeding, the
+test fails as UNSUPPORTED if it is unable to spawn a setgid child,
+which is how it should have been in the first place.
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+(cherry picked from commit 716a3bdc41b2b4b864dc64475015ba51e35e1273)
+
+diff --git a/stdlib/tst-secure-getenv.c b/stdlib/tst-secure-getenv.c
+index a682b7493e41f200..156c92fea216729f 100644
+--- a/stdlib/tst-secure-getenv.c
++++ b/stdlib/tst-secure-getenv.c
+@@ -30,156 +30,12 @@
+ #include <sys/wait.h>
+ #include <unistd.h>
+ 
++#include <support/check.h>
+ #include <support/support.h>
++#include <support/capture_subprocess.h>
+ #include <support/test-driver.h>
+ 
+ static char MAGIC_ARGUMENT[] = "run-actual-test";
+-#define MAGIC_STATUS 19
+-
+-/* Return a GID which is not our current GID, but is present in the
+-   supplementary group list.  */
+-static gid_t
+-choose_gid (void)
+-{
+-  const int count = 64;
+-  gid_t groups[count];
+-  int ret = getgroups (count, groups);
+-  if (ret < 0)
+-    {
+-      printf ("getgroups: %m\n");
+-      exit (1);
+-    }
+-  gid_t current = getgid ();
+-  for (int i = 0; i < ret; ++i)
+-    {
+-      if (groups[i] != current)
+-	return groups[i];
+-    }
+-  return 0;
+-}
+-
+-
+-/* Copies the executable into a restricted directory, so that we can
+-   safely make it SGID with the TARGET group ID.  Then runs the
+-   executable.  */
+-static int
+-run_executable_sgid (gid_t target)
+-{
+-  char *dirname = xasprintf ("%s/secure-getenv.%jd",
+-			     test_dir, (intmax_t) getpid ());
+-  char *execname = xasprintf ("%s/bin", dirname);
+-  int infd = -1;
+-  int outfd = -1;
+-  int ret = -1;
+-  if (mkdir (dirname, 0700) < 0)
+-    {
+-      printf ("mkdir: %m\n");
+-      goto err;
+-    }
+-  infd = open ("/proc/self/exe", O_RDONLY);
+-  if (infd < 0)
+-    {
+-      printf ("open (/proc/self/exe): %m\n");
+-      goto err;
+-    }
+-  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+-  if (outfd < 0)
+-    {
+-      printf ("open (%s): %m\n", execname);
+-      goto err;
+-    }
+-  char buf[4096];
+-  for (;;)
+-    {
+-      ssize_t rdcount = read (infd, buf, sizeof (buf));
+-      if (rdcount < 0)
+-	{
+-	  printf ("read: %m\n");
+-	  goto err;
+-	}
+-      if (rdcount == 0)
+-	break;
+-      char *p = buf;
+-      char *end = buf + rdcount;
+-      while (p != end)
+-	{
+-	  ssize_t wrcount = write (outfd, buf, end - p);
+-	  if (wrcount == 0)
+-	    errno = ENOSPC;
+-	  if (wrcount <= 0)
+-	    {
+-	      printf ("write: %m\n");
+-	      goto err;
+-	    }
+-	  p += wrcount;
+-	}
+-    }
+-  if (fchown (outfd, getuid (), target) < 0)
+-    {
+-      printf ("fchown (%s): %m\n", execname);
+-      goto err;
+-    }
+-  if (fchmod (outfd, 02750) < 0)
+-    {
+-      printf ("fchmod (%s): %m\n", execname);
+-      goto err;
+-    }
+-  if (close (outfd) < 0)
+-    {
+-      printf ("close (outfd): %m\n");
+-      goto err;
+-    }
+-  if (close (infd) < 0)
+-    {
+-      printf ("close (infd): %m\n");
+-      goto err;
+-    }
+-
+-  int kid = fork ();
+-  if (kid < 0)
+-    {
+-      printf ("fork: %m\n");
+-      goto err;
+-    }
+-  if (kid == 0)
+-    {
+-      /* Child process.  */
+-      char *args[] = { execname, MAGIC_ARGUMENT, NULL };
+-      execve (execname, args, environ);
+-      printf ("execve (%s): %m\n", execname);
+-      _exit (1);
+-    }
+-  int status;
+-  if (waitpid (kid, &status, 0) < 0)
+-    {
+-      printf ("waitpid: %m\n");
+-      goto err;
+-    }
+-  if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
+-    {
+-      printf ("Unexpected exit status %d from child process\n",
+-	      status);
+-      goto err;
+-    }
+-  ret = 0;
+-
+-err:
+-  if (outfd >= 0)
+-    close (outfd);
+-  if (infd >= 0)
+-    close (infd);
+-  if (execname)
+-    {
+-      unlink (execname);
+-      free (execname);
+-    }
+-  if (dirname)
+-    {
+-      rmdir (dirname);
+-      free (dirname);
+-    }
+-  return ret;
+-}
+ 
+ static int
+ do_test (void)
+@@ -201,15 +57,15 @@ do_test (void)
+       exit (1);
+     }
+ 
+-  gid_t target = choose_gid ();
+-  if (target == 0)
+-    {
+-      fprintf (stderr,
+-	       "Could not find a suitable GID for user %jd, skipping test\n",
+-	       (intmax_t) getuid ());
+-      exit (0);
+-    }
+-  return run_executable_sgid (target);
++  int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
++
++  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
++    return EXIT_UNSUPPORTED;
++
++  if (!WIFEXITED (status))
++    FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
++
++  return 0;
+ }
+ 
+ static void
+@@ -218,23 +74,15 @@ alternative_main (int argc, char **argv)
+   if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
+     {
+       if (getgid () == getegid ())
+-	{
+-	  /* This can happen if the file system is mounted nosuid.  */
+-	  fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
+-		  (intmax_t) getgid ());
+-	  exit (MAGIC_STATUS);
+-	}
++	/* This can happen if the file system is mounted nosuid.  */
++	FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
++		   (intmax_t) getgid ());
+       if (getenv ("PATH") == NULL)
+-	{
+-	  printf ("PATH variable not present\n");
+-	  exit (3);
+-	}
++	FAIL_EXIT (3, "PATH variable not present\n");
+       if (secure_getenv ("PATH") != NULL)
+-	{
+-	  printf ("PATH variable not filtered out\n");
+-	  exit (4);
+-	}
+-      exit (MAGIC_STATUS);
++	FAIL_EXIT (4, "PATH variable not filtered out\n");
++
++      exit (EXIT_SUCCESS);
+     }
+ }
+ 
+diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
+index 2d2384e73df0d2d0..72fb30504684a84e 100644
+--- a/support/capture_subprocess.h
++++ b/support/capture_subprocess.h
+@@ -41,6 +41,12 @@ struct support_capture_subprocess support_capture_subprocess
+ struct support_capture_subprocess support_capture_subprogram
+   (const char *file, char *const argv[]);
+ 
++/* Copy the running program into a setgid binary and run it with CHILD_ID
++   argument.  If execution is successful, return the exit status of the child
++   program, otherwise return a non-zero failure exit code.  */
++int support_capture_subprogram_self_sgid
++  (char *child_id);
++
+ /* Deallocate the subprocess data captured by
+    support_capture_subprocess.  */
+ void support_capture_subprocess_free (struct support_capture_subprocess *);
+diff --git a/support/subprocess.h b/support/subprocess.h
+index c031878d94c70c71..a19335ee5dbfcf98 100644
+--- a/support/subprocess.h
++++ b/support/subprocess.h
+@@ -38,6 +38,11 @@ struct support_subprocess support_subprocess
+ struct support_subprocess support_subprogram
+   (const char *file, char *const argv[]);
+ 
++/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it
++   to complete.  Return program exit status.  */
++int support_subprogram_wait
++  (const char *file, char *const argv[]);
++
+ /* Wait for the subprocess indicated by PROC::PID.  Return the status
+    indicate by waitpid call.  */
+ int support_process_wait (struct support_subprocess *proc);
+diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
+index c475e2004da3183e..eec5371d5602aa29 100644
+--- a/support/support_capture_subprocess.c
++++ b/support/support_capture_subprocess.c
+@@ -20,11 +20,14 @@
+ #include <support/capture_subprocess.h>
+ 
+ #include <errno.h>
++#include <fcntl.h>
+ #include <stdlib.h>
+ #include <support/check.h>
+ #include <support/xunistd.h>
+ #include <support/xsocket.h>
+ #include <support/xspawn.h>
++#include <support/support.h>
++#include <support/test-driver.h>
+ 
+ static void
+ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+@@ -101,6 +104,129 @@ support_capture_subprogram (const char *file, char *const argv[])
+   return result;
+ }
+ 
++/* Copies the executable into a restricted directory, so that we can
++   safely make it SGID with the TARGET group ID.  Then runs the
++   executable.  */
++static int
++copy_and_spawn_sgid (char *child_id, gid_t gid)
++{
++  char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
++			     test_dir, (intmax_t) getpid ());
++  char *execname = xasprintf ("%s/bin", dirname);
++  int infd = -1;
++  int outfd = -1;
++  int ret = 1, status = 1;
++
++  TEST_VERIFY (mkdir (dirname, 0700) == 0);
++  if (support_record_failure_is_failed ())
++    goto err;
++
++  infd = open ("/proc/self/exe", O_RDONLY);
++  if (infd < 0)
++    FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
++
++  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
++  TEST_VERIFY (outfd >= 0);
++  if (support_record_failure_is_failed ())
++    goto err;
++
++  char buf[4096];
++  for (;;)
++    {
++      ssize_t rdcount = read (infd, buf, sizeof (buf));
++      TEST_VERIFY (rdcount >= 0);
++      if (support_record_failure_is_failed ())
++	goto err;
++      if (rdcount == 0)
++	break;
++      char *p = buf;
++      char *end = buf + rdcount;
++      while (p != end)
++	{
++	  ssize_t wrcount = write (outfd, buf, end - p);
++	  if (wrcount == 0)
++	    errno = ENOSPC;
++	  TEST_VERIFY (wrcount > 0);
++	  if (support_record_failure_is_failed ())
++	    goto err;
++	  p += wrcount;
++	}
++    }
++  TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
++  if (support_record_failure_is_failed ())
++    goto err;
++  TEST_VERIFY (fchmod (outfd, 02750) == 0);
++  if (support_record_failure_is_failed ())
++    goto err;
++  TEST_VERIFY (close (outfd) == 0);
++  if (support_record_failure_is_failed ())
++    goto err;
++  TEST_VERIFY (close (infd) == 0);
++  if (support_record_failure_is_failed ())
++    goto err;
++
++  /* We have the binary, now spawn the subprocess.  Avoid using
++     support_subprogram because we only want the program exit status, not the
++     contents.  */
++  ret = 0;
++
++  char * const args[] = {execname, child_id, NULL};
++
++  status = support_subprogram_wait (args[0], args);
++
++err:
++  if (outfd >= 0)
++    close (outfd);
++  if (infd >= 0)
++    close (infd);
++  if (execname != NULL)
++    {
++      unlink (execname);
++      free (execname);
++    }
++  if (dirname != NULL)
++    {
++      rmdir (dirname);
++      free (dirname);
++    }
++
++  if (ret != 0)
++    FAIL_EXIT1("Failed to make sgid executable for test\n");
++
++  return status;
++}
++
++int
++support_capture_subprogram_self_sgid (char *child_id)
++{
++  gid_t target = 0;
++  const int count = 64;
++  gid_t groups[count];
++
++  /* Get a GID which is not our current GID, but is present in the
++     supplementary group list.  */
++  int ret = getgroups (count, groups);
++  if (ret < 0)
++    FAIL_UNSUPPORTED("Could not get group list for user %jd\n",
++		     (intmax_t) getuid ());
++
++  gid_t current = getgid ();
++  for (int i = 0; i < ret; ++i)
++    {
++      if (groups[i] != current)
++	{
++	  target = groups[i];
++	  break;
++	}
++    }
++
++  if (target == 0)
++    FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
++		     (intmax_t) getuid ());
++
++  return copy_and_spawn_sgid (child_id, target);
++}
++
+ void
+ support_capture_subprocess_free (struct support_capture_subprocess *p)
+ {
+diff --git a/support/support_subprocess.c b/support/support_subprocess.c
+index af01827cac81d80c..f7ee28af2531eda8 100644
+--- a/support/support_subprocess.c
++++ b/support/support_subprocess.c
+@@ -92,6 +92,19 @@ support_subprogram (const char *file, char *const argv[])
+   return result;
+ }
+ 
++int
++support_subprogram_wait (const char *file, char *const argv[])
++{
++  posix_spawn_file_actions_t fa;
++
++  posix_spawn_file_actions_init (&fa);
++  struct support_subprocess res = support_subprocess_init ();
++
++  res.pid = xposix_spawn (file, &fa, NULL, argv, environ);
++
++  return support_process_wait (&res);
++}
++
+ int
+ support_process_wait (struct support_subprocess *proc)
+ {
diff --git a/SOURCES/glibc-rh1934155-4.patch b/SOURCES/glibc-rh1934155-4.patch
new file mode 100644
index 0000000..ebdebcf
--- /dev/null
+++ b/SOURCES/glibc-rh1934155-4.patch
@@ -0,0 +1,240 @@
+tst-env-setuid: Use support_capture_subprogram_self_sgid
+
+Use the support_capture_subprogram_self_sgid to spawn an sgid child.
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+(cherry picked from commit ca335281068a1ed549a75ee64f90a8310755956f)
+
+diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
+index 183a6dd133cfa16e..eda87f9dda293e79 100644
+--- a/elf/tst-env-setuid.c
++++ b/elf/tst-env-setuid.c
+@@ -29,173 +29,12 @@
+ #include <sys/wait.h>
+ #include <unistd.h>
+ 
++#include <support/check.h>
+ #include <support/support.h>
+ #include <support/test-driver.h>
++#include <support/capture_subprocess.h>
+ 
+ static char SETGID_CHILD[] = "setgid-child";
+-#define CHILD_STATUS 42
+-
+-/* Return a GID which is not our current GID, but is present in the
+-   supplementary group list.  */
+-static gid_t
+-choose_gid (void)
+-{
+-  const int count = 64;
+-  gid_t groups[count];
+-  int ret = getgroups (count, groups);
+-  if (ret < 0)
+-    {
+-      printf ("getgroups: %m\n");
+-      exit (1);
+-    }
+-  gid_t current = getgid ();
+-  for (int i = 0; i < ret; ++i)
+-    {
+-      if (groups[i] != current)
+-	return groups[i];
+-    }
+-  return 0;
+-}
+-
+-/* Spawn and execute a program and verify that it returns the CHILD_STATUS.  */
+-static pid_t
+-do_execve (char **args)
+-{
+-  pid_t kid = vfork ();
+-
+-  if (kid < 0)
+-    {
+-      printf ("vfork: %m\n");
+-      return -1;
+-    }
+-
+-  if (kid == 0)
+-    {
+-      /* Child process.  */
+-      execve (args[0], args, environ);
+-      _exit (-errno);
+-    }
+-
+-  if (kid < 0)
+-    return 1;
+-
+-  int status;
+-
+-  if (waitpid (kid, &status, 0) < 0)
+-    {
+-      printf ("waitpid: %m\n");
+-      return 1;
+-    }
+-
+-  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+-    return EXIT_UNSUPPORTED;
+-
+-  if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
+-    {
+-      printf ("Unexpected exit status %d from child process\n",
+-	      WEXITSTATUS (status));
+-      return 1;
+-    }
+-  return 0;
+-}
+-
+-/* Copies the executable into a restricted directory, so that we can
+-   safely make it SGID with the TARGET group ID.  Then runs the
+-   executable.  */
+-static int
+-run_executable_sgid (gid_t target)
+-{
+-  char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
+-			     test_dir, (intmax_t) getpid ());
+-  char *execname = xasprintf ("%s/bin", dirname);
+-  int infd = -1;
+-  int outfd = -1;
+-  int ret = 0;
+-  if (mkdir (dirname, 0700) < 0)
+-    {
+-      printf ("mkdir: %m\n");
+-      goto err;
+-    }
+-  infd = open ("/proc/self/exe", O_RDONLY);
+-  if (infd < 0)
+-    {
+-      printf ("open (/proc/self/exe): %m\n");
+-      goto err;
+-    }
+-  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+-  if (outfd < 0)
+-    {
+-      printf ("open (%s): %m\n", execname);
+-      goto err;
+-    }
+-  char buf[4096];
+-  for (;;)
+-    {
+-      ssize_t rdcount = read (infd, buf, sizeof (buf));
+-      if (rdcount < 0)
+-	{
+-	  printf ("read: %m\n");
+-	  goto err;
+-	}
+-      if (rdcount == 0)
+-	break;
+-      char *p = buf;
+-      char *end = buf + rdcount;
+-      while (p != end)
+-	{
+-	  ssize_t wrcount = write (outfd, buf, end - p);
+-	  if (wrcount == 0)
+-	    errno = ENOSPC;
+-	  if (wrcount <= 0)
+-	    {
+-	      printf ("write: %m\n");
+-	      goto err;
+-	    }
+-	  p += wrcount;
+-	}
+-    }
+-  if (fchown (outfd, getuid (), target) < 0)
+-    {
+-      printf ("fchown (%s): %m\n", execname);
+-      goto err;
+-    }
+-  if (fchmod (outfd, 02750) < 0)
+-    {
+-      printf ("fchmod (%s): %m\n", execname);
+-      goto err;
+-    }
+-  if (close (outfd) < 0)
+-    {
+-      printf ("close (outfd): %m\n");
+-      goto err;
+-    }
+-  if (close (infd) < 0)
+-    {
+-      printf ("close (infd): %m\n");
+-      goto err;
+-    }
+-
+-  char *args[] = {execname, SETGID_CHILD, NULL};
+-
+-  ret = do_execve (args);
+-
+-err:
+-  if (outfd >= 0)
+-    close (outfd);
+-  if (infd >= 0)
+-    close (infd);
+-  if (execname)
+-    {
+-      unlink (execname);
+-      free (execname);
+-    }
+-  if (dirname)
+-    {
+-      rmdir (dirname);
+-      free (dirname);
+-    }
+-  return ret;
+-}
+ 
+ #ifndef test_child
+ static int
+@@ -256,40 +95,32 @@ do_test (int argc, char **argv)
+   if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
+     {
+       if (getgid () == getegid ())
+-	{
+-	  /* This can happen if the file system is mounted nosuid.  */
+-	  fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
+-		   (intmax_t) getgid ());
+-	  exit (EXIT_UNSUPPORTED);
+-	}
++	/* This can happen if the file system is mounted nosuid.  */
++	FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
++			  (intmax_t) getgid ());
+ 
+       int ret = test_child ();
+ 
+       if (ret != 0)
+ 	exit (1);
+ 
+-      exit (CHILD_STATUS);
++      exit (EXIT_SUCCESS);
+     }
+   else
+     {
+       if (test_parent () != 0)
+ 	exit (1);
+ 
+-      /* Try running a setgid program.  */
+-      gid_t target = choose_gid ();
+-      if (target == 0)
+-	{
+-	  fprintf (stderr,
+-		   "Could not find a suitable GID for user %jd, skipping test\n",
+-		   (intmax_t) getuid ());
+-	  exit (0);
+-	}
++      int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
+ 
+-      return run_executable_sgid (target);
+-    }
++      if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
++	return EXIT_UNSUPPORTED;
++
++      if (!WIFEXITED (status))
++	FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+ 
+-  /* Something went wrong and our argv was corrupted.  */
+-  _exit (1);
++      return 0;
++    }
+ }
+ 
+ #define TEST_FUNCTION_ARGV do_test
diff --git a/SOURCES/glibc-rh1934155-5.patch b/SOURCES/glibc-rh1934155-5.patch
new file mode 100644
index 0000000..1f5dea1
--- /dev/null
+++ b/SOURCES/glibc-rh1934155-5.patch
@@ -0,0 +1,613 @@
+Enhance setuid-tunables test
+
+Instead of passing GLIBC_TUNABLES via the environment, pass the
+environment variable from parent to child.  This allows us to test
+multiple variables to ensure better coverage.
+
+The test list currently only includes the case that's already being
+tested.  More tests will be added later.
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+(cherry picked from commit 061fe3f8add46a89b7453e87eabb9c4695005ced)
+
+Also add intprops.h from 2.29 from commit 8e6fd2bdb21efe2cc1ae7571ff8fb2599db6a05a
+
+diff --git a/elf/Makefile b/elf/Makefile
+index fc9c685b9d23bb6c..2093cefa7e73349e 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -1597,8 +1597,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
+ 
+ tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
+ 		     LD_HWCAP_MASK=0x1
+-tst-env-setuid-tunables-ENV = \
+-	GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
+ 
+ $(objpfx)tst-debug1: $(libdl)
+ $(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
+diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
+index d7c4f0d5742cd526..a48281b175af6920 100644
+--- a/elf/tst-env-setuid-tunables.c
++++ b/elf/tst-env-setuid-tunables.c
+@@ -25,35 +25,50 @@
+ #include "config.h"
+ #undef _LIBC
+ 
+-#define test_parent test_parent_tunables
+-#define test_child test_child_tunables
+-
+-static int test_child_tunables (void);
+-static int test_parent_tunables (void);
+-
+-#include "tst-env-setuid.c"
++#include <errno.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/wait.h>
++#include <unistd.h>
++#include <intprops.h>
++#include <array_length.h>
++
++#include <support/check.h>
++#include <support/support.h>
++#include <support/test-driver.h>
++#include <support/capture_subprocess.h>
++
++const char *teststrings[] =
++{
++  "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
++};
+ 
+-#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
+-#define PARENT_VALSTRING_VALUE \
+-  "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
++const char *resultstrings[] =
++{
++  "glibc.malloc.mmap_threshold=4096",
++};
+ 
+ static int
+-test_child_tunables (void)
++test_child (int off)
+ {
+   const char *val = getenv ("GLIBC_TUNABLES");
+ 
+ #if HAVE_TUNABLES
+-  if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
++  if (val != NULL && strcmp (val, resultstrings[off]) == 0)
+     return 0;
+ 
+   if (val != NULL)
+-    printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
++    printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
+ 
+   return 1;
+ #else
+   if (val != NULL)
+     {
+-      printf ("GLIBC_TUNABLES not cleared\n");
++      printf ("[%d] GLIBC_TUNABLES not cleared\n", off);
+       return 1;
+     }
+   return 0;
+@@ -61,15 +76,48 @@ test_child_tunables (void)
+ }
+ 
+ static int
+-test_parent_tunables (void)
++do_test (int argc, char **argv)
+ {
+-  const char *val = getenv ("GLIBC_TUNABLES");
++  /* Setgid child process.  */
++  if (argc == 2)
++    {
++      if (getgid () == getegid ())
++	/* This can happen if the file system is mounted nosuid.  */
++	FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
++			  (intmax_t) getgid ());
+ 
+-  if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
+-    return 0;
++      int ret = test_child (atoi (argv[1]));
+ 
+-  if (val != NULL)
+-    printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
++      if (ret != 0)
++	exit (1);
+ 
+-  return 1;
++      exit (EXIT_SUCCESS);
++    }
++  else
++    {
++      int ret = 0;
++
++      /* Spawn tests.  */
++      for (int i = 0; i < array_length (teststrings); i++)
++	{
++	  char buf[INT_BUFSIZE_BOUND (int)];
++
++	  printf ("Spawned test for %s (%d)\n", teststrings[i], i);
++	  snprintf (buf, sizeof (buf), "%d\n", i);
++	  if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
++	    exit (1);
++
++	  int status = support_capture_subprogram_self_sgid (buf);
++
++	  /* Bail out early if unsupported.  */
++	  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
++	    return EXIT_UNSUPPORTED;
++
++	  ret |= status;
++	}
++      return ret;
++    }
+ }
++
++#define TEST_FUNCTION_ARGV do_test
++#include <support/test-driver.c>
+diff --git a/include/intprops.h b/include/intprops.h
+new file mode 100644
+index 0000000000000000..9702aec4c6e3c80a
+--- /dev/null
++++ b/include/intprops.h
+@@ -0,0 +1,455 @@
++/* intprops.h -- properties of integer types
++
++   Copyright (C) 2001-2018 Free Software Foundation, Inc.
++
++   This program 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.
++
++   This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.  */
++
++/* Written by Paul Eggert.  */
++
++#ifndef _GL_INTPROPS_H
++#define _GL_INTPROPS_H
++
++#include <limits.h>
++
++/* Return a value with the common real type of E and V and the value of V.
++   Do not evaluate E.  */
++#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
++
++/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
++   <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>.  */
++#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
++
++/* The extra casts in the following macros work around compiler bugs,
++   e.g., in Cray C 5.0.3.0.  */
++
++/* True if the arithmetic type T is an integer type.  bool counts as
++   an integer.  */
++#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
++
++/* True if the real type T is signed.  */
++#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
++
++/* Return 1 if the real expression E, after promotion, has a
++   signed or floating type.  Do not evaluate E.  */
++#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
++
++
++/* Minimum and maximum values for integer types and expressions.  */
++
++/* The width in bits of the integer type or expression T.
++   Do not evaluate T.
++   Padding bits are not supported; this is checked at compile-time below.  */
++#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
++
++/* The maximum and minimum values for the integer type T.  */
++#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
++#define TYPE_MAXIMUM(t)                                                 \
++  ((t) (! TYPE_SIGNED (t)                                               \
++        ? (t) -1                                                        \
++        : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)))
++
++/* The maximum and minimum values for the type of the expression E,
++   after integer promotion.  E is not evaluated.  */
++#define _GL_INT_MINIMUM(e)                                              \
++  (EXPR_SIGNED (e)                                                      \
++   ? ~ _GL_SIGNED_INT_MAXIMUM (e)                                       \
++   : _GL_INT_CONVERT (e, 0))
++#define _GL_INT_MAXIMUM(e)                                              \
++  (EXPR_SIGNED (e)                                                      \
++   ? _GL_SIGNED_INT_MAXIMUM (e)                                         \
++   : _GL_INT_NEGATE_CONVERT (e, 1))
++#define _GL_SIGNED_INT_MAXIMUM(e)                                       \
++  (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1)
++
++/* Work around OpenVMS incompatibility with C99.  */
++#if !defined LLONG_MAX && defined __INT64_MAX
++# define LLONG_MAX __INT64_MAX
++# define LLONG_MIN __INT64_MIN
++#endif
++
++/* This include file assumes that signed types are two's complement without
++   padding bits; the above macros have undefined behavior otherwise.
++   If this is a problem for you, please let us know how to fix it for your host.
++   This assumption is tested by the intprops-tests module.  */
++
++/* Does the __typeof__ keyword work?  This could be done by
++   'configure', but for now it's easier to do it by hand.  */
++#if (2 <= __GNUC__ \
++     || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
++     || (0x5110 <= __SUNPRO_C && !__STDC__))
++# define _GL_HAVE___TYPEOF__ 1
++#else
++# define _GL_HAVE___TYPEOF__ 0
++#endif
++
++/* Return 1 if the integer type or expression T might be signed.  Return 0
++   if it is definitely unsigned.  This macro does not evaluate its argument,
++   and expands to an integer constant expression.  */
++#if _GL_HAVE___TYPEOF__
++# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
++#else
++# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
++#endif
++
++/* Bound on length of the string representing an unsigned integer
++   value representable in B bits.  log10 (2.0) < 146/485.  The
++   smallest value of B where this bound is not tight is 2621.  */
++#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
++
++/* Bound on length of the string representing an integer type or expression T.
++   Subtract 1 for the sign bit if T is signed, and then add 1 more for
++   a minus sign if needed.
++
++   Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is
++   signed, this macro may overestimate the true bound by one byte when
++   applied to unsigned types of size 2, 4, 16, ... bytes.  */
++#define INT_STRLEN_BOUND(t)                                     \
++  (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \
++   + _GL_SIGNED_TYPE_OR_EXPR (t))
++
++/* Bound on buffer size needed to represent an integer type or expression T,
++   including the terminating null.  */
++#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
++
++
++/* Range overflow checks.
++
++   The INT_<op>_RANGE_OVERFLOW macros return 1 if the corresponding C
++   operators might not yield numerically correct answers due to
++   arithmetic overflow.  They do not rely on undefined or
++   implementation-defined behavior.  Their implementations are simple
++   and straightforward, but they are a bit harder to use than the
++   INT_<op>_OVERFLOW macros described below.
++
++   Example usage:
++
++     long int i = ...;
++     long int j = ...;
++     if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX))
++       printf ("multiply would overflow");
++     else
++       printf ("product is %ld", i * j);
++
++   Restrictions on *_RANGE_OVERFLOW macros:
++
++   These macros do not check for all possible numerical problems or
++   undefined or unspecified behavior: they do not check for division
++   by zero, for bad shift counts, or for shifting negative numbers.
++
++   These macros may evaluate their arguments zero or multiple times,
++   so the arguments should not have side effects.  The arithmetic
++   arguments (including the MIN and MAX arguments) must be of the same
++   integer type after the usual arithmetic conversions, and the type
++   must have minimum value MIN and maximum MAX.  Unsigned types should
++   use a zero MIN of the proper type.
++
++   These macros are tuned for constant MIN and MAX.  For commutative
++   operations such as A + B, they are also tuned for constant B.  */
++
++/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  */
++#define INT_ADD_RANGE_OVERFLOW(a, b, min, max)          \
++  ((b) < 0                                              \
++   ? (a) < (min) - (b)                                  \
++   : (max) - (b) < (a))
++
++/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  */
++#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max)     \
++  ((b) < 0                                              \
++   ? (max) + (b) < (a)                                  \
++   : (a) < (min) + (b))
++
++/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  */
++#define INT_NEGATE_RANGE_OVERFLOW(a, min, max)          \
++  ((min) < 0                                            \
++   ? (a) < - (max)                                      \
++   : 0 < (a))
++
++/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  Avoid && and || as they tickle
++   bugs in Sun C 5.11 2010/08/13 and other compilers; see
++   <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00401.html>.  */
++#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max)     \
++  ((b) < 0                                              \
++   ? ((a) < 0                                           \
++      ? (a) < (max) / (b)                               \
++      : (b) == -1                                       \
++      ? 0                                               \
++      : (min) / (b) < (a))                              \
++   : (b) == 0                                           \
++   ? 0                                                  \
++   : ((a) < 0                                           \
++      ? (a) < (min) / (b)                               \
++      : (max) / (b) < (a)))
++
++/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  Do not check for division by zero.  */
++#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max)       \
++  ((min) < 0 && (b) == -1 && (a) < - (max))
++
++/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  Do not check for division by zero.
++   Mathematically, % should never overflow, but on x86-like hosts
++   INT_MIN % -1 traps, and the C standard permits this, so treat this
++   as an overflow too.  */
++#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max)    \
++  INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max)
++
++/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic.
++   See above for restrictions.  Here, MIN and MAX are for A only, and B need
++   not be of the same type as the other arguments.  The C standard says that
++   behavior is undefined for shifts unless 0 <= B < wordwidth, and that when
++   A is negative then A << B has undefined behavior and A >> B has
++   implementation-defined behavior, but do not check these other
++   restrictions.  */
++#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max)   \
++  ((a) < 0                                              \
++   ? (a) < (min) >> (b)                                 \
++   : (max) >> (b) < (a))
++
++/* True if __builtin_add_overflow (A, B, P) works when P is non-null.  */
++#if 5 <= __GNUC__ && !defined __ICC
++# define _GL_HAS_BUILTIN_OVERFLOW 1
++#else
++# define _GL_HAS_BUILTIN_OVERFLOW 0
++#endif
++
++/* True if __builtin_add_overflow_p (A, B, C) works.  */
++#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
++
++/* The _GL*_OVERFLOW macros have the same restrictions as the
++   *_RANGE_OVERFLOW macros, except that they do not assume that operands
++   (e.g., A and B) have the same type as MIN and MAX.  Instead, they assume
++   that the result (e.g., A + B) has that type.  */
++#if _GL_HAS_BUILTIN_OVERFLOW_P
++# define _GL_ADD_OVERFLOW(a, b, min, max)                               \
++   __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0)
++# define _GL_SUBTRACT_OVERFLOW(a, b, min, max)                          \
++   __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0)
++# define _GL_MULTIPLY_OVERFLOW(a, b, min, max)                          \
++   __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0)
++#else
++# define _GL_ADD_OVERFLOW(a, b, min, max)                                \
++   ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max)                  \
++    : (a) < 0 ? (b) <= (a) + (b)                                         \
++    : (b) < 0 ? (a) <= (a) + (b)                                         \
++    : (a) + (b) < (b))
++# define _GL_SUBTRACT_OVERFLOW(a, b, min, max)                           \
++   ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max)             \
++    : (a) < 0 ? 1                                                        \
++    : (b) < 0 ? (a) - (b) <= (a)                                         \
++    : (a) < (b))
++# define _GL_MULTIPLY_OVERFLOW(a, b, min, max)                           \
++   (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a))))       \
++    || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
++#endif
++#define _GL_DIVIDE_OVERFLOW(a, b, min, max)                             \
++  ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max)  \
++   : (a) < 0 ? (b) <= (a) + (b) - 1                                     \
++   : (b) < 0 && (a) + (b) <= (a))
++#define _GL_REMAINDER_OVERFLOW(a, b, min, max)                          \
++  ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max)  \
++   : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b)                     \
++   : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max))
++
++/* Return a nonzero value if A is a mathematical multiple of B, where
++   A is unsigned, B is negative, and MAX is the maximum value of A's
++   type.  A's type must be the same as (A % B)'s type.  Normally (A %
++   -B == 0) suffices, but things get tricky if -B would overflow.  */
++#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max)                            \
++  (((b) < -_GL_SIGNED_INT_MAXIMUM (b)                                   \
++    ? (_GL_SIGNED_INT_MAXIMUM (b) == (max)                              \
++       ? (a)                                                            \
++       : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1))   \
++    : (a) % - (b))                                                      \
++   == 0)
++
++/* Check for integer overflow, and report low order bits of answer.
++
++   The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators
++   might not yield numerically correct answers due to arithmetic overflow.
++   The INT_<op>_WRAPV macros also store the low-order bits of the answer.
++   These macros work correctly on all known practical hosts, and do not rely
++   on undefined behavior due to signed arithmetic overflow.
++
++   Example usage, assuming A and B are long int:
++
++     if (INT_MULTIPLY_OVERFLOW (a, b))
++       printf ("result would overflow\n");
++     else
++       printf ("result is %ld (no overflow)\n", a * b);
++
++   Example usage with WRAPV flavor:
++
++     long int result;
++     bool overflow = INT_MULTIPLY_WRAPV (a, b, &result);
++     printf ("result is %ld (%s)\n", result,
++             overflow ? "after overflow" : "no overflow");
++
++   Restrictions on these macros:
++
++   These macros do not check for all possible numerical problems or
++   undefined or unspecified behavior: they do not check for division
++   by zero, for bad shift counts, or for shifting negative numbers.
++
++   These macros may evaluate their arguments zero or multiple times, so the
++   arguments should not have side effects.
++
++   The WRAPV macros are not constant expressions.  They support only
++   +, binary -, and *.  The result type must be signed.
++
++   These macros are tuned for their last argument being a constant.
++
++   Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
++   A % B, and A << B would overflow, respectively.  */
++
++#define INT_ADD_OVERFLOW(a, b) \
++  _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW)
++#define INT_SUBTRACT_OVERFLOW(a, b) \
++  _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW)
++#if _GL_HAS_BUILTIN_OVERFLOW_P
++# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a)
++#else
++# define INT_NEGATE_OVERFLOW(a) \
++   INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
++#endif
++#define INT_MULTIPLY_OVERFLOW(a, b) \
++  _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
++#define INT_DIVIDE_OVERFLOW(a, b) \
++  _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW)
++#define INT_REMAINDER_OVERFLOW(a, b) \
++  _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW)
++#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
++  INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
++                                 _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
++
++/* Return 1 if the expression A <op> B would overflow,
++   where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test,
++   assuming MIN and MAX are the minimum and maximum for the result type.
++   Arguments should be free of side effects.  */
++#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow)        \
++  op_result_overflow (a, b,                                     \
++                      _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
++                      _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
++
++/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
++   Return 1 if the result overflows.  See above for restrictions.  */
++#define INT_ADD_WRAPV(a, b, r) \
++  _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW)
++#define INT_SUBTRACT_WRAPV(a, b, r) \
++  _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW)
++#define INT_MULTIPLY_WRAPV(a, b, r) \
++  _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW)
++
++/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390.  See:
++   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
++   https://llvm.org/bugs/show_bug.cgi?id=25390
++   For now, assume all versions of GCC-like compilers generate bogus
++   warnings for _Generic.  This matters only for older compilers that
++   lack __builtin_add_overflow.  */
++#if __GNUC__
++# define _GL__GENERIC_BOGUS 1
++#else
++# define _GL__GENERIC_BOGUS 0
++#endif
++
++/* Store the low-order bits of A <op> B into *R, where OP specifies
++   the operation.  BUILTIN is the builtin operation, and OVERFLOW the
++   overflow predicate.  Return 1 if the result overflows.  See above
++   for restrictions.  */
++#if _GL_HAS_BUILTIN_OVERFLOW
++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r)
++#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
++   (_Generic \
++    (*(r), \
++     signed char: \
++       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
++                        signed char, SCHAR_MIN, SCHAR_MAX), \
++     short int: \
++       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
++                        short int, SHRT_MIN, SHRT_MAX), \
++     int: \
++       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
++                        int, INT_MIN, INT_MAX), \
++     long int: \
++       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
++                        long int, LONG_MIN, LONG_MAX), \
++     long long int: \
++       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
++                        long long int, LLONG_MIN, LLONG_MAX)))
++#else
++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
++   (sizeof *(r) == sizeof (signed char) \
++    ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
++                       signed char, SCHAR_MIN, SCHAR_MAX) \
++    : sizeof *(r) == sizeof (short int) \
++    ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
++                       short int, SHRT_MIN, SHRT_MAX) \
++    : sizeof *(r) == sizeof (int) \
++    ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
++                       int, INT_MIN, INT_MAX) \
++    : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
++# ifdef LLONG_MAX
++#  define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
++    (sizeof *(r) == sizeof (long int) \
++     ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
++                        long int, LONG_MIN, LONG_MAX) \
++     : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
++                        long long int, LLONG_MIN, LLONG_MAX))
++# else
++#  define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
++    _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
++                     long int, LONG_MIN, LONG_MAX)
++# endif
++#endif
++
++/* Store the low-order bits of A <op> B into *R, where the operation
++   is given by OP.  Use the unsigned type UT for calculation to avoid
++   overflow problems.  *R's type is T, with extrema TMIN and TMAX.
++   T must be a signed integer type.  Return 1 if the result overflows.  */
++#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
++  (sizeof ((a) op (b)) < sizeof (t) \
++   ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \
++   : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax))
++#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \
++  ((overflow (a, b) \
++    || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \
++    || (tmax) < ((a) op (b))) \
++   ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
++   : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
++
++/* Return the low-order bits of A <op> B, where the operation is given
++   by OP.  Use the unsigned type UT for calculation to avoid undefined
++   behavior on signed integer overflow, and convert the result to type T.
++   UT is at least as wide as T and is no narrower than unsigned int,
++   T is two's complement, and there is no padding or trap representations.
++   Assume that converting UT to T yields the low-order bits, as is
++   done in all known two's-complement C compilers.  E.g., see:
++   https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
++
++   According to the C standard, converting UT to T yields an
++   implementation-defined result or signal for values outside T's
++   range.  However, code that works around this theoretical problem
++   runs afoul of a compiler bug in Oracle Studio 12.3 x86.  See:
++   https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
++   As the compiler bug is real, don't try to work around the
++   theoretical problem.  */
++
++#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
++  ((t) ((ut) (a) op (ut) (b)))
++
++#endif /* _GL_INTPROPS_H */
diff --git a/SOURCES/glibc-rh1934155-6.patch b/SOURCES/glibc-rh1934155-6.patch
new file mode 100644
index 0000000..83e0ff4
--- /dev/null
+++ b/SOURCES/glibc-rh1934155-6.patch
@@ -0,0 +1,160 @@
+Fix SXID_ERASE behavior in setuid programs (BZ #27471)
+
+When parse_tunables tries to erase a tunable marked as SXID_ERASE for
+setuid programs, it ends up setting the envvar string iterator
+incorrectly, because of which it may parse the next tunable
+incorrectly.  Given that currently the implementation allows malformed
+and unrecognized tunables pass through, it may even allow SXID_ERASE
+tunables to go through.
+
+This change revamps the SXID_ERASE implementation so that:
+
+- Only valid tunables are written back to the tunestr string, because
+  of which children of SXID programs will only inherit a clean list of
+  identified tunables that are not SXID_ERASE.
+
+- Unrecognized tunables get scrubbed off from the environment and
+  subsequently from the child environment.
+
+- This has the side-effect that a tunable that is not identified by
+  the setxid binary, will not be passed on to a non-setxid child even
+  if the child could have identified that tunable.  This may break
+  applications that expect this behaviour but expecting such tunables
+  to cross the SXID boundary is wrong.
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+(cherry picked from commit 2ed18c5b534d9e92fc006202a5af0df6b72e7aca)
+
+diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
+index 4c9d36e3980758b9..bbc3679e3564a766 100644
+--- a/elf/dl-tunables.c
++++ b/elf/dl-tunables.c
+@@ -178,6 +178,7 @@ parse_tunables (char *tunestr, char *valstring)
+     return;
+ 
+   char *p = tunestr;
++  size_t off = 0;
+ 
+   while (true)
+     {
+@@ -191,7 +192,11 @@ parse_tunables (char *tunestr, char *valstring)
+       /* If we reach the end of the string before getting a valid name-value
+ 	 pair, bail out.  */
+       if (p[len] == '\0')
+-	return;
++	{
++	  if (__libc_enable_secure)
++	    tunestr[off] = '\0';
++	  return;
++	}
+ 
+       /* We did not find a valid name-value pair before encountering the
+ 	 colon.  */
+@@ -217,35 +222,28 @@ parse_tunables (char *tunestr, char *valstring)
+ 
+ 	  if (tunable_is_name (cur->name, name))
+ 	    {
+-	      /* If we are in a secure context (AT_SECURE) then ignore the tunable
+-		 unless it is explicitly marked as secure.  Tunable values take
+-		 precendence over their envvar aliases.  */
++	      /* If we are in a secure context (AT_SECURE) then ignore the
++		 tunable unless it is explicitly marked as secure.  Tunable
++		 values take precedence over their envvar aliases.  We write
++		 the tunables that are not SXID_ERASE back to TUNESTR, thus
++		 dropping all SXID_ERASE tunables and any invalid or
++		 unrecognized tunables.  */
+ 	      if (__libc_enable_secure)
+ 		{
+-		  if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
++		  if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
+ 		    {
+-		      if (p[len] == '\0')
+-			{
+-			  /* Last tunable in the valstring.  Null-terminate and
+-			     return.  */
+-			  *name = '\0';
+-			  return;
+-			}
+-		      else
+-			{
+-			  /* Remove the current tunable from the string.  We do
+-			     this by overwriting the string starting from NAME
+-			     (which is where the current tunable begins) with
+-			     the remainder of the string.  We then have P point
+-			     to NAME so that we continue in the correct
+-			     position in the valstring.  */
+-			  char *q = &p[len + 1];
+-			  p = name;
+-			  while (*q != '\0')
+-			    *name++ = *q++;
+-			  name[0] = '\0';
+-			  len = 0;
+-			}
++		      if (off > 0)
++			tunestr[off++] = ':';
++
++		      const char *n = cur->name;
++
++		      while (*n != '\0')
++			tunestr[off++] = *n++;
++
++		      tunestr[off++] = '=';
++
++		      for (size_t j = 0; j < len; j++)
++			tunestr[off++] = value[j];
+ 		    }
+ 
+ 		  if (cur->security_level != TUNABLE_SECLEVEL_NONE)
+@@ -258,9 +256,7 @@ parse_tunables (char *tunestr, char *valstring)
+ 	    }
+ 	}
+ 
+-      if (p[len] == '\0')
+-	return;
+-      else
++      if (p[len] != '\0')
+ 	p += len + 1;
+     }
+ }
+diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
+index a48281b175af6920..0b9b075c40598c6f 100644
+--- a/elf/tst-env-setuid-tunables.c
++++ b/elf/tst-env-setuid-tunables.c
+@@ -45,11 +45,37 @@
+ const char *teststrings[] =
+ {
+   "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
++  "glibc.malloc.perturb=0x800",
++  "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
++  "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
++  "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
++  "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
++  ":glibc.malloc.garbage=2:glibc.malloc.check=1",
++  "glibc.malloc.check=1:glibc.malloc.check=2",
++  "not_valid.malloc.check=2",
++  "glibc.not_valid.check=2",
+ };
+ 
+ const char *resultstrings[] =
+ {
+   "glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.perturb=0x800",
++  "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.mmap_threshold=4096",
++  "glibc.malloc.mmap_threshold=4096",
++  "",
++  "",
++  "",
++  "",
++  "",
++  "",
+ };
+ 
+ static int
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index 2624e04..453856d 100644
--- a/SPECS/glibc.spec
+++ b/SPECS/glibc.spec
@@ -1,6 +1,6 @@
 %define glibcsrcdir glibc-2.28
 %define glibcversion 2.28
-%define glibcrelease 155%{?dist}
+%define glibcrelease 157%{?dist}
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
 #
@@ -697,6 +697,15 @@ Patch560: glibc-rh1912670-5.patch
 Patch561: glibc-rh1930302-1.patch
 Patch562: glibc-rh1930302-2.patch
 Patch563: glibc-rh1927877.patch
+Patch564: glibc-rh1918719-1.patch
+Patch565: glibc-rh1918719-2.patch
+Patch566: glibc-rh1918719-3.patch
+Patch567: glibc-rh1934155-1.patch
+Patch568: glibc-rh1934155-2.patch
+Patch569: glibc-rh1934155-3.patch
+Patch570: glibc-rh1934155-4.patch
+Patch571: glibc-rh1934155-5.patch
+Patch572: glibc-rh1934155-6.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -2608,6 +2617,12 @@ fi
 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
 
 %changelog
+* Wed Apr 14 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-157
+- Consistently SXID_ERASE tunables in sxid binaries (#1934155)
+
+* Wed Mar 31 2021 DJ Delorie <dj@redhat.com> - 2.28-156
+- Backport ifunc optimizations for glibc for ppc64le (#1918719)
+
 * Wed Mar 24 2021 Arjun Shankar <arjun@redhat.com> - 2.28-155
 - CVE-2021-27645: nscd: Fix double free in netgroupcache (#1927877)