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 +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 +Reviewed-by: Tulio Magno Quites Machado Filho + +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 ++ . */ ++ ++#include ++ ++# 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 ++ . */ ++ ++#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 ++#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 +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 +Reviewed-by: Tulio Magno Quites Machado Filho + +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 ++ . */ ++ ++#define USE_AS_STPNCPY ++#include ++ ++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 + ++#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 ++ . */ ++ ++#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 +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 +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 +--- + 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 + + 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 + +(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 + #include + ++#include + #include ++#include + #include + + 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 + + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include + + 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 + +(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 + #include + ++#include + #include + #include ++#include + + 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 + +(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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++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 +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 . */ ++ ++/* Written by Paul Eggert. */ ++ ++#ifndef _GL_INTPROPS_H ++#define _GL_INTPROPS_H ++ ++#include ++ ++/* 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 ++ . */ ++#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__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__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 ++ . */ ++#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__OVERFLOW macros return 1 if the corresponding C operators ++ might not yield numerically correct answers due to arithmetic overflow. ++ The INT__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 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 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 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 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 + +(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 - 2.28-157 +- Consistently SXID_ERASE tunables in sxid binaries (#1934155) + +* Wed Mar 31 2021 DJ Delorie - 2.28-156 +- Backport ifunc optimizations for glibc for ppc64le (#1918719) + * Wed Mar 24 2021 Arjun Shankar - 2.28-155 - CVE-2021-27645: nscd: Fix double free in netgroupcache (#1927877)