diff --git a/backport-Avoid-use-of-atoi-in-some-places-in-libc.patch b/backport-Avoid-use-of-atoi-in-some-places-in-libc.patch new file mode 100644 index 0000000000000000000000000000000000000000..c9916226de81637c0412f29ff0b382561ca2f12b --- /dev/null +++ b/backport-Avoid-use-of-atoi-in-some-places-in-libc.patch @@ -0,0 +1,120 @@ +From a3708cf6b0a5a68e2ed1ce3db28a03ed21d368d2 Mon Sep 17 00:00:00 2001 +From: Joseph Myers +Date: Mon, 19 Dec 2022 14:45:44 +0000 +Subject: [PATCH] Avoid use of atoi in some places in libc + +This patch is split out of +. + +atoi has undefined behavior on out-of-range input, which makes it +problematic to use anywhere in glibc that might be processing input +out-of-range for atoi but not specified to produce undefined behavior +for the function calling atoi. Change some uses of atoi to call +strtol instead; this avoids the undefined behavior, though there is no +guarantee that the overflow handling of strtol is really right in +those places either. This also serves to avoid localplt test failures +given an installed header redirection for strtol (which means that the +call from the inline atoi implementation doesn't end up at a hidden +alias from libc_hidden_proto). + +Certainly, the use of atoi is questionable in argp-help.c (shared with +gnulib, so shouldn't depend on glibc implementation details, and +processing user-provided input), and maybe also in argp-parse.c (I'm +not sure what that code in argp-parse.c is meant to be used for). I +also changed inet/rexec.c and resolv/res_init.c similarly to use +strtol to avoid such localplt failures, although given those files (in +those versions) are only used in glibc it's not problematic for them +to rely on the specific behavior of glibc's atoi on out-of-range input +(in the absence of compiler optimizations based on the undefined +behavior) in the same way it's problematic for gnulib code to do so. + +There may be other uses of atoi (or atol or atoll), in any of glibc's +installed code, for which it would also be appropriate to avoid the +undefined behavior on out-of-range input; this patch only fixes the +specific cases needed to avoid localplt failures. + +Tested for x86_64. +--- + argp/argp-help.c | 6 +++--- + argp/argp-parse.c | 2 +- + inet/rexec.c | 2 +- + resolv/res_init.c | 6 +++--- + 4 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/argp/argp-help.c b/argp/argp-help.c +index 90a2795cef..f7f1134c80 100644 +--- a/argp/argp-help.c ++++ b/argp/argp-help.c +@@ -210,9 +210,9 @@ fill_in_uparams (const struct argp_state *state) + } + else if (isdigit ((unsigned char) *arg)) + { +- val = atoi (arg); +- while (isdigit ((unsigned char) *arg)) +- arg++; ++ char *ep; ++ val = strtol (arg, &ep, 10); ++ arg = ep; + SKIPWS (arg); + } + +diff --git a/argp/argp-parse.c b/argp/argp-parse.c +index 68dc45417b..1533b43aaf 100644 +--- a/argp/argp-parse.c ++++ b/argp/argp-parse.c +@@ -147,7 +147,7 @@ argp_default_parser (int key, char *arg, struct argp_state *state) + break; + + case OPT_HANG: +- _argp_hang = atoi (arg ? arg : "3600"); ++ _argp_hang = arg ? strtol (arg, NULL, 10) : 3600; + while (_argp_hang-- > 0) + __sleep (1); + break; +diff --git a/inet/rexec.c b/inet/rexec.c +index 064e979d68..c647b7ac34 100644 +--- a/inet/rexec.c ++++ b/inet/rexec.c +@@ -134,7 +134,7 @@ retry: + if (!getnameinfo(&sa2.sa, sa2len, + NULL, 0, servbuff, sizeof(servbuff), + NI_NUMERICSERV)) +- port = atoi(servbuff); ++ port = strtol(servbuff, NULL, 10); + (void) sprintf(num, "%u", port); + (void) __write(s, num, strlen(num)+1); + { socklen_t len = sizeof (from); +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 2c0bea658e..61b958a437 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -654,7 +654,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + /* Search for and process individual options. */ + if (!strncmp (cp, "ndots:", sizeof ("ndots:") - 1)) + { +- int i = atoi (cp + sizeof ("ndots:") - 1); ++ int i = strtol (cp + sizeof ("ndots:") - 1, NULL, 10); + if (i <= RES_MAXNDOTS) + parser->template.ndots = i; + else +@@ -662,7 +662,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + } + else if (!strncmp (cp, "timeout:", sizeof ("timeout:") - 1)) + { +- int i = atoi (cp + sizeof ("timeout:") - 1); ++ int i = strtol (cp + sizeof ("timeout:") - 1, NULL, 10); + if (i <= RES_MAXRETRANS) + parser->template.retrans = i; + else +@@ -670,7 +670,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + } + else if (!strncmp (cp, "attempts:", sizeof ("attempts:") - 1)) + { +- int i = atoi (cp + sizeof ("attempts:") - 1); ++ int i = strtol (cp + sizeof ("attempts:") - 1, NULL, 10); + if (i <= RES_MAXRETRY) + parser->template.retry = i; + else +-- +2.33.0 + diff --git a/backport-gmon-fix-memory-corruption-issues-BZ-30101.patch b/backport-gmon-fix-memory-corruption-issues-BZ-30101.patch new file mode 100644 index 0000000000000000000000000000000000000000..61606e544df5ecc97d7c9ee511f15e4888705439 --- /dev/null +++ b/backport-gmon-fix-memory-corruption-issues-BZ-30101.patch @@ -0,0 +1,194 @@ +From bde121872001d8f3224eeafa5b7effb871c3fbca Mon Sep 17 00:00:00 2001 +From: Simon Kissane +Date: Sat, 11 Feb 2023 08:58:02 +1100 +Subject: [PATCH] gmon: fix memory corruption issues [BZ# 30101] + +V2 of this patch fixes an issue in V1, where the state was changed to ON not +OFF at end of _mcleanup. I hadn't noticed that (counterintuitively) ON=0 and +OFF=3, hence zeroing the buffer turned it back on. So set the state to OFF +after the memset. + +1. Prevent double free, and reads from unallocated memory, when + _mcleanup is (incorrectly) called two or more times in a row, + without an intervening call to __monstartup; with this patch, the + second and subsequent calls effectively become no-ops instead. + While setting tos=NULL is minimal fix, safest action is to zero the + whole gmonparam buffer. + +2. Prevent memory leak when __monstartup is (incorrectly) called two + or more times in a row, without an intervening call to _mcleanup; + with this patch, the second and subsequent calls effectively become + no-ops instead. + +3. After _mcleanup, treat __moncontrol(1) as __moncontrol(0) instead. + With zeroing of gmonparam buffer in _mcleanup, this stops the + state incorrectly being changed to GMON_PROF_ON despite profiling + actually being off. If we'd just done the minimal fix to _mcleanup + of setting tos=NULL, there is risk of far worse memory corruption: + kcount would point to deallocated memory, and the __profil syscall + would make the kernel write profiling data into that memory, + which could have since been reallocated to something unrelated. + +4. Ensure __moncontrol(0) still turns off profiling even in error + state. Otherwise, if mcount overflows and sets state to + GMON_PROF_ERROR, when _mcleanup calls __moncontrol(0), the __profil + syscall to disable profiling will not be invoked. _mcleanup will + free the buffer, but the kernel will still be writing profiling + data into it, potentially corrupted arbitrary memory. + +Also adds a test case for (1). Issues (2)-(4) are not feasible to test. + +Signed-off-by: Simon Kissane +Reviewed-by: DJ Delorie +--- + gmon/Makefile | 15 ++++++++++++++- + gmon/gmon.c | 26 +++++++++++++++++++------- + gmon/tst-mcleanup.c | 31 +++++++++++++++++++++++++++++++ + 3 files changed, 64 insertions(+), 8 deletions(-) + create mode 100644 gmon/tst-mcleanup.c + +diff --git a/gmon/Makefile b/gmon/Makefile +index 706f50f7..475e533c 100644 +--- a/gmon/Makefile ++++ b/gmon/Makefile +@@ -1,4 +1,5 @@ + # Copyright (C) 1995-2021 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -25,7 +26,7 @@ include ../Makeconfig + headers := sys/gmon.h sys/gmon_out.h sys/profil.h + routines := gmon mcount profil sprofil prof-freq + +-tests = tst-sprofil tst-gmon tst-mcount-overflow ++tests = tst-sprofil tst-gmon tst-mcount-overflow tst-mcleanup + ifeq ($(build-profile),yes) + tests += tst-profile-static + tests-static += tst-profile-static +@@ -68,6 +69,14 @@ ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-mcount-overflow-check.out + endif + ++CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg ++tst-mcleanup-no-pie = yes ++CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) ++tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-mcleanup.out ++endif ++ + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg + CRT-tst-gmon-static := $(csu-objpfx)gcrt1.o + tst-gmon-static-no-pie = yes +@@ -123,6 +132,10 @@ $(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)ts + $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ + $(evaluate-test) + ++$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data ++clean-tst-mcleanup-data: ++ rm -f $(objpfx)tst-mcleanup.data.* ++ + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ + $(evaluate-test) +diff --git a/gmon/gmon.c b/gmon/gmon.c +index 689bf801..5e99a735 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -102,11 +102,8 @@ __moncontrol (int mode) + { + struct gmonparam *p = &_gmonparam; + +- /* Don't change the state if we ran into an error. */ +- if (p->state == GMON_PROF_ERROR) +- return; +- +- if (mode) ++ /* Treat start request as stop if error or gmon not initialized. */ ++ if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) + { + /* start */ + __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); +@@ -116,7 +113,9 @@ __moncontrol (int mode) + { + /* stop */ + __profil(NULL, 0, 0, 0); +- p->state = GMON_PROF_OFF; ++ /* Don't change the state if we ran into an error. */ ++ if (p->state != GMON_PROF_ERROR) ++ p->state = GMON_PROF_OFF; + } + } + libc_hidden_def (__moncontrol) +@@ -146,6 +145,14 @@ __monstartup (u_long lowpc, u_long highpc) + maxarcs = MAXARCS; + #endif + ++ /* ++ * If we are incorrectly called twice in a row (without an ++ * intervening call to _mcleanup), ignore the second call to ++ * prevent leaking memory. ++ */ ++ if (p->tos != NULL) ++ return; ++ + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. +@@ -463,9 +470,14 @@ _mcleanup (void) + { + __moncontrol (0); + +- if (_gmonparam.state != GMON_PROF_ERROR) ++ if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) + write_gmon (); + + /* free the memory. */ + free (_gmonparam.tos); ++ ++ /* reset buffer to initial state for safety */ ++ memset(&_gmonparam, 0, sizeof _gmonparam); ++ /* somewhat confusingly, ON=0, OFF=3 */ ++ _gmonparam.state = GMON_PROF_OFF; + } +diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c +new file mode 100644 +index 00000000..b259653e +--- /dev/null ++++ b/gmon/tst-mcleanup.c +@@ -0,0 +1,31 @@ ++/* Test program for repeated invocation of _mcleanup ++ Copyright The GNU Toolchain Authors. ++ 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 ++ . */ ++ ++/* Intentionally calls _mcleanup() twice: once manually, it will be ++ called again as an atexit handler. This is incorrect use of the API, ++ but the point of the test is to make sure we don't crash when the ++ API is misused in this way. */ ++ ++#include ++ ++int ++main (void) ++{ ++ _mcleanup(); ++ return 0; ++} +-- +2.33.0 + diff --git a/backport-gmon-improve-mcount-overflow-handling-BZ-27576.patch b/backport-gmon-improve-mcount-overflow-handling-BZ-27576.patch new file mode 100644 index 0000000000000000000000000000000000000000..c303e1823311db92990ad0adfa391b89a86062a6 --- /dev/null +++ b/backport-gmon-improve-mcount-overflow-handling-BZ-27576.patch @@ -0,0 +1,424 @@ +From 31be941e4367c001b2009308839db5c67bf9dcbc Mon Sep 17 00:00:00 2001 +From: Simon Kissane +Date: Sat, 11 Feb 2023 20:12:13 +1100 +Subject: [PATCH] gmon: improve mcount overflow handling [BZ# 27576] + +When mcount overflows, no gmon.out file is generated, but no message is printed +to the user, leaving the user with no idea why, and thinking maybe there is +some bug - which is how BZ 27576 ended up being logged. Print a message to +stderr in this case so the user knows what is going on. + +As a comment in sys/gmon.h acknowledges, the hardcoded MAXARCS value is too +small for some large applications, including the test case in that BZ. Rather +than increase it, add tunables to enable MINARCS and MAXARCS to be overridden +at runtime (glibc.gmon.minarcs and glibc.gmon.maxarcs). So if a user gets the +mcount overflow error, they can try increasing maxarcs (they might need to +increase minarcs too if the heuristic is wrong in their case.) + +Note setting minarcs/maxarcs too large can cause monstartup to fail with an +out of memory error. If you set them large enough, it can cause an integer +overflow in calculating the buffer size. I haven't done anything to defend +against that - it would not generally be a security vulnerability, since these +tunables will be ignored in suid/sgid programs (due to the SXID_ERASE default), +and if you can set GLIBC_TUNABLES in the environment of a process, you can take +it over anyway (LD_PRELOAD, LD_LIBRARY_PATH, etc). I thought about modifying +the code of monstartup to defend against integer overflows, but doing so is +complicated, and I realise the existing code is susceptible to them even prior +to this change (e.g. try passing a pathologically large highpc argument to +monstartup), so I decided just to leave that possibility in-place. + +Add a test case which demonstrates mcount overflow and the tunables. + +Document the new tunables in the manual. + +Signed-off-by: Simon Kissane +Reviewed-by: DJ Delorie +--- + elf/dl-tunables.list | 13 ++++++ + gmon/Makefile | 22 +++++++++- + gmon/gmon.c | 29 +++++++++++-- + gmon/mcount.c | 5 +++ + gmon/sys/gmon.h | 6 ++- + gmon/tst-mcount-overflow-check.sh | 45 +++++++++++++++++++ + gmon/tst-mcount-overflow.c | 72 +++++++++++++++++++++++++++++++ + manual/tunables.texi | 59 +++++++++++++++++++++++++ + 8 files changed, 244 insertions(+), 7 deletions(-) + create mode 100644 gmon/tst-mcount-overflow-check.sh + create mode 100644 gmon/tst-mcount-overflow.c + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 379701b8..ea19387d 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -160,4 +160,17 @@ glibc { + security_level: SXID_IGNORE + } + } ++ ++ gmon { ++ minarcs { ++ type: INT_32 ++ minval: 50 ++ default: 50 ++ } ++ maxarcs { ++ type: INT_32 ++ minval: 50 ++ default: 1048576 ++ } ++ } + } +diff --git a/gmon/Makefile b/gmon/Makefile +index 7b7b8543..706f50f7 100644 +--- a/gmon/Makefile ++++ b/gmon/Makefile +@@ -25,7 +25,7 @@ include ../Makeconfig + headers := sys/gmon.h sys/gmon_out.h sys/profil.h + routines := gmon mcount profil sprofil prof-freq + +-tests = tst-sprofil tst-gmon ++tests = tst-sprofil tst-gmon tst-mcount-overflow + ifeq ($(build-profile),yes) + tests += tst-profile-static + tests-static += tst-profile-static +@@ -56,6 +56,18 @@ ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-gmon-gprof.out + endif + ++CFLAGS-tst-mcount-overflow.c := -fno-omit-frame-pointer -pg ++tst-mcount-overflow-no-pie = yes ++CRT-tst-mcount-overflow := $(csu-objpfx)g$(start-installed-name) ++# Intentionally use invalid config where maxarcs&1 1>/dev/null | cat ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-mcount-overflow-check.out ++endif ++ + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg + CRT-tst-gmon-static := $(csu-objpfx)gcrt1.o + tst-gmon-static-no-pie = yes +@@ -103,6 +115,14 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data + clean-tst-gmon-data: + rm -f $(objpfx)tst-gmon.data.* + ++$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data ++clean-tst-mcount-overflow-data: ++ rm -f $(objpfx)tst-mcount-overflow.data.* ++ ++$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out ++ $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ ++ $(evaluate-test) ++ + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ + $(evaluate-test) +diff --git a/gmon/gmon.c b/gmon/gmon.c +index bf76358d..689bf801 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -46,6 +46,11 @@ + #include + #include + ++#if HAVE_TUNABLES ++# define TUNABLE_NAMESPACE gmon ++# include ++#endif ++ + #ifdef PIC + # include + +@@ -124,6 +129,22 @@ __monstartup (u_long lowpc, u_long highpc) + int o; + char *cp; + struct gmonparam *p = &_gmonparam; ++ long int minarcs, maxarcs; ++ ++#if HAVE_TUNABLES ++ /* Read minarcs/maxarcs tunables. */ ++ minarcs = TUNABLE_GET (minarcs, int32_t, NULL); ++ maxarcs = TUNABLE_GET (maxarcs, int32_t, NULL); ++ if (maxarcs < minarcs) ++ { ++ ERR("monstartup: maxarcs < minarcs, setting maxarcs = minarcs\n"); ++ maxarcs = minarcs; ++ } ++#else ++ /* No tunables, we use hardcoded defaults */ ++ minarcs = MINARCS; ++ maxarcs = MAXARCS; ++#endif + + /* + * round lowpc and highpc to multiples of the density we're using +@@ -146,10 +167,10 @@ __monstartup (u_long lowpc, u_long highpc) + } + p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); + p->tolimit = p->textsize * ARCDENSITY / 100; +- if (p->tolimit < MINARCS) +- p->tolimit = MINARCS; +- else if (p->tolimit > MAXARCS) +- p->tolimit = MAXARCS; ++ if (p->tolimit < minarcs) ++ p->tolimit = minarcs; ++ else if (p->tolimit > maxarcs) ++ p->tolimit = maxarcs; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); +diff --git a/gmon/mcount.c b/gmon/mcount.c +index 9d4a1a50..f7180fdb 100644 +--- a/gmon/mcount.c ++++ b/gmon/mcount.c +@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; + + #include + ++#include ++#include ++#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1) ++ + /* + * mcount is called on entry to each function compiled with the profiling + * switch set. _mcount(), which is declared in a machine-dependent way +@@ -170,6 +174,7 @@ done: + return; + overflow: + p->state = GMON_PROF_ERROR; ++ ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n"); + return; + } + +diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h +index b4cc3b04..af0582a3 100644 +--- a/gmon/sys/gmon.h ++++ b/gmon/sys/gmon.h +@@ -111,6 +111,8 @@ extern struct __bb *__bb_head; + * Always allocate at least this many tostructs. This + * hides the inadequacy of the ARCDENSITY heuristic, at least + * for small programs. ++ * ++ * Value can be overridden at runtime by glibc.gmon.minarcs tunable. + */ + #define MINARCS 50 + +@@ -124,8 +126,8 @@ extern struct __bb *__bb_head; + * Used to be max representable value of ARCINDEX minus 2, but now + * that ARCINDEX is a long, that's too large; we don't really want + * to allow a 48 gigabyte table. +- * The old value of 1<<16 wasn't high enough in practice for large C++ +- * programs; will 1<<20 be adequate for long? FIXME ++ * ++ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable. + */ + #define MAXARCS (1 << 20) + +diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh +new file mode 100644 +index 00000000..27eb5538 +--- /dev/null ++++ b/gmon/tst-mcount-overflow-check.sh +@@ -0,0 +1,45 @@ ++#!/bin/sh ++# Test expected messages generated when mcount overflows ++# Copyright (C) 2017-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. ++# 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 ++# . ++ ++LC_ALL=C ++export LC_ALL ++set -e ++exec 2>&1 ++ ++program="$1" ++ ++check_msg() { ++ if ! grep -q "$1" "$program.out"; then ++ echo "FAIL: expected message not in output: $1" ++ exit 1 ++ fi ++} ++ ++check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs' ++check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated' ++ ++for data_file in $1.data.*; do ++ if [ -f "$data_file" ]; then ++ echo "FAIL: expected no data files, but found $data_file" ++ exit 1 ++ fi ++done ++ ++echo PASS +diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c +new file mode 100644 +index 00000000..06cc93ef +--- /dev/null ++++ b/gmon/tst-mcount-overflow.c +@@ -0,0 +1,72 @@ ++/* Test program to trigger mcount overflow in profiling collection. ++ Copyright (C) 2017-2023 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 ++ . */ ++ ++/* Program with sufficiently complex, yet pointless, call graph ++ that it will trigger an mcount overflow, when you set the ++ minarcs/maxarcs tunables to very low values. */ ++ ++#define PREVENT_TAIL_CALL asm volatile ("") ++ ++/* Calls REP(n) macro 16 times, for n=0..15. ++ * You need to define REP(n) before using this. ++ */ ++#define REPS \ ++ REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \ ++ REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15) ++ ++/* Defines 16 leaf functions named f1_0 to f1_15 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {}; ++REPS ++#undef REP ++ ++/* Calls all 16 leaf functions f1_* in succession */ ++__attribute__ ((noinline, noclone, weak)) void ++f2 (void) ++{ ++# define REP(n) f1_##n(); ++ REPS ++# undef REP ++ PREVENT_TAIL_CALL; ++} ++ ++/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void \ ++ f2_##n (void) { f2(); PREVENT_TAIL_CALL; }; ++REPS ++#undef REP ++ ++__attribute__ ((noinline, noclone, weak)) void ++f3 (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ { ++ /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */ ++# define REP(n) f1_##n(); f2_##n(); ++ REPS ++# undef REP ++ } ++} ++ ++int ++main (void) ++{ ++ f3 (1000); ++ return 0; ++} +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 00a83b0c..ff98a18f 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -77,6 +77,9 @@ glibc.malloc.check: 0 (min: 0, max: 3) + capabilities seen by @theglibc{} + * Memory Related Tunables:: Tunables that control the use of memory by + @theglibc{}. ++* gmon Tunables:: Tunables that control the gmon profiler, used in ++ conjunction with gprof ++ + @end menu + + @node Tunable names +@@ -598,3 +601,59 @@ support in the kernel if this tunable has any non-zero value. + + The default value is @samp{0}, which disables all memory tagging. + @end deftp ++ ++@node gmon Tunables ++@section gmon Tunables ++@cindex gmon tunables ++ ++@deftp {Tunable namespace} glibc.gmon ++This tunable namespace affects the behaviour of the gmon profiler. ++gmon is a component of @theglibc{} which is normally used in ++conjunction with gprof. ++ ++When GCC compiles a program with the @code{-pg} option, it instruments ++the program with calls to the @code{mcount} function, to record the ++program's call graph. At program startup, a memory buffer is allocated ++to store this call graph; the size of the buffer is calculated using a ++heuristic based on code size. If during execution, the buffer is found ++to be too small, profiling will be aborted and no @file{gmon.out} file ++will be produced. In that case, you will see the following message ++printed to standard error: ++ ++@example ++mcount: call graph buffer size limit exceeded, gmon.out will not be generated ++@end example ++ ++Most of the symbols discussed in this section are defined in the header ++@code{sys/gmon.h}. However, some symbols (for example @code{mcount}) ++are not defined in any header file, since they are only intended to be ++called from code generated by the compiler. ++@end deftp ++ ++@deftp Tunable glibc.mem.minarcs ++The heuristic for sizing the call graph buffer is known to be ++insufficient for small programs; hence, the calculated value is clamped ++to be at least a minimum size. The default minimum (in units of ++call graph entries, @code{struct tostruct}), is given by the macro ++@code{MINARCS}. If you have some program with an unusually complex ++call graph, for which the heuristic fails to allocate enough space, ++you can use this tunable to increase the minimum to a larger value. ++@end deftp ++ ++@deftp Tunable glibc.mem.maxarcs ++To prevent excessive memory consumption when profiling very large ++programs, the call graph buffer is allowed to have a maximum of ++@code{MAXARCS} entries. For some very large programs, the default ++value of @code{MAXARCS} defined in @file{sys/gmon.h} is too small; in ++that case, you can use this tunable to increase it. ++ ++Note the value of the @code{maxarcs} tunable must be greater or equal ++to that of the @code{minarcs} tunable; if this constraint is violated, ++a warning will printed to standard error at program startup, and ++the @code{minarcs} value will be used as the maximum as well. ++ ++Setting either tunable too high may result in a call graph buffer ++whose size exceeds the available memory; in that case, an out of memory ++error will be printed at program startup, the profiler will be ++disabled, and no @file{gmon.out} file will be generated. ++@end deftp +-- +2.33.0 + diff --git a/backport-posix-Fix-system-blocks-SIGCHLD-erroneously-BZ-30163.patch b/backport-posix-Fix-system-blocks-SIGCHLD-erroneously-BZ-30163.patch new file mode 100644 index 0000000000000000000000000000000000000000..78bebb6c6307fed4ead22429e6ef1ba04b2b3637 --- /dev/null +++ b/backport-posix-Fix-system-blocks-SIGCHLD-erroneously-BZ-30163.patch @@ -0,0 +1,290 @@ +From 436a604b7dc741fc76b5a6704c6cd8bb178518e7 Mon Sep 17 00:00:00 2001 +From: Adam Yi +Date: Tue, 7 Mar 2023 07:30:02 -0500 +Subject: [PATCH] posix: Fix system blocks SIGCHLD erroneously [BZ #30163] + +Fix bug that SIGCHLD is erroneously blocked forever in the following +scenario: + +1. Thread A calls system but hasn't returned yet +2. Thread B calls another system but returns + +SIGCHLD would be blocked forever in thread B after its system() returns, +even after the system() in thread A returns. + +Although POSIX does not require, glibc system implementation aims to be +thread and cancellation safe. This bug was introduced in +5fb7fc96350575c9adb1316833e48ca11553be49 when we moved reverting signal +mask to happen when the last concurrently running system returns, +despite that signal mask is per thread. This commit reverts this logic +and adds a test. + +Signed-off-by: Adam Yi +Reviewed-by: Adhemerval Zanella +--- + stdlib/tst-system.c | 26 +++++++++++++++++++ + support/Makefile | 2 ++ + support/dtotimespec-time64.c | 27 +++++++++++++++++++ + support/dtotimespec.c | 50 ++++++++++++++++++++++++++++++++++++ + support/shell-container.c | 28 ++++++++++++++++++++ + support/timespec.h | 4 +++ + sysdeps/posix/system.c | 6 ++--- + 7 files changed, 140 insertions(+), 3 deletions(-) + create mode 100644 support/dtotimespec-time64.c + create mode 100644 support/dtotimespec.c + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 178808e0..d1413d7c 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + + static char *tmpdir; +@@ -72,6 +73,20 @@ call_system (void *closure) + } + } + ++static void * ++sleep_and_check_sigchld (void *closure) ++{ ++ double *seconds = (double *) closure; ++ char cmd[namemax]; ++ sprintf (cmd, "sleep %lf" , *seconds); ++ TEST_COMPARE (system (cmd), 0); ++ ++ sigset_t blocked = {0}; ++ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0); ++ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0); ++ return NULL; ++} ++ + static int + do_test (void) + { +@@ -155,6 +170,17 @@ do_test (void) + xchmod (_PATH_BSHELL, st.st_mode); + } + ++ { ++ pthread_t long_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 0.2 }); ++ pthread_t short_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 0.1 }); ++ xpthread_join (short_sleep_thread); ++ xpthread_join (long_sleep_thread); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/support/Makefile b/support/Makefile +index 724ae6d7..936af554 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -32,6 +32,8 @@ libsupport-routines = \ + check_hostent \ + check_netent \ + delayed_exit \ ++ dtotimespec \ ++ dtotimespec-time64 \ + ignore_stderr \ + next_to_fault \ + oom_error \ +diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c +new file mode 100644 +index 00000000..b3d5e351 +--- /dev/null ++++ b/support/dtotimespec-time64.c +@@ -0,0 +1,27 @@ ++/* Convert double to timespec. 64-bit time support. ++ Copyright (C) 2011-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ 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 ++ ++#if __TIMESIZE != 64 ++# define timespec __timespec64 ++# define time_t __time64_t ++# define dtotimespec dtotimespec_time64 ++# include "dtotimespec.c" ++#endif +diff --git a/support/dtotimespec.c b/support/dtotimespec.c +new file mode 100644 +index 00000000..cde5b4d7 +--- /dev/null ++++ b/support/dtotimespec.c +@@ -0,0 +1,50 @@ ++/* Convert double to timespec. ++ Copyright (C) 2011-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ 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 ++ . */ ++ ++/* Convert the double value SEC to a struct timespec. Round toward ++ positive infinity. On overflow, return an extremal value. */ ++ ++#include ++#include ++ ++struct timespec ++dtotimespec (double sec) ++{ ++ if (sec <= TYPE_MINIMUM (time_t)) ++ return make_timespec (TYPE_MINIMUM (time_t), 0); ++ else if (sec >= 1.0 + TYPE_MAXIMUM (time_t)) ++ return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); ++ else ++ { ++ time_t s = sec; ++ double frac = TIMESPEC_HZ * (sec - s); ++ long ns = frac; ++ ns += ns < frac; ++ s += ns / TIMESPEC_HZ; ++ ns %= TIMESPEC_HZ; ++ ++ if (ns < 0) ++ { ++ s--; ++ ns += TIMESPEC_HZ; ++ } ++ ++ return make_timespec (s, ns); ++ } ++} +diff --git a/support/shell-container.c b/support/shell-container.c +index b2a4324d..6fe925dc 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -39,6 +39,7 @@ + #include + + #include ++#include + + /* Design considerations + +@@ -171,6 +172,32 @@ kill_func (char **argv) + return 0; + } + ++/* Emulate the "/bin/sleep" command. No suffix support. Options are ++ ignored. */ ++static int ++sleep_func (char **argv) ++{ ++ if (argv[0] == NULL) ++ { ++ fprintf (stderr, "sleep: missing operand\n"); ++ return 1; ++ } ++ char *endptr = NULL; ++ double sec = strtod (argv[0], &endptr); ++ if (endptr == argv[0] || errno == ERANGE || sec < 0) ++ { ++ fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]); ++ return 1; ++ } ++ struct timespec ts = dtotimespec (sec); ++ if (nanosleep (&ts, NULL) < 0) ++ { ++ fprintf (stderr, "sleep: failed to nanosleep: %s\n", strerror (errno)); ++ return 1; ++ } ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -181,6 +208,7 @@ static struct { + { "cp", copy_func }, + { "exit", exit_func }, + { "kill", kill_func }, ++ { "sleep", sleep_func }, + { NULL, NULL } + }; + +diff --git a/support/timespec.h b/support/timespec.h +index 0478aef5..843a90d6 100644 +--- a/support/timespec.h ++++ b/support/timespec.h +@@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected, + struct timespec observed, + double lower_bound, double upper_bound); + ++struct timespec dtotimespec (double sec) __attribute__((const)); ++ + #else + struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec), + timespec_add_time64); +@@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected, + double lower_bound, + double upper_bound), + support_timespec_check_in_range_time64); ++ ++struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64); + #endif + + /* Check that the timespec on the left represents a time before the +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 48668fb3..b9676abb 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -179,16 +179,16 @@ do_system (const char *line) + as if the shell had terminated using _exit(127). */ + status = W_EXITCODE (127, 0); + ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ + DO_LOCK (); + if (SUB_REF () == 0) + { +- /* sigaction can not fail with SIGINT/SIGQUIT used with old +- disposition. Same applies for sigprocmask. */ + __sigaction (SIGINT, &intr, NULL); + __sigaction (SIGQUIT, &quit, NULL); +- __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + + if (ret != 0) + __set_errno (ret); +-- +2.33.0 + diff --git a/backport-stdlib-Undo-post-review-change-to-16adc58e73f3-BZ-27.patch b/backport-stdlib-Undo-post-review-change-to-16adc58e73f3-BZ-27.patch new file mode 100644 index 0000000000000000000000000000000000000000..efcbff9bc76961c8eb6580bfdc527d8836f9b577 --- /dev/null +++ b/backport-stdlib-Undo-post-review-change-to-16adc58e73f3-BZ-27.patch @@ -0,0 +1,140 @@ +From fd78cfa72ea2bab30fdb4e1e0672b34471426c05 Mon Sep 17 00:00:00 2001 +From: Vitaly Buka +Date: Sat, 18 Feb 2023 12:53:41 -0800 +Subject: [PATCH] stdlib: Undo post review change to 16adc58e73f3 [BZ #27749] + +Post review removal of "goto restart" from +https://sourceware.org/pipermail/libc-alpha/2021-April/125470.html +introduced a bug when some atexit handers skipped. + +Signed-off-by: Vitaly Buka + +Reviewed-by: Adhemerval Zanella +--- + stdlib/Makefile | 1 + + stdlib/exit.c | 7 +++- + stdlib/test-atexit-recursive.c | 75 ++++++++++++++++++++++++++++++++++ + 3 files changed, 81 insertions(+), 2 deletions(-) + create mode 100644 stdlib/test-atexit-recursive.c + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index a4ac30d1..73cd3370 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -73,6 +73,7 @@ tests := \ + test-a64l \ + test-at_quick_exit-race \ + test-atexit-race \ ++ test-atexit-recursive \ + test-bz22786 \ + test-canon \ + test-canon2 \ +diff --git a/stdlib/exit.c b/stdlib/exit.c +index 453eb85b..546343f7 100644 +--- a/stdlib/exit.c ++++ b/stdlib/exit.c +@@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + exit (). */ + while (true) + { +- struct exit_function_list *cur = *listp; ++ struct exit_function_list *cur; ++ ++ restart: ++ cur = *listp; + + if (cur == NULL) + { +@@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called)) + /* The last exit function, or another thread, has registered + more exit functions. Start the loop over. */ +- continue; ++ goto restart; + } + + *listp = cur->next; +diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c +new file mode 100644 +index 00000000..0596b976 +--- /dev/null ++++ b/stdlib/test-atexit-recursive.c +@@ -0,0 +1,75 @@ ++/* Support file for atexit/exit, etc. race tests (BZ #27749). ++ Copyright (C) 2023 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 ++ . */ ++ ++/* Check that atexit handler registed from another handler still called. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++atexit_cb (void) ++{ ++} ++ ++static void ++atexit_last (void) ++{ ++ _exit (1); ++} ++ ++static void ++atexit_recursive (void) ++{ ++ atexit (&atexit_cb); ++ atexit (&atexit_last); ++} ++ ++_Noreturn static void ++test_and_exit (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ atexit (&atexit_cb); ++ atexit (&atexit_recursive); ++ exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < 100; ++i) ++ if (xfork () == 0) ++ test_and_exit (i); ++ ++ for (int i = 0; i < 100; ++i) ++ { ++ int status; ++ xwaitpid (0, &status, 0); ++ if (!WIFEXITED (status)) ++ FAIL_EXIT1 ("Failed iterations %d", i); ++ TEST_COMPARE (WEXITSTATUS (status), 1); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test ++#include +-- +2.33.0 + diff --git a/glibc.spec b/glibc.spec index 0e59804650b619ac9520f8483f8ea3a6bbab7275..e90cf1d1ba595fa45afcb03936dcc11cda608c82 100644 --- a/glibc.spec +++ b/glibc.spec @@ -66,7 +66,7 @@ ############################################################################## Name: glibc Version: 2.34 -Release: 114 +Release: 115 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ @@ -247,6 +247,11 @@ Patch159: io-Fix-use-after-free-in-ftw-BZ-26779.patch Patch160: backport-x86-Fix-wcsnlen-avx2-page-cross-length-comparison-BZ.patch Patch161: gmon-Fix-allocated-buffer-overflow-bug-29444.patch Patch162: malloc-Fix-transposed-arguments-in-sysmalloc_mmap_fa.patch +Patch163: backport-Avoid-use-of-atoi-in-some-places-in-libc.patch +Patch164: backport-stdlib-Undo-post-review-change-to-16adc58e73f3-BZ-27.patch +patch165: backport-gmon-improve-mcount-overflow-handling-BZ-27576.patch +Patch166: backport-gmon-fix-memory-corruption-issues-BZ-30101.patch +Patch167: backport-posix-Fix-system-blocks-SIGCHLD-erroneously-BZ-30163.patch Patch9000: turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch @@ -1453,6 +1458,13 @@ fi %endif %changelog +* Sat Mar 25 2023 shixuantong - 2.34-115 +- Avoid use of atoi in some places in libc +- stdlib: Undo post review change to 16adc58e73f3 +- gmon: improve mcount overflow handling +- gmon: fix memory corruption issues +- posix: Fix system blocks SIGCHLD erroneously + * Sat Mar 25 2023 Chen Ziyang - 2.34-114 - elf/ld.so: fix 2 bugs in ld.so mmap shared object use hugepage - bugfix: ld.so mmap now first mmap 2MB continuous memory by MAP_NORESERVE flag because we do not want to revert to 4KB when 2MB resources is smaller then entire so. We want to check resources happend in later _mmap_segment_filesz function