From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.2 required=3.0 tests=AWL,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,NICE_REPLY_A, RCVD_IN_DNSWL_MED,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id 65ECC1F4B4 for ; Sun, 20 Sep 2020 23:15:55 +0000 (UTC) Received: from localhost ([::1]:34720 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kK8Yk-0000d6-95 for normalperson@yhbt.net; Sun, 20 Sep 2020 19:15:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45724) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kK8Yd-0000bq-RL; Sun, 20 Sep 2020 19:15:49 -0400 Received: from zimbra.cs.ucla.edu ([131.179.128.68]:54752) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kK8YZ-000645-Pv; Sun, 20 Sep 2020 19:15:47 -0400 Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 1F1B0160066; Sun, 20 Sep 2020 16:15:39 -0700 (PDT) Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id YZdCNi2bW2fm; Sun, 20 Sep 2020 16:15:36 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 941401600EA; Sun, 20 Sep 2020 16:15:36 -0700 (PDT) X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 08qfC0Uyz_P0; Sun, 20 Sep 2020 16:15:36 -0700 (PDT) Received: from [192.168.1.9] (cpe-75-82-69-226.socal.res.rr.com [75.82.69.226]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id 5238A160066; Sun, 20 Sep 2020 16:15:36 -0700 (PDT) Subject: Re: libsigsegv on LinuxFromScratch To: Bruno Haible References: <30574f07-50f3-c3f0-7ec6-e21bac053db4@gmail.com> <2841b553-b4c7-6216-54be-51805c87af9a@gmail.com> <1651225.mJHhjzxva5@omega> From: Paul Eggert Autocrypt: addr=eggert@cs.ucla.edu; prefer-encrypt=mutual; keydata= LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgptUUlOQkV5QWNtUUJFQURB QXlIMnhvVHU3cHBHNUQzYThGTVpFb243NGRDdmM0K3ExWEEySjJ0QnkycHdhVHFmCmhweHhk R0E5Smo1MFVKM1BENGJTVUVnTjh0TFowc2FuNDdsNVhUQUZMaTI0NTZjaVNsNW04c0thSGxH ZHQ5WG0KQUF0bVhxZVpWSVlYL1VGUzk2ZkR6ZjR4aEVtbS95N0xiWUVQUWRVZHh1NDd4QTVL aFRZcDVibHRGM1dZRHoxWQpnZDdneDA3QXV3cDdpdzdlTnZub0RUQWxLQWw4S1lEWnpiRE5D UUdFYnBZM2VmWkl2UGRlSStGV1FONFcra2doCnkrUDZhdTZQcklJaFlyYWV1YTdYRGRiMkxT MWVuM1NzbUUzUWpxZlJxSS9BMnVlOEpNd3N2WGUvV0szOEV6czYKeDc0aVRhcUkzQUZINmls QWhEcXBNbmQvbXNTRVNORnQ3NkRpTzFaS1FNcjlhbVZQa25qZlBtSklTcWRoZ0IxRApsRWR3 MzRzUk9mNlY4bVp3MHhmcVQ2UEtFNDZMY0ZlZnpzMGtiZzRHT1JmOHZqRzJTZjF0azVlVThN Qml5Ti9iClowM2JLTmpOWU1wT0REUVF3dVA4NGtZTGtYMndCeHhNQWhCeHdiRFZadWR6eERa SjFDMlZYdWpDT0pWeHEya2wKakJNOUVUWXVVR3FkNzVBVzJMWHJMdzYrTXVJc0hGQVlBZ1Jy NytLY3dEZ0JBZndoUEJZWDM0blNTaUhsbUxDKwpLYUhMZUNMRjVaSTJ2S20zSEVlQ1R0bE9n N3haRU9OZ3d6TCtmZEtvK0Q2U29DOFJSeEpLczhhM3NWZkk0dDZDCm5yUXp2SmJCbjZneGRn Q3U1aTI5SjFRQ1lyQ1l2cWwyVXlGUEFLK2RvOTkvMWpPWFQ0bTI4MzZqMXdBUkFRQUIKdENC UVlYVnNJRVZuWjJWeWRDQThaV2RuWlhKMFFHTnpMblZqYkdFdVpXUjFQb2tDVlFRVEFRZ0FQ d0liQXdZTApDUWdIQXdJR0ZRZ0NDUW9MQkJZQ0F3RUNIZ0VDRjRBV0lRUitONUtwMkt6MzFq TzhGWWp0bCtrT1lxcCtOQVVDClh5Vzlsd1VKRks0THN3QUtDUkR0bCtrT1lxcCtOS05WRC85 SE1zSTE2MDZuMFV1VFhId0lUc3lPakFJOVNET1QKK0MzRFV2NnFsTTVCSDJuV0FNVGlJaXlB NXVnbHNKdjkzb2kydk50RmYvUS9tLzFjblpXZ25WbkV4a3lMSTRFTgpTZDF1QnZyMC9sQ1Nk UGxQME1nNkdXU3BYTXUreDB2ZFQwQWFaTk9URTBGblB1b2xkYzNYRDc2QzJxZzhzWC9pCmF4 WFRLSHk5UCtCbEFxL0NzNy9weERRMEV6U24wVVNaMkMwbDV2djRQTXBBL3BpY25TNks2MDlK dkRHYU9SbXcKWmVYSVpxUU5aVitaUXMrVVl0Vm9ndURUcWJ5M0lVWTFJOEJsWEhScHRhajlB TW40VW9oL0NxcFFsVm9qb3lXbApIcWFGbm5KQktlRjBodko5U0F5YWx3dXpBakc3dlFXMDdN WW5jYU9GbTB3b2lLYmc1SkxPOEY0U0JUSWt1TzBECkNmOW5MQWF5NlZzQjRyendkRWZSd2pQ TFlBbjdNUjNmdkhDRXpmcmtsZFRyYWlCTzFUMGllREs4MEk3c0xmNnAKTWVDWUkxOXBVbHgw L05STUdDZGRpRklRZGZ0aEtXWEdSUzVMQXM4andCZjhINkc1UFdpblByRUlhb21JUDIxaQp2 dWhRRDA3YllxOUlpSWRlbGpqVWRIY0dJMGkvQjRNNTZaYWE4RmYzOGluaU9sckRZQ21ZV1I0 ZENXWml1UWVaCjNPZ3FlUXM5YTZqVHZnZERHVm1SVnFZK2p6azhQbGFIZmNvazhST2hGY0hL a2NmaHVCaEwyNWhsUklzaFJET0UKc2tYcUt3bnpyYnFnYTNHWFpYZnNYQW9GYnpOaExkTHY5 QStMSkFZU2tYUDYvNXFkVHBFTFZHb3N5SDg4NFZkYgpCcGtHSTA0b1lWcXVsYmtDRFFSTWdI SmtBUkFBcG9YcnZ4UDNESWZqQ05PdFhVL1Bkd01TaEtkWC9SbFNzNVBmCnVuVjF3YktQOGhl clhIcnZRZEZWcUVDYVRTeG1saHpiazhYMFBrWTlnY1ZhVTJPNDlUM3FzT2QxY0hlRjUyWUYK R0V0MExoc0JlTWpnTlg1dVoxVjc2cjhneWVWbEZwV1diMFNJd0pVQkhyRFhleEY2N3VwZVJi MnZkSEJqWUROZQp5U24rMEI3Z0ZFcXZWbVp1K0xhZHVkRHA2a1FMamF0RnZIUUhVU0dOc2hC bmtrY2FUYmlJOVBzdDBHQ2MyYWl6Cm5CaVBQQTJXUXhBUGxQUmgzT0dUc241VEhBRG1ianFZ NkZFTUxhc1ZYOERTQ2JsTXZMd05lTy84U3h6aUJpZGgKcUxwSkNxZFFSV0hrdTVYeGdJa0dl S096NU9MRHZYSFdKeWFmckVZamprUzZBazZCNXo2c3ZLbGlDbFduakhRYwpqbFB6eW9GRmdL VEVmY3FEeENqNFJZMEQwRGd0RkQwTmZ5ZU9pZHJTQi9TelRlMmh3cnlRRTNycFNpcW8rMGNH CmR6aDR5QUhLWUorVXJYWjRwOTNaaGpHZktEMXhsck5ZRGxXeVc5UEdtYnZxRnVEbWlJQVFm OVdEL3d6RWZJQ2MKK0YrdURESSt1WWtSeFVGcDkyeWttZGhERUZnMXlqWXNVOGlHVTY5YUh5 dmhxMzZ6NHpjdHZicWhSTnpPV0IxYgpWSi9kSU1EdnNFeEdjWFFWRElUN3NETlh2MHdFM2pL U0twcDdOREcxb1hVWEwrMitTRjk5S2p5NzUzQWJRU0FtCkg2MTdmeUJOd2hKV3ZRWWcrbVV2 UHBpR090c2VzOUVYVUkzbFM0djBNRWFQRzQzZmxFczFVUisxcnBGUVdWSG8KMXkxT08rc0FF UUVBQVlrQ1BBUVlBUWdBSmdJYkRCWWhCSDQza3FuWXJQZldNN3dWaU8yWDZRNWlxbjQwQlFK ZgpKYjJ6QlFrVXJndlBBQW9KRU8yWDZRNWlxbjQwY25NUC8xN0NnVWtYVDlhSUpyaVBNOHdi Y2VZcmNsNytiZFlFCmY3OVNsd1NiYkhON1I0Q29JSkZPbE45Uy8zNHR5cEdWWXZwZ21DSkRZ RlRCeHlQTzkyaU1YRGdBNCtjV0h6dDUKVDFhWU85aHNLaGg3dkR0Sys2UHJvWkdjKzA4Z1VU WEhoYjk3aE1NUWhrbkpsbmZqcFNFQzllbTkwNkZVK0k5MwpUMWZUR3VwbkJhM2FXY0s4ak0w SmFCR2J5MmhHMVMzb2xhRExTVHRCSU5OQlltdnVXUjlNS09oaHFEcmxrNWN3CkZESkxoNU5y WHRlRVkwOFdBemNMekczcGtyWFBIa0ZlTVF0ZnFrMGpMZEdHdkdDM05DSWtxWXJkTGhpUnZH cHIKdTM4QzI2UkVuNWY0STB2R0UzVmZJWEhlOFRNQ05tUXV0MU50TXVVbXBESXkxYUx4R3p1 cHRVaG5PSk4vL3IrVgpqRFBvaTNMT3lTTllwaHFlL2RNdWJzZlVyNm9oUDQxbUtGODFGdXdJ NGFtcUp0cnFJTDJ5cWF4M2EwcWxmd0N4ClhmdGllcUpjdWVrWCtlQ1BEQ0tyWU1YUjBGWWd3 cEcySVRaVUd0ckVqRVNsRTZEc2N4NzM0SEtkcjVPUklvY0wKVVVLRU9HZWlVNkRHaEdGZGI1 VHd1MFNuK3UxbVVQRE4wTSsrQ2RNdkNsSUU4a2xvNEc5MUVPSW11MVVwYjh4YwpPUFF3eGgx andxU3JVNVF3b05tU1llZ1FTSExwSVV1ckZ6MWlRVWgxdnBQWHpLaW5rV0VxdjRJcUExY2lM K0x5CnlTdUxrcDdNc0pwVlJNYldKQ05XT09TYmFING9EQko1ZEhNR2MzNXg1bW9zQ2s5MFBY a251RkREc1lIZkRvNXMKbWY5bG82WVh4N045Cj0zTGFJCi0tLS0tRU5EIFBHUCBQVUJMSUMg S0VZIEJMT0NLLS0tLS0K Organization: UCLA Computer Science Department Message-ID: Date: Sun, 20 Sep 2020 16:15:35 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <1651225.mJHhjzxva5@omega> Content-Type: multipart/mixed; boundary="------------936512A241C3F572F212D46A" Content-Language: en-US Received-SPF: pass client-ip=131.179.128.68; envelope-from=eggert@cs.ucla.edu; helo=zimbra.cs.ucla.edu X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/20 19:15:39 X-ACL-Warn: Detected OS = Linux 3.1-3.10 [fuzzy] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, NICE_REPLY_A=-0.001, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: bug-gnulib@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Gnulib discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: GNU grep developers , bug-gnulib@gnu.org, Bruce Dubbs , Jim Meyering Errors-To: bug-gnulib-bounces+normalperson=yhbt.net@gnu.org Sender: "bug-gnulib" This is a multi-part message in MIME format. --------------936512A241C3F572F212D46A Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 9/19/20 4:47 PM, Bruno Haible wrote: > havelib: Avoid linking with libc.a on GNU systems. Thanks for fixing the bug. This caused me to look at the c-stack module for the first time in a while, and I found some old-fashioned code and some unlikely bugs and fixed one misfeature when libsigsegv is not in use. I installed the attached patches to the c-stack module in Gnulib to try to fix it. These changes shouldn't affect how c-stack behaves when libsigsegv is in use. While looking into this I discovered pthread_getattr_np + pthread_attr_getstack which might have been nice for the GNU/Linux part of c-stack.c, except they're not async-signal-safe. As I understand it, libsigsegv works around the async-signal-safe problem by parsing /proc/self/maps with async-signal-safe functions, which is quite a feat and is probably beyond what c-stack should do. PS. I also found this circa-2015 Linux kernel bug related to PIE that looks like it might be of interest to the libsigsegv developers https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-1000253 This bug causes /proc/self/maps to report the wrong VMA (actually, overlapping VMAs) for the stack. This could be worth a comment in the libsigsegv sources. For more commentary in this area please see: https://stackoverflow.com/questions/56893353/analyzing-memory-mapping-of-a-process-with-pmap-stack/56920770 PPS. Given the longstanding security problems with stack overflow (as witness the name stackoverflow.com!) it is somewhat disturbing that there is still no reliable way in GNU/Linux to answer the simple question "Where's my stack?" or to detect and recover from stack overflow reliably. What's up with that? --------------936512A241C3F572F212D46A Content-Type: text/x-patch; charset=UTF-8; name="0001-c-stack-improve-checking-if-libsigsegv.patch" Content-Disposition: attachment; filename="0001-c-stack-improve-checking-if-libsigsegv.patch" Content-Transfer-Encoding: quoted-printable >From 8ba9126d00bfe1ab77a5c820c58c68933d4df85c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 20 Sep 2020 11:48:17 -0700 Subject: [PATCH 1/2] c-stack: improve checking if !libsigsegv MIME-Version: 1.0 Content-Type: text/plain; charset=3DUTF-8 Content-Transfer-Encoding: 8bit If SIGINFO_WORKS, do not treat a null pointer dereference as if it were a stack overflow. Use uintptr_t and INT_ADD_WRAPV to avoid unlikely pointer overflow. Also, fix some obsolete code and typos. I found these problems while looking into this bug report: https://lists.gnu.org/r/grep-devel/2020-09/msg00053.html * lib/c-stack.c: Include c-stack.h first, to test interface. Include inttypes.h for UINTPTR_MAX, stdbool.h, stddef.h for max_align_t, intprops.h for INT_ADD_WRAPV. (USE_LIBSIGSEGV): New macro; use it to simplify later code. (SIGSTKSZ): Simplify setup. Work around libsigsegv bug only for libsigsegv 2.8 and earlier since the bug should be fixed after that. (alternate_signal_stack): Use max_align_t instead of doing it by hand. (segv_handler, overflow_handler, segv_handler) [DEBUG]: Assume sprintf returns byte count; this assumption is safe now. (page_size): New static volatile variable, since sysconf isn=E2=80=99t documented to be async-signal-safe on Solaris. This variable is present and used if (!USE_LIBSIGSEGV && HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK && HAVE_STACK_OVERFLOW_HANDLING && SIGINFO_WORKS). (segv_handler): Use it if present. Never report null pointer dereference as a stack overflow. Check for (unlikely) unsigned and/or pointer overflow. * m4/c-stack.m4 (AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC): Rename cache variables to gl_cv_sys_stack_overflow_works and gl_cv_sys_xsi_stack_overflow_heuristic. All uses changed. (gl_PREREQ_C_STACK): Do not require AC_FUNC_ALLOCA, since c-stack no longer uses STACK_DIRECTION. Do not check for unistd.h, since we depend on unistd. Fix shell typo =E2=80=98$"ac_cv_sys_xsi_stack_overflow_heuristic"=E2=80=99= . * modules/c-stack (Depends-on): Sort. Add intprops, inttypes, stdbool, stddef. --- ChangeLog | 37 +++++++++++++ lib/c-stack.c | 135 ++++++++++++++++++++++++++++-------------------- m4/c-stack.m4 | 33 ++++++------ modules/c-stack | 12 +++-- 4 files changed, 139 insertions(+), 78 deletions(-) diff --git a/ChangeLog b/ChangeLog index cc1cd4a40..087b9232f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +2020-09-20 Paul Eggert + + c-stack: improve checking if !libsigsegv + If SIGINFO_WORKS, do not treat a null pointer dereference as if it + were a stack overflow. Use uintptr_t and INT_ADD_WRAPV to avoid + unlikely pointer overflow. Also, fix some obsolete code and typos. + I found these problems while looking into this bug report: + https://lists.gnu.org/r/grep-devel/2020-09/msg00053.html + * lib/c-stack.c: Include c-stack.h first, to test interface. + Include inttypes.h for UINTPTR_MAX, stdbool.h, stddef.h for + max_align_t, intprops.h for INT_ADD_WRAPV. + (USE_LIBSIGSEGV): New macro; use it to simplify later code. + (SIGSTKSZ): Simplify setup. Work around libsigsegv bug only + for libsigsegv 2.8 and earlier since the bug should be fixed + after that. + (alternate_signal_stack): Use max_align_t instead of doing it by hand. + (segv_handler, overflow_handler, segv_handler) [DEBUG]: + Assume sprintf returns byte count; this assumption is safe now. + (page_size): New static volatile variable, since sysconf isn=E2=80=99t + documented to be async-signal-safe on Solaris. This variable is + present and used if (!USE_LIBSIGSEGV && HAVE_SIGALTSTACK && + HAVE_DECL_SIGALTSTACK && HAVE_STACK_OVERFLOW_HANDLING && + SIGINFO_WORKS). + (segv_handler): Use it if present. Never report null pointer + dereference as a stack overflow. Check for (unlikely) unsigned + and/or pointer overflow. + * m4/c-stack.m4 (AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC): + Rename cache variables to gl_cv_sys_stack_overflow_works + and gl_cv_sys_xsi_stack_overflow_heuristic. + All uses changed. + (gl_PREREQ_C_STACK): Do not require AC_FUNC_ALLOCA, since + c-stack no longer uses STACK_DIRECTION. + Do not check for unistd.h, since we depend on unistd. + Fix shell typo =E2=80=98$"ac_cv_sys_xsi_stack_overflow_heuristic"=E2=80= =99. + * modules/c-stack (Depends-on): Sort. Add intprops, inttypes, + stdbool, stddef. + 2020-09-20 Bruno Haible =20 Revert now-unnecessary override of config.guess on Alpine Linux 3.10. diff --git a/lib/c-stack.c b/lib/c-stack.c index 59606299b..3649c1bfe 100644 --- a/lib/c-stack.c +++ b/lib/c-stack.c @@ -35,30 +35,25 @@ =20 #include =20 +#include "c-stack.h" + #include "gettext.h" #define _(msgid) gettext (msgid) =20 #include +#include =20 #include #if ! HAVE_STACK_T && ! defined stack_t typedef struct sigaltstack stack_t; #endif -#ifndef SIGSTKSZ -# define SIGSTKSZ 16384 -#elif HAVE_LIBSIGSEGV && SIGSTKSZ < 16384 -/* libsigsegv 2.6 through 2.8 have a bug where some architectures use - more than the Linux default of an 8k alternate stack when deciding - if a fault was caused by stack overflow. */ -# undef SIGSTKSZ -# define SIGSTKSZ 16384 -#endif =20 +#include +#include #include #include =20 -/* Posix 2001 declares ucontext_t in , Posix 200x in - . */ +/* Pre-2008 POSIX declared ucontext_t in ucontext.h instead of signal.h.= */ #if HAVE_UCONTEXT_H # include #endif @@ -69,13 +64,26 @@ typedef struct sigaltstack stack_t; # include #endif =20 -#if HAVE_LIBSIGSEGV +/* Use libsigsegv only if needed; kernels like Solaris can detect + stack overflow without the overhead of an external library. */ +#define USE_LIBSIGSEGV (HAVE_XSI_STACK_OVERFLOW_HEURISTIC && HAVE_LIBSIG= SEGV) + +#if USE_LIBSIGSEGV # include +/* libsigsegv 2.6 through 2.8 have a bug where some architectures use + more than the Linux default of an 8k alternate stack when deciding + if a fault was caused by stack overflow. */ +# if LIBSIGSEGV_VERSION <=3D 0x0208 && SIGSTKSZ < 16384 +# undef SIGSTKSZ +# endif +#endif +#ifndef SIGSTKSZ +# define SIGSTKSZ 16384 #endif =20 -#include "c-stack.h" #include "exitfail.h" #include "ignore-value.h" +#include "intprops.h" #include "getprogname.h" =20 #if defined SA_ONSTACK && defined SA_SIGINFO @@ -97,7 +105,7 @@ static _GL_ASYNC_SAFE void (* volatile segv_action) (i= nt); static char const * volatile program_error_message; static char const * volatile stack_overflow_message; =20 -#if ((HAVE_LIBSIGSEGV && ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC) \ +#if (USE_LIBSIGSEGV \ || (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK \ && HAVE_STACK_OVERFLOW_HANDLING)) =20 @@ -111,12 +119,12 @@ static _GL_ASYNC_SAFE _Noreturn void die (int signo) { char const *message; -#if !SIGINFO_WORKS && !HAVE_LIBSIGSEGV +# if !SIGINFO_WORKS && !USE_LIBSIGSEGV /* We can't easily determine whether it is a stack overflow; so assume that the rest of our program is perfect (!) and that this segmentation violation is a stack overflow. */ signo =3D 0; -#endif /* !SIGINFO_WORKS && !HAVE_LIBSIGSEGV */ +# endif segv_action (signo); message =3D signo ? program_error_message : stack_overflow_message; ignore_value (write (STDERR_FILENO, progname, strlen (progname))); @@ -128,22 +136,12 @@ die (int signo) raise (signo); abort (); } -#endif - -#if (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK \ - && HAVE_STACK_OVERFLOW_HANDLING) || HAVE_LIBSIGSEGV =20 /* Storage for the alternate signal stack. */ static union { char buffer[SIGSTKSZ]; - - /* These other members are for proper alignment. There's no - standard way to guarantee stack alignment, but this seems enough - in practice. */ - long double ld; - long l; - void *p; + max_align_t align; } alternate_signal_stack; =20 static _GL_ASYNC_SAFE void @@ -153,10 +151,7 @@ null_action (int signo _GL_UNUSED) =20 #endif /* SIGALTSTACK || LIBSIGSEGV */ =20 -/* Only use libsigsegv if we need it; platforms like Solaris can - detect stack overflow without the overhead of an external - library. */ -#if HAVE_LIBSIGSEGV && ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC +#if USE_LIBSIGSEGV =20 /* Nonzero if general segv handler could not be installed. */ static volatile int segv_handler_missing; @@ -171,8 +166,8 @@ segv_handler (void *address _GL_UNUSED, int serious) { char buf[1024]; int saved_errno =3D errno; - sprintf (buf, "segv_handler serious=3D%d\n", serious); - ignore_value (write (STDERR_FILENO, buf, strlen (buf))); + ignore_value (write (STDERR_FILENO, buf, + sprintf (buf, "segv_handler serious=3D%d\n", se= rious))); errno =3D saved_errno; } # endif @@ -193,9 +188,10 @@ overflow_handler (int emergency, stackoverflow_conte= xt_t context _GL_UNUSED) # if DEBUG { char buf[1024]; - sprintf (buf, "overflow_handler emergency=3D%d segv_handler_missing=3D= %d\n", - emergency, segv_handler_missing); - ignore_value (write (STDERR_FILENO, buf, strlen (buf))); + ignore_value (write (STDERR_FILENO, buf, + sprintf (buf, ("overflow_handler emergency=3D%d= " + " segv_handler_missing=3D%d\n"), + emergency, segv_handler_missing))); } # endif =20 @@ -228,6 +224,8 @@ c_stack_action (_GL_ASYNC_SAFE void (*action) (int)) =20 # if SIGINFO_WORKS =20 +static size_t volatile page_size; + /* Handle a segmentation violation and exit. This function is async-signal-safe. */ =20 @@ -235,8 +233,17 @@ static _GL_ASYNC_SAFE _Noreturn void segv_handler (int signo, siginfo_t *info, void *context _GL_UNUSED) { /* Clear SIGNO if it seems to have been a stack overflow. */ -# if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC - /* We can't easily determine whether it is a stack overflow; so + + /* If si_code is nonpositive, something like raise (SIGSEGV) occurred + so it cannot be a stack overflow. */ + bool cannot_be_stack_overflow =3D info->si_code <=3D 0; + + /* An unaligned address cannot be a stack overflow. */ +# if FAULT_YIELDS_SIGBUS + cannot_be_stack_overflow |=3D signo =3D=3D SIGBUS && info->si_code =3D= =3D BUS_ADRALN; +# endif + + /* If we can't easily determine that it is not a stack overflow, assume that the rest of our program is perfect (!) and that this segmentation violation is a stack overflow. =20 @@ -246,33 +253,44 @@ segv_handler (int signo, siginfo_t *info, void *con= text _GL_UNUSED) Solaris populates uc_stack with the details of the interrupted stack, while Linux populates it with the details of the current stack. */ - signo =3D 0; -# else - if (0 < info->si_code) + if (!cannot_be_stack_overflow) { /* If the faulting address is within the stack, or within one page of the stack, assume that it is a stack overflow. */ + uintptr_t faulting_address =3D (uintptr_t) info->si_addr; + + /* On all platforms we know of, the first page is not in the + stack to catch null pointer dereferening. However, all other + pages might be in the stack. */ + void *stack_base =3D (void *) (uintptr_t) page_size; + uintptr_t stack_size =3D 0; stack_size -=3D page_size; +# if HAVE_XSI_STACK_OVERFLOW_HEURISTIC + /* Tighten the stack bounds via the XSI heuristic. */ ucontext_t const *user_context =3D context; - char const *stack_base =3D user_context->uc_stack.ss_sp; - size_t stack_size =3D user_context->uc_stack.ss_size; - char const *faulting_address =3D info->si_addr; - size_t page_size =3D sysconf (_SC_PAGESIZE); - size_t s =3D faulting_address - stack_base + page_size; - if (s < stack_size + 2 * page_size) + stack_base =3D user_context->uc_stack.ss_sp; + stack_size =3D user_context->uc_stack.ss_size; +# endif + uintptr_t base =3D (uintptr_t) stack_base, + lo =3D (INT_SUBTRACT_WRAPV (base, page_size, &lo) || lo < page_s= ize + ? page_size : lo), + hi =3D ((INT_ADD_WRAPV (base, stack_size, &hi) + || INT_ADD_WRAPV (hi, page_size - 1, &hi)) + ? UINTPTR_MAX : hi); + if (lo <=3D faulting_address && faulting_address <=3D hi) signo =3D 0; =20 # if DEBUG { char buf[1024]; - sprintf (buf, - "segv_handler fault=3D%p base=3D%p size=3D%lx page=3D%l= x signo=3D%d\n", - faulting_address, stack_base, (unsigned long) stack_siz= e, - (unsigned long) page_size, signo); - ignore_value (write (STDERR_FILENO, buf, strlen (buf))); + ignore_value (write (STDERR_FILENO, buf, + sprintf (buf, + ("segv_handler code=3D%d fault=3D%= p base=3D%p" + " size=3D0x%zx page=3D0x%zx signo= =3D%d\n"), + info->si_code, info->si_addr, stac= k_base, + stack_size, page_size, signo))); } -# endif - } # endif + } =20 die (signo); } @@ -303,6 +321,10 @@ c_stack_action (_GL_ASYNC_SAFE void (*action) (int)) stack_overflow_message =3D _("stack overflow"); progname =3D getprogname (); =20 +# if SIGINFO_WORKS + page_size =3D sysconf (_SC_PAGESIZE); +# endif + sigemptyset (&act.sa_mask); =20 # if SIGINFO_WORKS @@ -323,8 +345,9 @@ c_stack_action (_GL_ASYNC_SAFE void (*action) (int)) return sigaction (SIGSEGV, &act, NULL); } =20 -#else /* ! ((HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK - && HAVE_STACK_OVERFLOW_HANDLING) || HAVE_LIBSIGSEGV) */ +#else /* ! (USE_LIBSIGSEGV + || (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK + && HAVE_STACK_OVERFLOW_HANDLING)) */ =20 int c_stack_action (_GL_ASYNC_SAFE void (*action) (int) _GL_UNUSED) diff --git a/m4/c-stack.m4 b/m4/c-stack.m4 index c3e2bddd3..e98f80fff 100644 --- a/m4/c-stack.m4 +++ b/m4/c-stack.m4 @@ -7,7 +7,7 @@ =20 # Written by Paul Eggert. =20 -# serial 17 +# serial 18 =20 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC], [ @@ -34,7 +34,7 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC], [Define to 1 if an invalid memory address access may yield a SIGBUS= .]) =20 AC_CACHE_CHECK([for working C stack overflow detection], - [ac_cv_sys_stack_overflow_works], + [gl_cv_sys_stack_overflow_works], [AC_RUN_IFELSE([AC_LANG_SOURCE( [[ #include @@ -121,17 +121,17 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC], return recurse (0); } ]])], - [ac_cv_sys_stack_overflow_works=3Dyes], - [ac_cv_sys_stack_overflow_works=3Dno], + [gl_cv_sys_stack_overflow_works=3Dyes], + [gl_cv_sys_stack_overflow_works=3Dno], [case "$host_os" in # Guess no on native Windows. - mingw*) ac_cv_sys_stack_overflow_works=3D"guessing no" ;; - *) ac_cv_sys_stack_overflow_works=3Dcross-compiling ;; + mingw*) gl_cv_sys_stack_overflow_works=3D"guessing no" ;; + *) gl_cv_sys_stack_overflow_works=3Dcross-compiling ;; esac ]) ]) =20 - if test "$ac_cv_sys_stack_overflow_works" =3D yes; then + if test "$gl_cv_sys_stack_overflow_works" =3D yes; then AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], [1], [Define to 1 if extending the stack slightly past the limit causes a SIGSEGV which can be handled on an alternate stack established @@ -200,14 +200,14 @@ int main () fi =20 AC_CACHE_CHECK([for precise C stack overflow detection], - [ac_cv_sys_xsi_stack_overflow_heuristic], + [gl_cv_sys_xsi_stack_overflow_heuristic], [dnl On Linux/sparc64 (both in 32-bit and 64-bit mode), it would be= wrong dnl to set HAVE_XSI_STACK_OVERFLOW_HEURISTIC to 1, because the thi= rd dnl argument passed to the segv_handler is a 'struct sigcontext *'= , not dnl an 'ucontext_t *'. It would lead to a failure of test-c-stack= 2.sh. case "${host_os}--${host_cpu}" in linux*--sparc*) - ac_cv_sys_xsi_stack_overflow_heuristic=3Dno + gl_cv_sys_xsi_stack_overflow_heuristic=3Dno ;; *) AC_RUN_IFELSE( @@ -329,14 +329,14 @@ int main () return recurse (0); } ]])], - [ac_cv_sys_xsi_stack_overflow_heuristic=3Dyes], - [ac_cv_sys_xsi_stack_overflow_heuristic=3Dno], - [ac_cv_sys_xsi_stack_overflow_heuristic=3Dcross-compiling]) + [gl_cv_sys_xsi_stack_overflow_heuristic=3Dyes], + [gl_cv_sys_xsi_stack_overflow_heuristic=3Dno], + [gl_cv_sys_xsi_stack_overflow_heuristic=3Dcross-compiling]) ;; esac ]) =20 - if test $ac_cv_sys_xsi_stack_overflow_heuristic =3D yes; then + if test "$gl_cv_sys_xsi_stack_overflow_heuristic" =3D yes; then AC_DEFINE([HAVE_XSI_STACK_OVERFLOW_HEURISTIC], [1], [Define to 1 if extending the stack slightly past the limit cause= s a SIGSEGV, and an alternate stack can be established with sigalt= stack, @@ -353,19 +353,16 @@ AC_DEFUN([gl_PREREQ_C_STACK], [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC]) AC_REQUIRE([gl_LIBSIGSEGV]) =20 - # for STACK_DIRECTION - AC_REQUIRE([AC_FUNC_ALLOCA]) - AC_CHECK_FUNCS_ONCE([sigaltstack]) AC_CHECK_DECLS([sigaltstack], , , [[#include ]]) =20 - AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h]) + AC_CHECK_HEADERS_ONCE([ucontext.h]) =20 AC_CHECK_TYPES([stack_t], , , [#include ]) =20 dnl c-stack does not need -lsigsegv if the system has XSI heuristics. if test "$gl_cv_lib_sigsegv" =3D yes \ - && test $"ac_cv_sys_xsi_stack_overflow_heuristic" !=3D yes ; then + && test "$gl_cv_sys_xsi_stack_overflow_heuristic" !=3D yes; then AC_SUBST([LIBCSTACK], [$LIBSIGSEGV]) AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV]) fi diff --git a/modules/c-stack b/modules/c-stack index ca2c208e1..8c898eb9e 100644 --- a/modules/c-stack +++ b/modules/c-stack @@ -7,15 +7,19 @@ lib/c-stack.c m4/c-stack.m4 =20 Depends-on: -gettext-h errno exitfail +getprogname +gettext-h ignore-value -unistd +intprops +inttypes +libsigsegv raise sigaction -libsigsegv -getprogname +stdbool +stddef +unistd =20 configure.ac: gl_C_STACK --=20 2.17.1 --------------936512A241C3F572F212D46A Content-Type: text/x-patch; charset=UTF-8; name="0002-c-stack-output-diagnostic-in-single-write.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-c-stack-output-diagnostic-in-single-write.patch" >From 649a39bbd0641c8bb48ba25e5d62d03f8f36125f Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 20 Sep 2020 12:52:15 -0700 Subject: [PATCH 2/2] c-stack: output diagnostic in single 'write' * lib/c-stack.c (die): In the typical case, use just one 'write' syscall to output the diagnostic, as this lessens interleaving. (die, c_stack_action): Assume C99. * modules/c-stack (Depends-on): Add c99, mempcpy. --- ChangeLog | 6 ++++++ lib/c-stack.c | 39 ++++++++++++++++++++++++++++++--------- modules/c-stack | 2 ++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 087b9232f..a43c32eb8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-09-20 Paul Eggert + c-stack: output diagnostic in single 'write' + * lib/c-stack.c (die): In the typical case, use just one 'write' + syscall to output the diagnostic, as this lessens interleaving. + (die, c_stack_action): Assume C99. + * modules/c-stack (Depends-on): Add c99, mempcpy. + c-stack: improve checking if !libsigsegv If SIGINFO_WORKS, do not treat a null pointer dereference as if it were a stack overflow. Use uintptr_t and INT_ADD_WRAPV to avoid diff --git a/lib/c-stack.c b/lib/c-stack.c index 3649c1bfe..742eb023e 100644 --- a/lib/c-stack.c +++ b/lib/c-stack.c @@ -118,7 +118,6 @@ static char const * volatile progname; static _GL_ASYNC_SAFE _Noreturn void die (int signo) { - char const *message; # if !SIGINFO_WORKS && !USE_LIBSIGSEGV /* We can't easily determine whether it is a stack overflow; so assume that the rest of our program is perfect (!) and that @@ -126,11 +125,34 @@ die (int signo) signo = 0; # endif segv_action (signo); - message = signo ? program_error_message : stack_overflow_message; - ignore_value (write (STDERR_FILENO, progname, strlen (progname))); - ignore_value (write (STDERR_FILENO, ": ", 2)); - ignore_value (write (STDERR_FILENO, message, strlen (message))); - ignore_value (write (STDERR_FILENO, "\n", 1)); + char const *message = signo ? program_error_message : stack_overflow_message; + + /* If the message is short, write it all at once to avoid + interleaving with other messages. Avoid writev as it is not + documented to be async-signal-safe. */ + size_t prognamelen = strlen (progname); + size_t messagelen = strlen (message); + static char const separator[] = {':', ' '}; + char buf[SIGSTKSZ / 16 + sizeof separator]; + ptrdiff_t buflen; + if (prognamelen + messagelen < sizeof buf - sizeof separator) + { + char *p = mempcpy (buf, progname, prognamelen); + p = mempcpy (p, separator, sizeof separator); + p = mempcpy (p, message, messagelen); + *p++ = '\n'; + buflen = p - buf; + } + else + { + ignore_value (write (STDERR_FILENO, progname, prognamelen)); + ignore_value (write (STDERR_FILENO, separator, sizeof separator)); + ignore_value (write (STDERR_FILENO, message, messagelen)); + buf[0] = '\n'; + buflen = 1; + } + ignore_value (write (STDERR_FILENO, buf, buflen)); + if (! signo) _exit (exit_failure); raise (signo); @@ -299,9 +321,7 @@ segv_handler (int signo, siginfo_t *info, void *context _GL_UNUSED) int c_stack_action (_GL_ASYNC_SAFE void (*action) (int)) { - int r; stack_t st; - struct sigaction act; st.ss_flags = 0; # if SIGALTSTACK_SS_REVERSED /* Irix mistakenly treats ss_sp as the upper bound, rather than @@ -312,7 +332,7 @@ c_stack_action (_GL_ASYNC_SAFE void (*action) (int)) st.ss_sp = alternate_signal_stack.buffer; st.ss_size = sizeof alternate_signal_stack.buffer; # endif - r = sigaltstack (&st, NULL); + int r = sigaltstack (&st, NULL); if (r != 0) return r; @@ -325,6 +345,7 @@ c_stack_action (_GL_ASYNC_SAFE void (*action) (int)) page_size = sysconf (_SC_PAGESIZE); # endif + struct sigaction act; sigemptyset (&act.sa_mask); # if SIGINFO_WORKS diff --git a/modules/c-stack b/modules/c-stack index 8c898eb9e..5ddf6e6f5 100644 --- a/modules/c-stack +++ b/modules/c-stack @@ -7,6 +7,7 @@ lib/c-stack.c m4/c-stack.m4 Depends-on: +c99 errno exitfail getprogname @@ -15,6 +16,7 @@ ignore-value intprops inttypes libsigsegv +mempcpy raise sigaction stdbool -- 2.17.1 --------------936512A241C3F572F212D46A--